Tomato 1.28
[tomato.git] / release / src / router / busybox / miscutils / makedevs.c
blobbe080552b76d652bd8fce635bca2be2410918cb5
1 /* vi: set sw=4 ts=4: */
2 /*
3 * public domain -- Dave 'Kill a Cop' Cinege <dcinege@psychosis.com>
5 * makedevs
6 * Make ranges of device files quickly.
7 * known bugs: can't deal with alpha ranges
8 */
10 #include "libbb.h"
12 #if ENABLE_FEATURE_MAKEDEVS_LEAF
14 makedevs NAME TYPE MAJOR MINOR FIRST LAST [s]
15 TYPEs:
16 b Block device
17 c Character device
18 f FIFO
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
26 int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
27 int makedevs_main(int argc, char **argv)
29 mode_t mode;
30 char *basedev, *type, *nodname, *buf;
31 int Smajor, Sminor, S, E;
33 if (argc < 7 || argv[1][0] == '-')
34 bb_show_usage();
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;
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();
60 while (S <= E) {
61 sprintf(buf, "%s%u", basedev, S);
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);
68 /*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
69 nodname = buf;
70 S++;
71 Sminor++;
74 return 0;
77 #elif ENABLE_FEATURE_MAKEDEVS_TABLE
79 /* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */
81 int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
82 int makedevs_main(int argc UNUSED_PARAM, char **argv)
84 parser_t *parser;
85 char *line = (char *)"-";
86 int ret = EXIT_SUCCESS;
88 opt_complementary = "=1"; /* exactly one param */
89 getopt32(argv, "d:", &line);
90 argv += optind;
92 xchdir(*argv); /* ensure root dir exists */
94 umask(0);
96 printf("rootdir=%s\ntable=", *argv);
97 if (NOT_LONE_DASH(line)) {
98 printf("'%s'\n", line);
99 } else {
100 puts("<stdin>");
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;
120 linenum = parser->lineno;
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)
127 bb_error_msg("invalid line %d: '%s'", linenum, line);
128 ret = EXIT_FAILURE;
129 continue;
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++;
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;
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;
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;
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;
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;
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;
198 free(full_name_inc);
201 if (ENABLE_FEATURE_CLEAN_UP)
202 config_close(parser);
204 return ret;
207 #else
208 # error makedevs configuration error, either leaf or table must be selected
209 #endif