diff options
author | Chen Qi <Qi.Chen@windriver.com> | 2013-08-13 14:11:49 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2013-08-16 11:14:33 +0100 |
commit | 36d622b4c6e2ff1e976b713c6841383f4188f851 (patch) | |
tree | dcc8ed0dbaaa4362702beb5c6e7afe2a73d61dae | |
parent | ca367d02fde01bebc37666a05341a91d6b1366cc (diff) | |
download | poky-36d622b4c6e2ff1e976b713c6841383f4188f851.tar.gz |
makedevs: support using user/group names in device table files
Compared to hard coding the numeric group and user ids in the device
table files, the way of using user/group names is preferred.
This patch adds the ability to makedevs to correctly deal with device
table files with user/group names in them.
To maintain backward compatibility, the way of using uid/gid is still
supported.
[YOCTO #1159]
(From OE-Core rev: 1fcf718e3a1e50446ab61972069566e5016bc625)
Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
Signed-off-by: Saul Wold <sgw@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c | 207 |
1 files changed, 178 insertions, 29 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 index 6c1f2fb461..cc3707b2c8 100644 --- a/meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c +++ b/meta/recipes-devtools/makedevs/makedevs-1.0.0/makedevs.c | |||
@@ -16,6 +16,11 @@ | |||
16 | 16 | ||
17 | #define MINORBITS 8 | 17 | #define MINORBITS 8 |
18 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) | 18 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) |
19 | #define MAX_ID_LEN 40 | ||
20 | #define MAX_NAME_LEN 40 | ||
21 | #ifndef PATH_MAX | ||
22 | #define PATH_MAX 4096 | ||
23 | #endif | ||
19 | 24 | ||
20 | /* These are all stolen from busybox's libbb to make | 25 | /* These are all stolen from busybox's libbb to make |
21 | * error handling simpler (and since I maintain busybox, | 26 | * error handling simpler (and since I maintain busybox, |
@@ -27,6 +32,15 @@ static const char *const memory_exhausted = "memory exhausted"; | |||
27 | static char default_rootdir[]="."; | 32 | static char default_rootdir[]="."; |
28 | static char *rootdir = default_rootdir; | 33 | static char *rootdir = default_rootdir; |
29 | 34 | ||
35 | struct name_id { | ||
36 | char name[MAX_NAME_LEN+1]; | ||
37 | unsigned long id; | ||
38 | struct name_id *next; | ||
39 | }; | ||
40 | |||
41 | static struct name_id *usr_list = NULL; | ||
42 | static struct name_id *grp_list = NULL; | ||
43 | |||
30 | static void verror_msg(const char *s, va_list p) | 44 | static void verror_msg(const char *s, va_list p) |
31 | { | 45 | { |
32 | fflush(stdout); | 46 | fflush(stdout); |
@@ -57,17 +71,6 @@ static void vperror_msg(const char *s, va_list p) | |||
57 | fprintf(stderr, "%s%s\n", s, strerror(err)); | 71 | fprintf(stderr, "%s%s\n", s, strerror(err)); |
58 | } | 72 | } |
59 | 73 | ||
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, ...) | 74 | static void perror_msg_and_die(const char *s, ...) |
72 | { | 75 | { |
73 | va_list p; | 76 | va_list p; |
@@ -102,6 +105,124 @@ static char *xstrdup(const char *s) | |||
102 | return t; | 105 | return t; |
103 | } | 106 | } |
104 | 107 | ||
108 | static struct name_id* alloc_node(void) | ||
109 | { | ||
110 | struct name_id *node; | ||
111 | node = (struct name_id*)malloc(sizeof(struct name_id)); | ||
112 | if (node == NULL) { | ||
113 | error_msg_and_die(memory_exhausted); | ||
114 | } | ||
115 | memset((void *)node->name, 0, MAX_NAME_LEN+1); | ||
116 | node->id = 0xffffffff; | ||
117 | node->next = NULL; | ||
118 | return node; | ||
119 | } | ||
120 | |||
121 | static struct name_id* parse_line(char *line) | ||
122 | { | ||
123 | char *p; | ||
124 | int i; | ||
125 | char id_buf[MAX_ID_LEN+1]; | ||
126 | struct name_id *node; | ||
127 | node = alloc_node(); | ||
128 | p = line; | ||
129 | i = 0; | ||
130 | // Get name field | ||
131 | while (*p != ':') { | ||
132 | if (i > MAX_NAME_LEN) | ||
133 | error_msg_and_die("Name field too long"); | ||
134 | node->name[i++] = *p++; | ||
135 | } | ||
136 | node->name[i] = '\0'; | ||
137 | p++; | ||
138 | // Skip the second field | ||
139 | while (*p != ':') | ||
140 | p++; | ||
141 | p++; | ||
142 | // Get id field | ||
143 | i = 0; | ||
144 | while (*p != ':') { | ||
145 | if (i > MAX_ID_LEN) | ||
146 | error_msg_and_die("ID filed too long"); | ||
147 | id_buf[i++] = *p++; | ||
148 | } | ||
149 | id_buf[i] = '\0'; | ||
150 | node->id = atol(id_buf); | ||
151 | return node; | ||
152 | } | ||
153 | |||
154 | static void get_list_from_file(FILE *file, struct name_id **plist) | ||
155 | { | ||
156 | char *line; | ||
157 | int len = 0; | ||
158 | size_t length = 256; | ||
159 | struct name_id *node, *cur; | ||
160 | |||
161 | if((line = (char *)malloc(length)) == NULL) { | ||
162 | error_msg_and_die(memory_exhausted); | ||
163 | } | ||
164 | |||
165 | while ((len = getline(&line, &length, file)) != -1) { | ||
166 | node = parse_line(line); | ||
167 | if (*plist == NULL) { | ||
168 | *plist = node; | ||
169 | cur = *plist; | ||
170 | } else { | ||
171 | cur->next = node; | ||
172 | cur = cur->next; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | if (line) | ||
177 | free(line); | ||
178 | } | ||
179 | |||
180 | static unsigned long convert2guid(char *id_buf, struct name_id *search_list) | ||
181 | { | ||
182 | char *p; | ||
183 | int isnum; | ||
184 | struct name_id *node; | ||
185 | p = id_buf; | ||
186 | isnum = 1; | ||
187 | while (*p != '\0') { | ||
188 | if (!isdigit(*p)) { | ||
189 | isnum = 0; | ||
190 | break; | ||
191 | } | ||
192 | p++; | ||
193 | } | ||
194 | if (isnum) { | ||
195 | // Check for bad user/group name | ||
196 | node = search_list; | ||
197 | while (node != NULL) { | ||
198 | if (!strncmp(node->name, id_buf, strlen(id_buf))) { | ||
199 | fprintf(stderr, "WARNING: Bad user/group name %s detected\n", id_buf); | ||
200 | break; | ||
201 | } | ||
202 | node = node->next; | ||
203 | } | ||
204 | return (unsigned long)atol(id_buf); | ||
205 | } else { | ||
206 | node = search_list; | ||
207 | while (node != NULL) { | ||
208 | if (!strncmp(node->name, id_buf, strlen(id_buf))) | ||
209 | return node->id; | ||
210 | node = node->next; | ||
211 | } | ||
212 | error_msg_and_die("No entry for %s in search list", id_buf); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void free_list(struct name_id *list) | ||
217 | { | ||
218 | struct name_id *cur; | ||
219 | cur = list; | ||
220 | while (cur != NULL) { | ||
221 | list = cur; | ||
222 | cur = cur->next; | ||
223 | free(list); | ||
224 | } | ||
225 | } | ||
105 | 226 | ||
106 | static void add_new_directory(char *name, char *path, | 227 | static void add_new_directory(char *name, char *path, |
107 | unsigned long uid, unsigned long gid, unsigned long mode) | 228 | unsigned long uid, unsigned long gid, unsigned long mode) |
@@ -162,8 +283,9 @@ static void add_new_fifo(char *name, char *path, unsigned long uid, | |||
162 | 283 | ||
163 | 284 | ||
164 | /* device table entries take the form of: | 285 | /* device table entries take the form of: |
165 | <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count> | 286 | <path> <type> <mode> <usr> <grp> <major> <minor> <start> <inc> <count> |
166 | /dev/mem c 640 0 0 1 1 0 0 - | 287 | /dev/mem c 640 0 0 1 1 0 0 - |
288 | /dev/zero c 644 root root 1 5 - - - | ||
167 | 289 | ||
168 | type can be one of: | 290 | type can be one of: |
169 | f A regular file | 291 | f A regular file |
@@ -181,18 +303,23 @@ static void add_new_fifo(char *name, char *path, unsigned long uid, | |||
181 | static int interpret_table_entry(char *line) | 303 | static int interpret_table_entry(char *line) |
182 | { | 304 | { |
183 | char *name; | 305 | char *name; |
306 | char usr_buf[MAX_ID_LEN]; | ||
307 | char grp_buf[MAX_ID_LEN]; | ||
184 | char path[4096], type; | 308 | char path[4096], type; |
185 | unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; | 309 | unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; |
186 | unsigned long start = 0, increment = 1, count = 0; | 310 | unsigned long start = 0, increment = 1, count = 0; |
187 | 311 | ||
188 | if (0 > sscanf(line, "%40s %c %lo %lu %lu %lu %lu %lu %lu %lu", path, | 312 | if (0 > sscanf(line, "%40s %c %lo %40s %40s %lu %lu %lu %lu %lu", path, |
189 | &type, &mode, &uid, &gid, &major, &minor, &start, | 313 | &type, &mode, usr_buf, grp_buf, &major, &minor, &start, |
190 | &increment, &count)) | 314 | &increment, &count)) |
191 | { | 315 | { |
192 | return 1; | 316 | return 1; |
193 | } | 317 | } |
194 | 318 | ||
195 | if (!strcmp(path, "/")) { | 319 | uid = convert2guid(usr_buf, usr_list); |
320 | gid = convert2guid(grp_buf, grp_list); | ||
321 | |||
322 | if (strncmp(path, "/", 1)) { | ||
196 | error_msg_and_die("Device table entries require absolute paths"); | 323 | error_msg_and_die("Device table entries require absolute paths"); |
197 | } | 324 | } |
198 | name = xstrdup(path + 1); | 325 | name = xstrdup(path + 1); |
@@ -231,7 +358,6 @@ static int interpret_table_entry(char *line) | |||
231 | /* FIXME: MKDEV uses illicit insider knowledge of kernel | 358 | /* FIXME: MKDEV uses illicit insider knowledge of kernel |
232 | * major/minor representation... */ | 359 | * major/minor representation... */ |
233 | dev_t rdev = MKDEV(major, minor); | 360 | dev_t rdev = MKDEV(major, minor); |
234 | |||
235 | add_new_device(name, path, uid, gid, mode, rdev); | 361 | add_new_device(name, path, uid, gid, mode, rdev); |
236 | } | 362 | } |
237 | break; | 363 | break; |
@@ -249,17 +375,15 @@ static void parse_device_table(FILE * file) | |||
249 | size_t length = 256; | 375 | size_t length = 256; |
250 | int len = 0; | 376 | int len = 0; |
251 | 377 | ||
378 | if((line = (char *)malloc(length)) == NULL) { | ||
379 | error_msg_and_die(memory_exhausted); | ||
380 | } | ||
252 | /* Looks ok so far. The general plan now is to read in one | 381 | /* Looks ok so far. The general plan now is to read in one |
253 | * line at a time, check for leading comment delimiters ('#'), | 382 | * line at a time, check for leading comment delimiters ('#'), |
254 | * then try and parse the line as a device table. If we fail | 383 | * then try and parse the line as a device table. If we fail |
255 | * to parse things, try and help the poor fool to fix their | 384 | * to parse things, try and help the poor fool to fix their |
256 | * device table with a useful error msg... */ | 385 | * device table with a useful error msg... */ |
257 | 386 | ||
258 | if((line = (char *)malloc(length)) == NULL) { | ||
259 | fclose(file); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | while ((len = getline(&line, &length, file)) != -1) { | 387 | while ((len = getline(&line, &length, file)) != -1) { |
264 | /* First trim off any whitespace */ | 388 | /* First trim off any whitespace */ |
265 | 389 | ||
@@ -273,20 +397,20 @@ static void parse_device_table(FILE * file) | |||
273 | /* If this is NOT a comment line, try to interpret it */ | 397 | /* If this is NOT a comment line, try to interpret it */ |
274 | if (*line != '#') interpret_table_entry(line); | 398 | if (*line != '#') interpret_table_entry(line); |
275 | } | 399 | } |
276 | if (line) free(line); | ||
277 | 400 | ||
278 | fclose(file); | 401 | if (line) |
402 | free(line); | ||
279 | } | 403 | } |
280 | 404 | ||
281 | static int go(char *dname, FILE * devtable) | 405 | static int parse_devtable(FILE * devtable) |
282 | { | 406 | { |
283 | struct stat sb; | 407 | struct stat sb; |
284 | 408 | ||
285 | if (lstat(dname, &sb)) { | 409 | if (lstat(rootdir, &sb)) { |
286 | perror_msg_and_die("%s", dname); | 410 | perror_msg_and_die("%s", rootdir); |
287 | } | 411 | } |
288 | if (chdir(dname)) | 412 | if (chdir(rootdir)) |
289 | perror_msg_and_die("%s", dname); | 413 | perror_msg_and_die("%s", rootdir); |
290 | 414 | ||
291 | if (devtable) | 415 | if (devtable) |
292 | parse_device_table(devtable); | 416 | parse_device_table(devtable); |
@@ -322,6 +446,10 @@ int main(int argc, char **argv) | |||
322 | int c, opt; | 446 | int c, opt; |
323 | extern char *optarg; | 447 | extern char *optarg; |
324 | struct stat statbuf; | 448 | struct stat statbuf; |
449 | char passwd_path[PATH_MAX]; | ||
450 | char group_path[PATH_MAX]; | ||
451 | FILE *passwd_file = NULL; | ||
452 | FILE *group_file = NULL; | ||
325 | FILE *devtable = NULL; | 453 | FILE *devtable = NULL; |
326 | 454 | ||
327 | umask (0); | 455 | umask (0); |
@@ -354,6 +482,27 @@ int main(int argc, char **argv) | |||
354 | } | 482 | } |
355 | } | 483 | } |
356 | 484 | ||
357 | go(rootdir, devtable); | 485 | // Get name-id mapping |
486 | sprintf(passwd_path, "%s/etc/passwd", rootdir); | ||
487 | sprintf(group_path, "%s/etc/group", rootdir); | ||
488 | if ((passwd_file = fopen(passwd_path, "r")) != NULL) { | ||
489 | get_list_from_file(passwd_file, &usr_list); | ||
490 | fclose(passwd_file); | ||
491 | } | ||
492 | if ((group_file = fopen(group_path, "r")) != NULL) { | ||
493 | get_list_from_file(group_file, &grp_list); | ||
494 | fclose(group_file); | ||
495 | } | ||
496 | |||
497 | // Parse devtable | ||
498 | if(devtable) { | ||
499 | parse_devtable(devtable); | ||
500 | fclose(devtable); | ||
501 | } | ||
502 | |||
503 | // Free list | ||
504 | free_list(usr_list); | ||
505 | free_list(grp_list); | ||
506 | |||
358 | return 0; | 507 | return 0; |
359 | } | 508 | } |