Upload Tizen:Main source
[external/mkdevnodes.git] / mkdevnodes.c
1
2 /*
3  * (C) Copyright 2010 Intel Corporation
4  *
5  * Author: Auke Kok <auke-jan.h.kok@intel.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; version 2
10  * of the License.
11  */
12
13 #define _GNU_SOURCE
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <getopt.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <pwd.h>
26 #include <grp.h>
27
28
29 /*
30  * dev_info - filter table
31  *
32  * devices found in sysfs often require different base permissions or
33  * group/owner ids. To set things up as correctly as possible, we
34  * traverse a table with overrides. The table is parsed in order and
35  * multiple fields can hit (e.g. one with the ALL wildcard, and one
36  * specific for the minor node number).  The last field to hit will
37  * effectively be used.
38  *
39  * ALL in the minor node field marks all minor nodes to use that field.
40  * ALL in the major node field marks the end of the table.
41  *
42  * a non-NULL string in the 'dir' field allows you to prepend a
43  * path between the device node and the /dev/ folder name. This is
44  * mostly used for alsa and v4l device nodes.
45  */
46
47 #define DEV "/dev"
48
49 #define ALL 256
50
51
52 struct dev_info {
53         unsigned int major;
54         unsigned int minor; /* 256 = all */
55         const char *dir;
56         const char *owner;
57         const char *group;
58         unsigned int perms;
59         int uid; /* -1 in these fields cause owner/group to be */
60         int gid; /* looked up in /etc/group and /etc/passwd */
61 };
62
63 static struct dev_info di_chr[] = {
64         {   1,    1,    NULL, "root",  "kmem", 0640,  0, -1 }, /* mem */
65         {   1,    2,    NULL, "root",  "kmem", 0640,  0, -1 }, /* kmem */
66         {   1,    3,    NULL, "root",  "root", 0666,  0,  0 }, /* null */
67         {   1,    4,    NULL, "root",  "kmem", 0640,  0, -1 }, /* port */
68         {   1,    5,    NULL, "root",  "root", 0666,  0,  0 }, /* zero */
69         {   1,    7,    NULL, "root",  "root", 0666,  0,  0 }, /* full */
70         {   1,    8,    NULL, "root",  "root", 0666,  0,  0 }, /* random */
71         {   1,    9,    NULL, "root",  "root", 0666,  0,  0 }, /* urandom */
72         {   2,  ALL,    NULL, "root",   "tty", 0660,  0, -1 }, /* pty */
73         {   3,  ALL,    NULL, "root",   "tty", 0660,  0, -1 }, /* tty* */
74         {   4,  ALL,    NULL, "root",   "tty", 0660,  0, -1 }, /* ttyS* */
75         {   5,    0,    NULL, "root",   "tty", 0666,  0, -1 }, /* tty */
76         {   5,    1,    NULL, "root",   "tty", 0600,  0, -1 }, /* console */
77         {   5,    2,    NULL, "root",   "tty", 0666,  0, -1 }, /* ptmx */
78         {   7,  ALL,    NULL, "root",   "tty", 0660,  0, -1 }, /* vcs* */
79         {  13,  ALL, "input", "root", "video", 0660,  0, -1 }, /* input */
80         {  10,  232,    NULL, "root",   "kvm", 0660,  0, -1 }, /* kvm */
81         {  14,  ALL,    NULL, "root", "audio", 0660,  0, -1 }, /* oss */
82         {  21,  ALL,    NULL, "root",  "disk", 0640,  0, -1 }, /* sg* */
83         {  29,  ALL,    NULL, "root", "video", 0600,  0, -1 }, /* fb* */
84         {  81,  ALL,   "v4l", "root", "video", 0660,  0, -1 }, /* v4l */
85         { 116,  ALL,   "snd", "root", "audio", 0660,  0, -1 }, /* alsa */
86         { 189,  ALL,   "usb", "root",  "root", 0600,  0,  0 }, /* usb */
87         { 226,  ALL,   "dri", "root", "video", 0660,  0,  0 }, /* dri */
88
89         /* terminate */
90         { ALL, 0, NULL, NULL, NULL, 0, 0, 0 },
91 };
92
93 static struct dev_info di_blk[] = {
94         {  1, ALL, NULL, "root",  "disk", 0640,  0, -1 }, /* ram* */
95         {  8, ALL, NULL, "root",  "disk", 0640,  0, -1 }, /* sd* */
96         { 11, ALL, NULL, "root", "cdrom", 0640,  0, -1 }, /* sr* */
97         /* terminate */
98         { ALL, 0, NULL, NULL, NULL, 0, 0, 0 },
99 };
100
101 static void node_add(int type, unsigned int maj, unsigned int min,
102                      char* name, struct dev_info *di)
103 {
104         struct passwd *p;
105         struct group *g;
106         unsigned int perms = 0660;
107         int owner = 0;
108         int group = 0;
109         char path[PATH_MAX];
110         int n = 0;
111
112         /* defaults */
113         snprintf(path, PATH_MAX, "%s/%s", DEV, name);
114
115         while (di[n].major != ALL) {
116                 if (maj != di[n].major)
117                         goto out;
118                 if ((min != di[n].minor) && (di[n].minor != ALL))
119                         goto out;
120
121                 if (di[n].dir != NULL) {
122                         snprintf(path, PATH_MAX, "%s/%s", DEV, di[n].dir);
123                         mkdir(path, 0755);
124                         snprintf(path, PATH_MAX, "%s/%s/%s", DEV, di[n].dir, name);
125                 }
126
127                 perms = di[n].perms;
128
129                 if (di[n].uid == -1) {
130                         p = getpwnam(di[n].owner);
131                         if (p) {
132                                 owner = p->pw_uid;
133                                 di[n].uid = owner;
134                         }
135                 } else {
136                         owner = di[n].uid;
137                 }
138
139                 if (di[n].gid == -1) {
140                         g = getgrnam(di[n].group);
141                         if (g) {
142                                 group = g->gr_gid;
143                                 di[n].gid = group;
144                         }
145                 } else {
146                         group = di[n].gid;
147                 }
148                 /* don't break, allow more filters to hit */
149 out:
150                 n++;
151         }
152
153         if ((owner == 0) && (group == 0)) {
154                 mknod(path, type | perms, makedev(maj, min));
155         } else {
156                 if (mknod(path, type, makedev(maj, min)))
157                         return;
158                 if (chown(path, owner, group))
159                         return;
160                 chmod(path, perms);
161         }
162 }
163
164 static void walk(const char *dir, int type, struct dev_info *di)
165 {
166         DIR *d;
167         struct dirent *entry;
168         char path[PATH_MAX];
169         ssize_t len;
170         unsigned int maj;
171         unsigned int min;
172
173         d = opendir(dir);
174         if (!d)
175                 return;
176
177         while ((entry = readdir(d))) {
178                 char p[PATH_MAX];
179
180                 if ((strcmp(".", entry->d_name) == 0) ||
181                     (strcmp("..", entry->d_name) == 0))
182                         continue;
183
184                 sscanf(entry->d_name, "%d:%d", &maj, &min);
185
186                 snprintf(p, PATH_MAX, "%s/%s", dir, entry->d_name);
187                 len = readlink(p, path, PATH_MAX - 1);
188                 if (len != -1)
189                         path[len] = '\0';
190
191                 node_add(type, maj, min, basename(path), di);
192
193         }
194
195         closedir(d);
196 }
197
198 void populate_dev_blk(void)
199 {
200         int u = umask(0000);
201         walk("/sys/dev/block", S_IFBLK, di_blk);
202         umask(u);
203 }
204
205 void populate_dev_chr(void)
206 {
207         int u = umask(0000);
208         walk("/sys/dev/char", S_IFCHR, di_chr);
209         umask(u);
210 }
211
212 static struct option opts[] = {
213         { "block", 0, NULL, 'b' },
214         { "char", 0, NULL, 'c' },
215         { "help", 0, NULL, 'h' },
216         { 0, 0, NULL, 0 }
217 };
218
219 void usage(const char *name)
220 {
221         printf("Usage: %s [OPTION...]\n", name);
222         printf("  -b, --block        Only create block device nodes\n");
223         printf("  -c, --char         Only create char device nodes \n"); 
224         printf("  -h, --help         Show this help message\n"); 
225 }
226
227 int main(int argc, char **argv)
228 {
229         int c;
230         int i;
231         int blk = 1;
232         int chr = 1;
233
234         while (1) {
235                 c = getopt_long(argc, argv, "bch", opts, &i);
236                 if (c == -1)
237                         break;
238
239                 switch (c) {
240                 case 'b':
241                         chr = 0;
242                         break;
243                 case 'c':
244                         blk = 0;
245                         break;
246                 case 'h':
247                         usage(argv[0]);
248                         exit (EXIT_SUCCESS);
249                         break;
250                 default:
251                         break;
252                 }
253         }
254
255         if (blk)
256                 populate_dev_blk();
257         if (chr)
258                 populate_dev_chr();
259         exit (EXIT_SUCCESS);
260 }