makedevs: shrink by Vladimir
[platform/upstream/busybox.git] / miscutils / makedevs.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
4  *
5  * makedevs
6  * Make ranges of device files quickly.
7  * known bugs: can't deal with alpha ranges
8  */
9
10 #include "libbb.h"
11
12 #if ENABLE_FEATURE_MAKEDEVS_LEAF
13 /*
14 makedevs NAME TYPE MAJOR MINOR FIRST LAST [s]
15 TYPEs:
16 b       Block device
17 c       Character device
18 f       FIFO
19
20 FIRST..LAST specify numbers appended to NAME.
21 If 's' is the last argument, the base device is created as well.
22 Examples:
23         makedevs /dev/ttyS c 4 66 2 63   ->  ttyS2-ttyS63
24         makedevs /dev/hda b 3 0 0 8 s    ->  hda,hda1-hda8
25 */
26 int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
27 int makedevs_main(int argc, char **argv)
28 {
29         mode_t mode;
30         char *basedev, *type, *nodname, *buf;
31         int Smajor, Sminor, S, E;
32
33         if (argc < 7 || argv[1][0] == '-')
34                 bb_show_usage();
35
36         basedev = argv[1];
37         buf = xasprintf("%s%u", argv[1], (unsigned)-1);
38         type = argv[2];
39         Smajor = xatoi_u(argv[3]);
40         Sminor = xatoi_u(argv[4]);
41         S = xatoi_u(argv[5]);
42         E = xatoi_u(argv[6]);
43         nodname = argv[7] ? basedev : buf;
44
45         mode = 0660;
46         switch (type[0]) {
47         case 'c':
48                 mode |= S_IFCHR;
49                 break;
50         case 'b':
51                 mode |= S_IFBLK;
52                 break;
53         case 'f':
54                 mode |= S_IFIFO;
55                 break;
56         default:
57                 bb_show_usage();
58         }
59
60         while (S <= E) {
61                 sprintf(buf, "%s%u", basedev, S);
62
63                 /* if mode != S_IFCHR and != S_IFBLK,
64                  * third param in mknod() ignored */
65                 if (mknod(nodname, mode, makedev(Smajor, Sminor)))
66                         bb_perror_msg("can't create %s", nodname);
67
68                 /*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
69                         nodname = buf;
70                 S++;
71                 Sminor++;
72         }
73
74         return 0;
75 }
76
77 #elif ENABLE_FEATURE_MAKEDEVS_TABLE
78
79 /* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */
80
81 int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
82 int makedevs_main(int argc UNUSED_PARAM, char **argv)
83 {
84         parser_t *parser;
85         char *line = (char *)"-";
86         int ret = EXIT_SUCCESS;
87
88         opt_complementary = "=1"; /* exactly one param */
89         getopt32(argv, "d:", &line);
90         argv += optind;
91
92         xchdir(*argv); /* ensure root dir exists */
93
94         umask(0);
95
96         printf("rootdir=%s\ntable=", *argv);
97         if (NOT_LONE_DASH(line)) {
98                 printf("'%s'\n", line);
99         } else {
100                 puts("<stdin>");
101         }
102
103         parser = config_open(line);
104         while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) {
105                 int linenum;
106                 char type;
107                 unsigned mode = 0755;
108                 unsigned major = 0;
109                 unsigned minor = 0;
110                 unsigned count = 0;
111                 unsigned increment = 0;
112                 unsigned start = 0;
113                 char name[41];
114                 char user[41];
115                 char group[41];
116                 char *full_name = name;
117                 uid_t uid;
118                 gid_t gid;
119
120                 linenum = parser->lineno;
121
122                 if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u",
123                                         name, &type, &mode, user, group,
124                                         &major, &minor, &start, &increment, &count))
125                  || ((unsigned)(major | minor | start | count | increment) > 255)
126                 ) {
127                         bb_error_msg("invalid line %d: '%s'", linenum, line);
128                         ret = EXIT_FAILURE;
129                         continue;
130                 }
131
132                 gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
133                 uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
134                 /* We are already in the right root dir,
135                  * so make absolute paths relative */
136                 if ('/' == *full_name)
137                         full_name++;
138
139                 if (type == 'd') {
140                         bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
141                         if (chown(full_name, uid, gid) == -1) {
142  chown_fail:
143                                 bb_perror_msg("line %d: can't chown %s", linenum, full_name);
144                                 ret = EXIT_FAILURE;
145                                 continue;
146                         }
147                         if (chmod(full_name, mode) < 0) {
148  chmod_fail:
149                                 bb_perror_msg("line %d: can't chmod %s", linenum, full_name);
150                                 ret = EXIT_FAILURE;
151                                 continue;
152                         }
153                 } else if (type == 'f') {
154                         struct stat st;
155                         if ((stat(full_name, &st) < 0 || !S_ISREG(st.st_mode))) {
156                                 bb_perror_msg("line %d: regular file '%s' does not exist", linenum, full_name);
157                                 ret = EXIT_FAILURE;
158                                 continue;
159                         }
160                         if (chown(full_name, uid, gid) < 0)
161                                 goto chown_fail;
162                         if (chmod(full_name, mode) < 0)
163                                 goto chmod_fail;
164                 } else {
165                         dev_t rdev;
166                         unsigned i;
167                         char *full_name_inc;
168
169                         if (type == 'p') {
170                                 mode |= S_IFIFO;
171                         } else if (type == 'c') {
172                                 mode |= S_IFCHR;
173                         } else if (type == 'b') {
174                                 mode |= S_IFBLK;
175                         } else {
176                                 bb_error_msg("line %d: unsupported file type %c", linenum, type);
177                                 ret = EXIT_FAILURE;
178                                 continue;
179                         }
180
181                         full_name_inc = xmalloc(strlen(full_name) + sizeof(int)*3 + 2);
182                         if (count)
183                                 count--;
184                         for (i = start; i <= start + count; i++) {
185                                 sprintf(full_name_inc, count ? "%s%u" : "%s", full_name, i);
186                                 rdev = makedev(major, minor + (i - start) * increment);
187                                 if (mknod(full_name_inc, mode, rdev) < 0) {
188                                         bb_perror_msg("line %d: can't create node %s", linenum, full_name_inc);
189                                         ret = EXIT_FAILURE;
190                                 } else if (chown(full_name_inc, uid, gid) < 0) {
191                                         bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc);
192                                         ret = EXIT_FAILURE;
193                                 } else if (chmod(full_name_inc, mode) < 0) {
194                                         bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc);
195                                         ret = EXIT_FAILURE;
196                                 }
197                         }
198                         free(full_name_inc);
199                 }
200         }
201         if (ENABLE_FEATURE_CLEAN_UP)
202                 config_close(parser);
203
204         return ret;
205 }
206
207 #else
208 # error makedevs configuration error, either leaf or table must be selected
209 #endif