3 * (C) Copyright 2010 Intel Corporation
5 * Author: Auke Kok <auke-jan.h.kok@intel.com>
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
18 #include <sys/types.h>
30 * dev_info - filter table
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.
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.
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.
54 unsigned int minor; /* 256 = all */
59 int uid; /* -1 in these fields cause owner/group to be */
60 int gid; /* looked up in /etc/group and /etc/passwd */
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 */
90 { ALL, 0, NULL, NULL, NULL, 0, 0, 0 },
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* */
98 { ALL, 0, NULL, NULL, NULL, 0, 0, 0 },
101 static void node_add(int type, unsigned int maj, unsigned int min,
102 char* name, struct dev_info *di)
106 unsigned int perms = 0660;
113 snprintf(path, PATH_MAX, "%s/%s", DEV, name);
115 while (di[n].major != ALL) {
116 if (maj != di[n].major)
118 if ((min != di[n].minor) && (di[n].minor != ALL))
121 if (di[n].dir != NULL) {
122 snprintf(path, PATH_MAX, "%s/%s", DEV, di[n].dir);
124 snprintf(path, PATH_MAX, "%s/%s/%s", DEV, di[n].dir, name);
129 if (di[n].uid == -1) {
130 p = getpwnam(di[n].owner);
139 if (di[n].gid == -1) {
140 g = getgrnam(di[n].group);
148 /* don't break, allow more filters to hit */
153 if ((owner == 0) && (group == 0)) {
154 mknod(path, type | perms, makedev(maj, min));
156 if (mknod(path, type, makedev(maj, min)))
158 if (chown(path, owner, group))
164 static void walk(const char *dir, int type, struct dev_info *di)
167 struct dirent *entry;
177 while ((entry = readdir(d))) {
180 if ((strcmp(".", entry->d_name) == 0) ||
181 (strcmp("..", entry->d_name) == 0))
184 sscanf(entry->d_name, "%d:%d", &maj, &min);
186 snprintf(p, PATH_MAX, "%s/%s", dir, entry->d_name);
187 len = readlink(p, path, PATH_MAX - 1);
191 node_add(type, maj, min, basename(path), di);
198 void populate_dev_blk(void)
201 walk("/sys/dev/block", S_IFBLK, di_blk);
205 void populate_dev_chr(void)
208 walk("/sys/dev/char", S_IFCHR, di_chr);
212 static struct option opts[] = {
213 { "block", 0, NULL, 'b' },
214 { "char", 0, NULL, 'c' },
215 { "help", 0, NULL, 'h' },
219 void usage(const char *name)
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");
227 int main(int argc, char **argv)
235 c = getopt_long(argc, argv, "bch", opts, &i);