blob: abf50577002151214e97ffa36294f3694a8bef2a [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Bernhard Reutner-Fischerd9cf7ac2006-04-12 18:39:58 +00002/*
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 */
Eric Andersen3d925622005-06-09 10:16:02 +00009
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Eric Andersen3d925622005-06-09 10:16:02 +000011
Denis Vlasenkoe3241842007-08-13 10:36:25 +000012#if ENABLE_FEATURE_MAKEDEVS_LEAF
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000013/*
14makedevs NAME TYPE MAJOR MINOR FIRST LAST [s]
15TYPEs:
16b Block device
17c Character device
Denis Vlasenkob2dc9132008-08-03 22:14:02 +000018f FIFO
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000019
20FIRST..LAST specify numbers appended to NAME.
21If 's' is the last argument, the base device is created as well.
22Examples:
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*/
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000026int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000027int makedevs_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +000028{
Eric Andersen36006022002-06-08 12:44:17 +000029 mode_t mode;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000030 char *basedev, *type, *nodname, *buf;
Eric Andersen4f807a82004-07-26 09:11:12 +000031 int Smajor, Sminor, S, E;
Eric Andersencc8ed391999-10-05 16:24:54 +000032
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000033 if (argc < 7 || argv[1][0] == '-')
Manuel Novoa III cad53642003-03-19 09:13:01 +000034 bb_show_usage();
Erik Andersen5e1189e2000-04-15 16:34:54 +000035
Eric Andersen19732c62002-04-13 14:26:44 +000036 basedev = argv[1];
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000037 buf = xasprintf("%s%u", argv[1], (unsigned)-1);
Eric Andersen19732c62002-04-13 14:26:44 +000038 type = argv[2];
Denis Vlasenko13858992006-10-08 12:49:22 +000039 Smajor = xatoi_u(argv[3]);
40 Sminor = xatoi_u(argv[4]);
41 S = xatoi_u(argv[5]);
42 E = xatoi_u(argv[6]);
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000043 nodname = argv[7] ? basedev : buf;
Eric Andersen36006022002-06-08 12:44:17 +000044
45 mode = 0660;
Eric Andersencc8ed391999-10-05 16:24:54 +000046 switch (type[0]) {
Erik Andersene49d5ec2000-02-08 19:58:47 +000047 case 'c':
Eric Andersen36006022002-06-08 12:44:17 +000048 mode |= S_IFCHR;
Erik Andersene49d5ec2000-02-08 19:58:47 +000049 break;
50 case 'b':
Eric Andersen36006022002-06-08 12:44:17 +000051 mode |= S_IFBLK;
Erik Andersene49d5ec2000-02-08 19:58:47 +000052 break;
53 case 'f':
Eric Andersen36006022002-06-08 12:44:17 +000054 mode |= S_IFIFO;
Erik Andersene49d5ec2000-02-08 19:58:47 +000055 break;
56 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +000057 bb_show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 }
Eric Andersencc8ed391999-10-05 16:24:54 +000059
Erik Andersene49d5ec2000-02-08 19:58:47 +000060 while (S <= E) {
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000061 sprintf(buf, "%s%u", basedev, S);
Erik Andersene49d5ec2000-02-08 19:58:47 +000062
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000063 /* if mode != S_IFCHR and != S_IFBLK,
64 * third param in mknod() ignored */
Eric Andersene71e7602004-07-30 14:36:37 +000065 if (mknod(nodname, mode, makedev(Smajor, Sminor)))
Denys Vlasenko651a2692010-03-23 16:25:17 +010066 bb_perror_msg("can't create '%s'", nodname);
Erik Andersene49d5ec2000-02-08 19:58:47 +000067
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000068 /*if (nodname == basedev)*/ /* ex. /dev/hda - to /dev/hda1 ... */
Eric Andersen36006022002-06-08 12:44:17 +000069 nodname = buf;
Erik Andersene49d5ec2000-02-08 19:58:47 +000070 S++;
71 Sminor++;
Eric Andersencc8ed391999-10-05 16:24:54 +000072 }
73
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 return 0;
Eric Andersencc8ed391999-10-05 16:24:54 +000075}
76
Denis Vlasenkoe3241842007-08-13 10:36:25 +000077#elif ENABLE_FEATURE_MAKEDEVS_TABLE
Eric Andersen3d925622005-06-09 10:16:02 +000078
Rob Landley1b751c82005-10-28 09:24:33 +000079/* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */
Eric Andersencc8ed391999-10-05 16:24:54 +000080
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000081int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000082int makedevs_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen3d925622005-06-09 10:16:02 +000083{
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000084 parser_t *parser;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000085 char *line = (char *)"-";
Eric Andersen3d925622005-06-09 10:16:02 +000086 int ret = EXIT_SUCCESS;
Eric Andersencc8ed391999-10-05 16:24:54 +000087
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000088 opt_complementary = "=1"; /* exactly one param */
Denis Vlasenkofe7cd642007-08-18 15:32:12 +000089 getopt32(argv, "d:", &line);
Denis Vlasenkob2dc9132008-08-03 22:14:02 +000090 argv += optind;
Eric Andersene8614db2005-07-18 09:28:36 +000091
Denis Vlasenkob2dc9132008-08-03 22:14:02 +000092 xchdir(*argv); /* ensure root dir exists */
Eric Andersen3d925622005-06-09 10:16:02 +000093
94 umask(0);
95
Denis Vlasenkob2dc9132008-08-03 22:14:02 +000096 printf("rootdir=%s\ntable=", *argv);
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +000097 if (NOT_LONE_DASH(line)) {
Denis Vlasenkob2dc9132008-08-03 22:14:02 +000098 printf("'%s'\n", line);
Eric Andersene8614db2005-07-18 09:28:36 +000099 } else {
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000100 puts("<stdin>");
Eric Andersene8614db2005-07-18 09:28:36 +0000101 }
102
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000103 parser = config_open(line);
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000104 while (config_read(parser, &line, 1, 1, "# \t", PARSE_NORMAL)) {
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000105 int linenum;
Eric Andersen3d925622005-06-09 10:16:02 +0000106 char type;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000107 unsigned mode = 0755;
108 unsigned major = 0;
109 unsigned minor = 0;
110 unsigned count = 0;
111 unsigned increment = 0;
112 unsigned start = 0;
Eric Andersen3d925622005-06-09 10:16:02 +0000113 char name[41];
114 char user[41];
115 char group[41];
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000116 char *full_name = name;
Eric Andersen3d925622005-06-09 10:16:02 +0000117 uid_t uid;
118 gid_t gid;
119
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000120 linenum = parser->lineno;
Eric Andersene8614db2005-07-18 09:28:36 +0000121
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000122 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 ) {
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000127 bb_error_msg("invalid line %d: '%s'", linenum, line);
Eric Andersen3d925622005-06-09 10:16:02 +0000128 ret = EXIT_FAILURE;
129 continue;
130 }
Bernhard Reutner-Fischer17329742005-12-21 15:07:30 +0000131
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +0000132 gid = (*group) ? get_ug_id(group, xgroup2gid) : getgid();
133 uid = (*user) ? get_ug_id(user, xuname2uid) : getuid();
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000134 /* We are already in the right root dir,
135 * so make absolute paths relative */
136 if ('/' == *full_name)
137 full_name++;
Eric Andersen3d925622005-06-09 10:16:02 +0000138
139 if (type == 'd') {
Eric Andersene8614db2005-07-18 09:28:36 +0000140 bb_make_directory(full_name, mode | S_IFDIR, FILEUTILS_RECUR);
Eric Andersen3d925622005-06-09 10:16:02 +0000141 if (chown(full_name, uid, gid) == -1) {
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000142 chown_fail:
143 bb_perror_msg("line %d: can't chown %s", linenum, full_name);
Eric Andersen3d925622005-06-09 10:16:02 +0000144 ret = EXIT_FAILURE;
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000145 continue;
Eric Andersen3d925622005-06-09 10:16:02 +0000146 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000147 if (chmod(full_name, mode) < 0) {
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000148 chmod_fail:
149 bb_perror_msg("line %d: can't chmod %s", linenum, full_name);
Eric Andersen90161c92005-07-18 22:40:59 +0000150 ret = EXIT_FAILURE;
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000151 continue;
Eric Andersen90161c92005-07-18 22:40:59 +0000152 }
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;
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000158 continue;
Eric Andersen90161c92005-07-18 22:40:59 +0000159 }
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000160 if (chown(full_name, uid, gid) < 0)
161 goto chown_fail;
162 if (chmod(full_name, mode) < 0)
163 goto chmod_fail;
Denis Vlasenkoe3241842007-08-13 10:36:25 +0000164 } else {
Eric Andersen3d925622005-06-09 10:16:02 +0000165 dev_t rdev;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000166 unsigned i;
167 char *full_name_inc;
Eric Andersen3d925622005-06-09 10:16:02 +0000168
169 if (type == 'p') {
170 mode |= S_IFIFO;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000171 } else if (type == 'c') {
Eric Andersen3d925622005-06-09 10:16:02 +0000172 mode |= S_IFCHR;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000173 } else if (type == 'b') {
Eric Andersen3d925622005-06-09 10:16:02 +0000174 mode |= S_IFBLK;
175 } else {
Eric Andersen2ada89b2005-07-18 09:45:35 +0000176 bb_error_msg("line %d: unsupported file type %c", linenum, type);
Eric Andersen3d925622005-06-09 10:16:02 +0000177 ret = EXIT_FAILURE;
Denis Vlasenkob2dc9132008-08-03 22:14:02 +0000178 continue;
Eric Andersen3d925622005-06-09 10:16:02 +0000179 }
180
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000181 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);
Eric Andersen3d925622005-06-09 10:16:02 +0000189 ret = EXIT_FAILURE;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000190 } else if (chown(full_name_inc, uid, gid) < 0) {
191 bb_perror_msg("line %d: can't chown %s", linenum, full_name_inc);
Eric Andersen3d925622005-06-09 10:16:02 +0000192 ret = EXIT_FAILURE;
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000193 } else if (chmod(full_name_inc, mode) < 0) {
194 bb_perror_msg("line %d: can't chmod %s", linenum, full_name_inc);
Eric Andersen90161c92005-07-18 22:40:59 +0000195 ret = EXIT_FAILURE;
196 }
Eric Andersen3d925622005-06-09 10:16:02 +0000197 }
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000198 free(full_name_inc);
Eric Andersen3d925622005-06-09 10:16:02 +0000199 }
Eric Andersen3d925622005-06-09 10:16:02 +0000200 }
Denis Vlasenkoe1fa8172008-08-01 02:15:05 +0000201 if (ENABLE_FEATURE_CLEAN_UP)
202 config_close(parser);
Eric Andersen3d925622005-06-09 10:16:02 +0000203
Bernhard Reutner-Fischer56fbd212006-04-24 17:41:29 +0000204 return ret;
Eric Andersencc8ed391999-10-05 16:24:54 +0000205}
Eric Andersene8614db2005-07-18 09:28:36 +0000206
Eric Andersen3d925622005-06-09 10:16:02 +0000207#else
Bernhard Reutner-Fischer771b1862006-03-24 14:30:05 +0000208# error makedevs configuration error, either leaf or table must be selected
Eric Andersen3d925622005-06-09 10:16:02 +0000209#endif