diff options
Diffstat (limited to 'meta/packages/makedevs/makedevs-1.0.0/makedevs.c')
-rw-r--r-- | meta/packages/makedevs/makedevs-1.0.0/makedevs.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/meta/packages/makedevs/makedevs-1.0.0/makedevs.c b/meta/packages/makedevs/makedevs-1.0.0/makedevs.c new file mode 100644 index 0000000000..a9bf8e782a --- /dev/null +++ b/meta/packages/makedevs/makedevs-1.0.0/makedevs.c | |||
@@ -0,0 +1,338 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <stdio.h> | ||
3 | #include <errno.h> | ||
4 | #include <string.h> | ||
5 | #include <stdarg.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <ctype.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <dirent.h> | ||
10 | #include <unistd.h> | ||
11 | #include <time.h> | ||
12 | #include <getopt.h> | ||
13 | #include <libgen.h> | ||
14 | #include <sys/types.h> | ||
15 | #include <sys/stat.h> | ||
16 | |||
17 | #define MINORBITS 8 | ||
18 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) | ||
19 | |||
20 | /* These are all stolen from busybox's libbb to make | ||
21 | * error handling simpler (and since I maintain busybox, | ||
22 | * I'm rather partial to these for error handling). | ||
23 | * -Erik | ||
24 | */ | ||
25 | static const char *const app_name = "makedevs"; | ||
26 | static const char *const memory_exhausted = "memory exhausted"; | ||
27 | static char default_rootdir[]="."; | ||
28 | static char *rootdir = default_rootdir; | ||
29 | |||
30 | static void verror_msg(const char *s, va_list p) | ||
31 | { | ||
32 | fflush(stdout); | ||
33 | fprintf(stderr, "%s: ", app_name); | ||
34 | vfprintf(stderr, s, p); | ||
35 | } | ||
36 | |||
37 | static void error_msg_and_die(const char *s, ...) | ||
38 | { | ||
39 | va_list p; | ||
40 | |||
41 | va_start(p, s); | ||
42 | verror_msg(s, p); | ||
43 | va_end(p); | ||
44 | putc('\n', stderr); | ||
45 | exit(EXIT_FAILURE); | ||
46 | } | ||
47 | |||
48 | static void vperror_msg(const char *s, va_list p) | ||
49 | { | ||
50 | int err = errno; | ||
51 | |||
52 | if (s == 0) | ||
53 | s = ""; | ||
54 | verror_msg(s, p); | ||
55 | if (*s) | ||
56 | s = ": "; | ||
57 | fprintf(stderr, "%s%s\n", s, strerror(err)); | ||
58 | } | ||
59 | |||
60 | #if 0 | ||
61 | static void perror_msg(const char *s, ...) | ||
62 | { | ||
63 | va_list p; | ||
64 | |||
65 | va_start(p, s); | ||
66 | vperror_msg(s, p); | ||
67 | va_end(p); | ||
68 | } | ||
69 | #endif | ||
70 | |||
71 | static void perror_msg_and_die(const char *s, ...) | ||
72 | { | ||
73 | va_list p; | ||
74 | |||
75 | va_start(p, s); | ||
76 | vperror_msg(s, p); | ||
77 | va_end(p); | ||
78 | exit(EXIT_FAILURE); | ||
79 | } | ||
80 | |||
81 | static FILE *xfopen(const char *path, const char *mode) | ||
82 | { | ||
83 | FILE *fp; | ||
84 | |||
85 | if ((fp = fopen(path, mode)) == NULL) | ||
86 | perror_msg_and_die("%s", path); | ||
87 | return fp; | ||
88 | } | ||
89 | |||
90 | static char *xstrdup(const char *s) | ||
91 | { | ||
92 | char *t; | ||
93 | |||
94 | if (s == NULL) | ||
95 | return NULL; | ||
96 | |||
97 | t = strdup(s); | ||
98 | |||
99 | if (t == NULL) | ||
100 | error_msg_and_die(memory_exhausted); | ||
101 | |||
102 | return t; | ||
103 | } | ||
104 | |||
105 | |||
106 | static void add_new_directory(char *name, char *path, | ||
107 | unsigned long uid, unsigned long gid, unsigned long mode) | ||
108 | { | ||
109 | // printf("Directory: %s %s UID: %ld GID %ld MODE: %ld\n", path, name, uid, gid, mode); | ||
110 | } | ||
111 | |||
112 | static void add_new_device(char *name, char *path, unsigned long uid, | ||
113 | unsigned long gid, unsigned long mode, dev_t rdev) | ||
114 | { | ||
115 | int status; | ||
116 | struct stat sb; | ||
117 | time_t timestamp = time(NULL); | ||
118 | |||
119 | memset(&sb, 0, sizeof(struct stat)); | ||
120 | status = lstat(path, &sb); | ||
121 | |||
122 | if (status >= 0) { | ||
123 | /* It is ok for some types of files to not exit on disk (such as | ||
124 | * device nodes), but if they _do_ exist the specified mode had | ||
125 | * better match the actual file or strange things will happen.... */ | ||
126 | if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) | ||
127 | error_msg_and_die("%s: file type does not match specified type!", path); | ||
128 | timestamp = sb.st_mtime; | ||
129 | } | ||
130 | |||
131 | mknod(name, mode, rdev); | ||
132 | // printf("Device: %s %s UID: %ld GID: %ld MODE: %ld MAJOR: %d MINOR: %d\n", | ||
133 | // path, name, uid, gid, mode, (short)(rdev >> 8), (short)(rdev & 0xff)); | ||
134 | } | ||
135 | |||
136 | static void add_new_file(char *name, char *path, unsigned long uid, | ||
137 | unsigned long gid, unsigned long mode) | ||
138 | { | ||
139 | // printf("File: %s %s UID: %ld GID: %ld MODE: %ld\n", | ||
140 | // path, name, gid, uid, mode); | ||
141 | } | ||
142 | |||
143 | |||
144 | /* device table entries take the form of: | ||
145 | <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count> | ||
146 | /dev/mem c 640 0 0 1 1 0 0 - | ||
147 | |||
148 | type can be one of: | ||
149 | f A regular file | ||
150 | d Directory | ||
151 | c Character special device file | ||
152 | b Block special device file | ||
153 | p Fifo (named pipe) | ||
154 | |||
155 | I don't bother with symlinks (permissions are irrelevant), hard | ||
156 | links (special cases of regular files), or sockets (why bother). | ||
157 | |||
158 | Regular files must exist in the target root directory. If a char, | ||
159 | block, fifo, or directory does not exist, it will be created. | ||
160 | */ | ||
161 | static int interpret_table_entry(char *line) | ||
162 | { | ||
163 | char *name; | ||
164 | char path[4096], type; | ||
165 | unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; | ||
166 | unsigned long start = 0, increment = 1, count = 0; | ||
167 | |||
168 | if (0 > sscanf(line, "%40s %c %lo %lu %lu %lu %lu %lu %lu %lu", path, | ||
169 | &type, &mode, &uid, &gid, &major, &minor, &start, | ||
170 | &increment, &count)) | ||
171 | { | ||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | if (!strcmp(path, "/")) { | ||
176 | error_msg_and_die("Device table entries require absolute paths"); | ||
177 | } | ||
178 | name = xstrdup(path + 1); | ||
179 | sprintf(path, "%s/%s\0", rootdir, name); | ||
180 | |||
181 | switch (type) { | ||
182 | case 'd': | ||
183 | mode |= S_IFDIR; | ||
184 | add_new_directory(name, path, uid, gid, mode); | ||
185 | break; | ||
186 | case 'f': | ||
187 | mode |= S_IFREG; | ||
188 | add_new_file(name, path, uid, gid, mode); | ||
189 | break; | ||
190 | case 'p': | ||
191 | mode |= S_IFIFO; | ||
192 | add_new_file(name, path, uid, gid, mode); | ||
193 | break; | ||
194 | case 'c': | ||
195 | case 'b': | ||
196 | mode |= (type == 'c') ? S_IFCHR : S_IFBLK; | ||
197 | if (count > 0) { | ||
198 | int i; | ||
199 | dev_t rdev; | ||
200 | char buf[80]; | ||
201 | |||
202 | for (i = start; i < count; i++) { | ||
203 | sprintf(buf, "%s%d", name, i); | ||
204 | /* FIXME: MKDEV uses illicit insider knowledge of kernel | ||
205 | * major/minor representation... */ | ||
206 | rdev = MKDEV(major, minor + (i * increment - start)); | ||
207 | add_new_device(buf, path, uid, gid, mode, rdev); | ||
208 | } | ||
209 | } else { | ||
210 | /* FIXME: MKDEV uses illicit insider knowledge of kernel | ||
211 | * major/minor representation... */ | ||
212 | dev_t rdev = MKDEV(major, minor); | ||
213 | |||
214 | add_new_device(name, path, uid, gid, mode, rdev); | ||
215 | } | ||
216 | break; | ||
217 | default: | ||
218 | error_msg_and_die("Unsupported file type"); | ||
219 | } | ||
220 | if (name) free(name); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | |||
225 | static void parse_device_table(FILE * file) | ||
226 | { | ||
227 | char *line; | ||
228 | size_t length = 256; | ||
229 | int len = 0; | ||
230 | |||
231 | /* Looks ok so far. The general plan now is to read in one | ||
232 | * line at a time, check for leading comment delimiters ('#'), | ||
233 | * then try and parse the line as a device table. If we fail | ||
234 | * to parse things, try and help the poor fool to fix their | ||
235 | * device table with a useful error msg... */ | ||
236 | |||
237 | if((line = (char *)malloc(length)) == NULL) { | ||
238 | fclose(file); | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | while ((len = getline(&line, &length, file)) != -1) { | ||
243 | /* First trim off any whitespace */ | ||
244 | |||
245 | /* trim trailing whitespace */ | ||
246 | while (len > 0 && isspace(line[len - 1])) | ||
247 | line[--len] = '\0'; | ||
248 | |||
249 | /* trim leading whitespace */ | ||
250 | memmove(line, &line[strspn(line, " \n\r\t\v")], len + 1); | ||
251 | |||
252 | /* If this is NOT a comment line, try to interpret it */ | ||
253 | if (*line != '#') interpret_table_entry(line); | ||
254 | } | ||
255 | if (line) free(line); | ||
256 | |||
257 | fclose(file); | ||
258 | } | ||
259 | |||
260 | static int go(char *dname, FILE * devtable) | ||
261 | { | ||
262 | struct stat sb; | ||
263 | |||
264 | if (lstat(dname, &sb)) { | ||
265 | perror_msg_and_die("%s", dname); | ||
266 | } | ||
267 | if (chdir(dname)) | ||
268 | perror_msg_and_die("%s", dname); | ||
269 | |||
270 | if (devtable) | ||
271 | parse_device_table(devtable); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | |||
277 | static struct option long_options[] = { | ||
278 | {"root", 1, NULL, 'r'}, | ||
279 | {"help", 0, NULL, 'h'}, | ||
280 | {"squash", 0, NULL, 'q'}, | ||
281 | {"version", 0, NULL, 'v'}, | ||
282 | {"devtable", 1, NULL, 'D'}, | ||
283 | {NULL, 0, NULL, 0} | ||
284 | }; | ||
285 | |||
286 | static char *helptext = | ||
287 | "Usage: makedevs [OPTIONS]\n" | ||
288 | "Build entries based upon device_table.txt\n\n" | ||
289 | "Options:\n" | ||
290 | " -r, -d, --root=DIR Build filesystem from directory DIR (default: cwd)\n" | ||
291 | " -D, --devtable=FILE Use the named FILE as a device table file\n" | ||
292 | " -q, --squash Squash permissions and owners making all files be owned by root\n" | ||
293 | " -h, --help Display this help text\n" | ||
294 | " -v, --version Display version information\n\n"; | ||
295 | |||
296 | |||
297 | static char *revtext = "$Revision: 0.1 $"; | ||
298 | |||
299 | int main(int argc, char **argv) | ||
300 | { | ||
301 | int c, opt; | ||
302 | extern char *optarg; | ||
303 | struct stat statbuf; | ||
304 | FILE *devtable = NULL; | ||
305 | |||
306 | umask (0); | ||
307 | |||
308 | while ((opt = getopt_long(argc, argv, "D:d:r:qhv", | ||
309 | long_options, &c)) >= 0) { | ||
310 | switch (opt) { | ||
311 | case 'D': | ||
312 | devtable = xfopen(optarg, "r"); | ||
313 | if (fstat(fileno(devtable), &statbuf) < 0) | ||
314 | perror_msg_and_die(optarg); | ||
315 | if (statbuf.st_size < 10) | ||
316 | error_msg_and_die("%s: not a proper device table file", optarg); | ||
317 | break; | ||
318 | case 'h': | ||
319 | fprintf(stderr, helptext); | ||
320 | exit(1); | ||
321 | case 'r': | ||
322 | case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */ | ||
323 | if (rootdir != default_rootdir) { | ||
324 | error_msg_and_die("root directory specified more than once"); | ||
325 | } | ||
326 | rootdir = xstrdup(optarg); | ||
327 | break; | ||
328 | |||
329 | case 'v': | ||
330 | fprintf(stderr, "makedevs revision %.*s\n", | ||
331 | (int) strlen(revtext) - 13, revtext + 11); | ||
332 | exit(1); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | go(rootdir, devtable); | ||
337 | return 0; | ||
338 | } | ||