diff options
Diffstat (limited to 'meta/recipes-devtools/makedevs')
-rw-r--r-- | meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c | 360 | ||||
-rw-r--r-- | meta/recipes-devtools/makedevs/makedevs_1.0.0.bb | 21 |
2 files changed, 381 insertions, 0 deletions
diff --git a/meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c b/meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c new file mode 100644 index 0000000000..c7ad722f2e --- /dev/null +++ b/meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c | |||
@@ -0,0 +1,360 @@ | |||
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 | mkdir(path, mode); | ||
110 | chown(path, uid, gid); | ||
111 | // printf("Directory: %s %s UID: %ld GID %ld MODE: %ld\n", path, name, uid, gid, mode); | ||
112 | } | ||
113 | |||
114 | static void add_new_device(char *name, char *path, unsigned long uid, | ||
115 | unsigned long gid, unsigned long mode, dev_t rdev) | ||
116 | { | ||
117 | int status; | ||
118 | struct stat sb; | ||
119 | time_t timestamp = time(NULL); | ||
120 | |||
121 | memset(&sb, 0, sizeof(struct stat)); | ||
122 | status = lstat(path, &sb); | ||
123 | |||
124 | if (status >= 0) { | ||
125 | /* It is ok for some types of files to not exit on disk (such as | ||
126 | * device nodes), but if they _do_ exist the specified mode had | ||
127 | * better match the actual file or strange things will happen.... */ | ||
128 | if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) | ||
129 | error_msg_and_die("%s: file type does not match specified type!", path); | ||
130 | timestamp = sb.st_mtime; | ||
131 | } | ||
132 | |||
133 | mknod(name, mode, rdev); | ||
134 | chown(path, uid, gid); | ||
135 | // printf("Device: %s %s UID: %ld GID: %ld MODE: %ld MAJOR: %d MINOR: %d\n", | ||
136 | // path, name, uid, gid, mode, (short)(rdev >> 8), (short)(rdev & 0xff)); | ||
137 | } | ||
138 | |||
139 | static void add_new_file(char *name, char *path, unsigned long uid, | ||
140 | unsigned long gid, unsigned long mode) | ||
141 | { | ||
142 | int fd = open(path,O_CREAT | O_WRONLY, mode); | ||
143 | if (fd < 0) { | ||
144 | error_msg_and_die("%s: file can not be created!", path); | ||
145 | } else { | ||
146 | close(fd); | ||
147 | } | ||
148 | chmod(path, mode); | ||
149 | chown(path, uid, gid); | ||
150 | // printf("File: %s %s UID: %ld GID: %ld MODE: %ld\n", | ||
151 | // path, name, gid, uid, mode); | ||
152 | } | ||
153 | |||
154 | |||
155 | static void add_new_fifo(char *name, char *path, unsigned long uid, | ||
156 | unsigned long gid, unsigned long mode) | ||
157 | { | ||
158 | if (mknod(path, mode, 0)) | ||
159 | error_msg_and_die("%s: file can not be created with mknod!", path); | ||
160 | chown(path, uid, gid); | ||
161 | // printf("File: %s %s UID: %ld GID: %ld MODE: %ld\n", | ||
162 | // path, name, gid, uid, mode); | ||
163 | } | ||
164 | |||
165 | |||
166 | /* device table entries take the form of: | ||
167 | <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count> | ||
168 | /dev/mem c 640 0 0 1 1 0 0 - | ||
169 | |||
170 | type can be one of: | ||
171 | f A regular file | ||
172 | d Directory | ||
173 | c Character special device file | ||
174 | b Block special device file | ||
175 | p Fifo (named pipe) | ||
176 | |||
177 | I don't bother with symlinks (permissions are irrelevant), hard | ||
178 | links (special cases of regular files), or sockets (why bother). | ||
179 | |||
180 | Regular files must exist in the target root directory. If a char, | ||
181 | block, fifo, or directory does not exist, it will be created. | ||
182 | */ | ||
183 | static int interpret_table_entry(char *line) | ||
184 | { | ||
185 | char *name; | ||
186 | char path[4096], type; | ||
187 | unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; | ||
188 | unsigned long start = 0, increment = 1, count = 0; | ||
189 | |||
190 | if (0 > sscanf(line, "%40s %c %lo %lu %lu %lu %lu %lu %lu %lu", path, | ||
191 | &type, &mode, &uid, &gid, &major, &minor, &start, | ||
192 | &increment, &count)) | ||
193 | { | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | if (!strcmp(path, "/")) { | ||
198 | error_msg_and_die("Device table entries require absolute paths"); | ||
199 | } | ||
200 | name = xstrdup(path + 1); | ||
201 | sprintf(path, "%s/%s\0", rootdir, name); | ||
202 | |||
203 | switch (type) { | ||
204 | case 'd': | ||
205 | mode |= S_IFDIR; | ||
206 | add_new_directory(name, path, uid, gid, mode); | ||
207 | break; | ||
208 | case 'f': | ||
209 | mode |= S_IFREG; | ||
210 | add_new_file(name, path, uid, gid, mode); | ||
211 | break; | ||
212 | case 'p': | ||
213 | mode |= S_IFIFO; | ||
214 | add_new_fifo(name, path, uid, gid, mode); | ||
215 | break; | ||
216 | case 'c': | ||
217 | case 'b': | ||
218 | mode |= (type == 'c') ? S_IFCHR : S_IFBLK; | ||
219 | if (count > 0) { | ||
220 | int i; | ||
221 | dev_t rdev; | ||
222 | char buf[80]; | ||
223 | |||
224 | for (i = start; i < count; i++) { | ||
225 | sprintf(buf, "%s%d", name, i); | ||
226 | /* FIXME: MKDEV uses illicit insider knowledge of kernel | ||
227 | * major/minor representation... */ | ||
228 | rdev = MKDEV(major, minor + (i * increment - start)); | ||
229 | add_new_device(buf, path, uid, gid, mode, rdev); | ||
230 | } | ||
231 | } else { | ||
232 | /* FIXME: MKDEV uses illicit insider knowledge of kernel | ||
233 | * major/minor representation... */ | ||
234 | dev_t rdev = MKDEV(major, minor); | ||
235 | |||
236 | add_new_device(name, path, uid, gid, mode, rdev); | ||
237 | } | ||
238 | break; | ||
239 | default: | ||
240 | error_msg_and_die("Unsupported file type"); | ||
241 | } | ||
242 | if (name) free(name); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | |||
247 | static void parse_device_table(FILE * file) | ||
248 | { | ||
249 | char *line; | ||
250 | size_t length = 256; | ||
251 | int len = 0; | ||
252 | |||
253 | /* Looks ok so far. The general plan now is to read in one | ||
254 | * line at a time, check for leading comment delimiters ('#'), | ||
255 | * then try and parse the line as a device table. If we fail | ||
256 | * to parse things, try and help the poor fool to fix their | ||
257 | * device table with a useful error msg... */ | ||
258 | |||
259 | if((line = (char *)malloc(length)) == NULL) { | ||
260 | fclose(file); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | while ((len = getline(&line, &length, file)) != -1) { | ||
265 | /* First trim off any whitespace */ | ||
266 | |||
267 | /* trim trailing whitespace */ | ||
268 | while (len > 0 && isspace(line[len - 1])) | ||
269 | line[--len] = '\0'; | ||
270 | |||
271 | /* trim leading whitespace */ | ||
272 | memmove(line, &line[strspn(line, " \n\r\t\v")], len + 1); | ||
273 | |||
274 | /* If this is NOT a comment line, try to interpret it */ | ||
275 | if (*line != '#') interpret_table_entry(line); | ||
276 | } | ||
277 | if (line) free(line); | ||
278 | |||
279 | fclose(file); | ||
280 | } | ||
281 | |||
282 | static int go(char *dname, FILE * devtable) | ||
283 | { | ||
284 | struct stat sb; | ||
285 | |||
286 | if (lstat(dname, &sb)) { | ||
287 | perror_msg_and_die("%s", dname); | ||
288 | } | ||
289 | if (chdir(dname)) | ||
290 | perror_msg_and_die("%s", dname); | ||
291 | |||
292 | if (devtable) | ||
293 | parse_device_table(devtable); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | |||
299 | static struct option long_options[] = { | ||
300 | {"root", 1, NULL, 'r'}, | ||
301 | {"help", 0, NULL, 'h'}, | ||
302 | {"squash", 0, NULL, 'q'}, | ||
303 | {"version", 0, NULL, 'v'}, | ||
304 | {"devtable", 1, NULL, 'D'}, | ||
305 | {NULL, 0, NULL, 0} | ||
306 | }; | ||
307 | |||
308 | static char *helptext = | ||
309 | "Usage: makedevs [OPTIONS]\n" | ||
310 | "Build entries based upon device_table.txt\n\n" | ||
311 | "Options:\n" | ||
312 | " -r, -d, --root=DIR Build filesystem from directory DIR (default: cwd)\n" | ||
313 | " -D, --devtable=FILE Use the named FILE as a device table file\n" | ||
314 | " -q, --squash Squash permissions and owners making all files be owned by root\n" | ||
315 | " -h, --help Display this help text\n" | ||
316 | " -v, --version Display version information\n\n"; | ||
317 | |||
318 | |||
319 | static char *revtext = "$Revision: 0.1 $"; | ||
320 | |||
321 | int main(int argc, char **argv) | ||
322 | { | ||
323 | int c, opt; | ||
324 | extern char *optarg; | ||
325 | struct stat statbuf; | ||
326 | FILE *devtable = NULL; | ||
327 | |||
328 | umask (0); | ||
329 | |||
330 | while ((opt = getopt_long(argc, argv, "D:d:r:qhv", | ||
331 | long_options, &c)) >= 0) { | ||
332 | switch (opt) { | ||
333 | case 'D': | ||
334 | devtable = xfopen(optarg, "r"); | ||
335 | if (fstat(fileno(devtable), &statbuf) < 0) | ||
336 | perror_msg_and_die(optarg); | ||
337 | if (statbuf.st_size < 10) | ||
338 | error_msg_and_die("%s: not a proper device table file", optarg); | ||
339 | break; | ||
340 | case 'h': | ||
341 | fprintf(stderr, helptext); | ||
342 | exit(1); | ||
343 | case 'r': | ||
344 | case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */ | ||
345 | if (rootdir != default_rootdir) { | ||
346 | error_msg_and_die("root directory specified more than once"); | ||
347 | } | ||
348 | rootdir = xstrdup(optarg); | ||
349 | break; | ||
350 | |||
351 | case 'v': | ||
352 | fprintf(stderr, "makedevs revision %.*s\n", | ||
353 | (int) strlen(revtext) - 13, revtext + 11); | ||
354 | exit(1); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | go(rootdir, devtable); | ||
359 | return 0; | ||
360 | } | ||
diff --git a/meta/recipes-devtools/makedevs/makedevs_1.0.0.bb b/meta/recipes-devtools/makedevs/makedevs_1.0.0.bb new file mode 100644 index 0000000000..5db2d9b142 --- /dev/null +++ b/meta/recipes-devtools/makedevs/makedevs_1.0.0.bb | |||
@@ -0,0 +1,21 @@ | |||
1 | DESCRIPTION = "A tool to make device nodes" | ||
2 | LICENSE = "GPLv2" | ||
3 | SECTION = "base" | ||
4 | PRIORITY = "required" | ||
5 | SRC_URI = "file://makedevs.c" | ||
6 | PR = "r6" | ||
7 | |||
8 | do_configure() { | ||
9 | install -m 0644 ${WORKDIR}/makedevs.c ${S}/ | ||
10 | } | ||
11 | |||
12 | do_compile() { | ||
13 | ${CC} ${CFLAGS} -o ${S}/makedevs ${S}/makedevs.c | ||
14 | } | ||
15 | |||
16 | do_install() { | ||
17 | install -d ${D}${base_sbindir} | ||
18 | install -m 0755 ${S}/makedevs ${D}${base_sbindir}/makedevs | ||
19 | } | ||
20 | |||
21 | BBCLASSEXTEND = "native" | ||