missed the 'merge' conflict stuff
[bootmanager.git] / source / libc-opendir-hack.c
1 #define _GNU_SOURCE 1
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <dlfcn.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <dirent.h>
9 #include <glob.h>
10 #include <stdarg.h>
11 #include <string.h>
12
13 #define INIT(x) real_ ## x = dlsym(RTLD_NEXT, #x); \
14                 if (!real_ ## x) { \
15                   fprintf(stderr, "Would the real " #x " please stand up? %s\n", dlerror()); \
16                   exit(1); \
17                 }
18
19 DIR *opendir(const char *name)
20 {
21   int fd = open(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE);
22   if (fd == -1)
23     return NULL;
24   return fdopendir(fd);
25 }
26
27 DIR *__opendir(const char *name)
28 {
29   return opendir(name);
30 }
31
32 static int (*real_glob)(const char *pattern, int flags,
33          int (*errfunc) (const char *epath, int eerrno),
34          glob_t *pglob);
35
36 int glob(const char *pattern, int flags,
37          int (*errfunc) (const char *epath, int eerrno),
38          glob_t *pglob)
39 {
40   if (!(flags & GLOB_ALTDIRFUNC)) {
41     pglob->gl_closedir = closedir;
42     pglob->gl_readdir = readdir;
43     pglob->gl_opendir = opendir;
44     pglob->gl_lstat = lstat;
45     pglob->gl_stat = stat;
46     flags |= GLOB_ALTDIRFUNC;
47   }
48   if (!real_glob) {
49     INIT(glob)
50   }
51   return real_glob(pattern, flags, errfunc, pglob);
52 }
53
54 #define PWD_LOCKFILE "/etc/.pwd.lock"
55
56 static int lock_fd = -1;
57
58 /* FIXME: Ignores multi-thread issues.
59  *        Doesn't wait for the file to become lockable
60  */
61 int lckpwdf(void)
62 {
63   struct flock fl = { 0 };
64
65   /* This process already holds the lock */
66   if (lock_fd != -1)
67     return -1;
68
69   lock_fd = open(PWD_LOCKFILE, O_WRONLY|O_CREAT, 0600);
70   if (lock_fd == -1)
71     return -1;
72
73   if (fcntl(lock_fd, F_SETFD, fcntl(lock_fd, F_GETFD, 0) | FD_CLOEXEC) == -1) {
74     close(lock_fd);
75     return -1;
76   }
77
78   fl.l_type = F_WRLCK;
79   fl.l_whence = SEEK_SET;
80   return fcntl(lock_fd, F_SETLKW, &fl);
81 }
82
83 int ulckpwdf(void)
84 {
85   int result;
86
87   if (lock_fd == -1)
88     return -1;
89
90   result = close(lock_fd);
91   lock_fd = -1;
92   return result;
93 }
94
95 static (*real_open)(const char *name, int flags, ...);
96 int open(const char *name, int flags, ...)
97 {
98   mode_t mode;
99   if (flags & O_CREAT) {
100     va_list va;
101     va_start(va, flags);
102     mode = va_arg(va, mode_t);
103     va_end(va);
104   }
105   if (!real_open) {
106     INIT(open)
107   }
108   return real_open(name, flags, mode);
109 }
110
111 static FILE *(*real_fopen)(const char *name, const char *flags);
112 FILE *fopen(const char *name, const char *flags)
113 {
114   char *str, *ptr = strchr(flags, 'e');
115   FILE *ret;
116   if (ptr) {
117     str = strdup(flags);
118     ptr = (str + (ptr - flags));
119     strcpy(ptr, ptr + 1);
120   }
121   else
122     str = flags;
123   if (!real_fopen) {
124     INIT(fopen)
125   }
126   ret = real_fopen(name, str);
127   if (ptr)
128     free(str);
129   return ret;
130 }
131
132 static void _init() __attribute__((constructor));
133 static void _init()
134 {
135   INIT(glob)
136   INIT(open)
137   INIT(fopen)
138 }