]>
Commit | Line | Data |
---|---|---|
ea733a2f GKH |
1 | /* |
2 | * udev-add.c | |
3 | * | |
4 | * Userspace devfs | |
5 | * | |
6 | * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> | |
7 | * | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation version 2 of the License. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
20 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <stdio.h> | |
27 | #include <fcntl.h> | |
28 | #include <unistd.h> | |
29 | #include <errno.h> | |
30 | ||
31 | #include "udev.h" | |
32 | #include "udev_version.h" | |
33 | #include "namedev.h" | |
8e41d35d | 34 | #include "udevdb.h" |
ea733a2f GKH |
35 | #include "libsysfs/libsysfs.h" |
36 | ||
37 | ||
ea733a2f GKH |
38 | /* |
39 | * Right now the major/minor of a device is stored in a file called | |
40 | * "dev" in sysfs. | |
41 | * The number is stored as: | |
42 | * MMmm | |
43 | * MM is the major | |
44 | * mm is the minor | |
45 | * The value is in hex. | |
46 | * Yes, this will probably change when we go to a bigger major/minor | |
47 | * range, and will have to be changed at that time. | |
48 | */ | |
49 | static int get_major_minor(struct sysfs_class_device *class_dev, int *major, int *minor) | |
50 | { | |
ea256f90 | 51 | int retval = -ENODEV; |
ea733a2f GKH |
52 | |
53 | char *dev; | |
54 | ||
55 | dev = sysfs_get_value_from_attributes(class_dev->directory->attributes, "dev"); | |
56 | if (dev == NULL) | |
ea256f90 | 57 | goto exit; |
ea733a2f GKH |
58 | |
59 | dbg("dev = %s", dev); | |
60 | ||
ea256f90 GKH |
61 | if (sscanf(dev, "%u:%u", major, minor) != 2) |
62 | goto exit; | |
ea733a2f GKH |
63 | |
64 | dbg("found major = %d, minor = %d", *major, *minor); | |
65 | ||
66 | retval = 0; | |
ea256f90 | 67 | exit: |
ea733a2f GKH |
68 | return retval; |
69 | } | |
70 | ||
71 | /* | |
72 | * We also want to add some permissions here, and possibly some symlinks | |
73 | */ | |
c2405f50 | 74 | static int create_node(char *name, char type, int major, int minor, mode_t mode) |
ea733a2f | 75 | { |
ea733a2f GKH |
76 | char filename[255]; |
77 | int retval = 0; | |
ea733a2f GKH |
78 | strncpy(filename, UDEV_ROOT, sizeof(filename)); |
79 | strncat(filename, name, sizeof(filename)); | |
1331c889 GKH |
80 | switch (type) { |
81 | case 'b': | |
82 | mode |= S_IFBLK; | |
83 | break; | |
84 | case 'c': | |
85 | case 'u': | |
86 | mode |= S_IFCHR; | |
87 | break; | |
88 | case 'p': | |
89 | mode |= S_IFIFO; | |
90 | break; | |
91 | default: | |
92 | dbg("unknown node type %c\n", type); | |
93 | return -EINVAL; | |
94 | } | |
0abf54fc | 95 | |
8479066e | 96 | dbg("mknod(%s, %#o, %u, %u)", filename, mode, major, minor); |
c2405f50 | 97 | retval = mknod(filename, mode, makedev(major, minor)); |
1331c889 GKH |
98 | if (retval) |
99 | dbg("mknod(%s, %#o, %u, %u) failed with error '%s'", | |
100 | filename, mode, major, minor, strerror(errno)); | |
ea733a2f GKH |
101 | return retval; |
102 | } | |
103 | ||
d7e954a4 | 104 | static struct sysfs_class_device *get_class_dev(char *device_name) |
ea733a2f | 105 | { |
63dde9f8 | 106 | char sysfs_path[SYSFS_PATH_MAX]; |
ea733a2f | 107 | char dev_path[SYSFS_PATH_MAX]; |
63dde9f8 GKH |
108 | int retval; |
109 | struct sysfs_class_device *class_dev = NULL; | |
110 | ||
111 | ||
112 | retval = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX); | |
113 | dbg("sysfs_path = %s", sysfs_path); | |
114 | if (retval) { | |
115 | dbg("sysfs_get_mnt_path failed"); | |
116 | goto exit; | |
117 | } | |
ea733a2f GKH |
118 | |
119 | strcpy(dev_path, sysfs_path); | |
120 | strcat(dev_path, device_name); | |
121 | ||
122 | dbg("looking at %s", dev_path); | |
123 | ||
124 | /* open up the sysfs class device for this thing... */ | |
125 | class_dev = sysfs_open_class_device(dev_path); | |
126 | if (class_dev == NULL) { | |
127 | dbg ("sysfs_open_class_device failed"); | |
63dde9f8 | 128 | goto exit; |
ea733a2f GKH |
129 | } |
130 | dbg("class_dev->name = %s", class_dev->name); | |
131 | ||
63dde9f8 | 132 | exit: |
ea733a2f GKH |
133 | return class_dev; |
134 | } | |
135 | ||
ea733a2f GKH |
136 | int udev_add_device(char *device, char *subsystem) |
137 | { | |
138 | struct sysfs_class_device *class_dev; | |
139 | struct device_attr attr; | |
ea733a2f GKH |
140 | int major; |
141 | int minor; | |
142 | char type; | |
ea733a2f GKH |
143 | int retval = -EINVAL; |
144 | ||
ea733a2f GKH |
145 | /* for now, the block layer is the only place where block devices are */ |
146 | if (strcmp(subsystem, "block") == 0) | |
147 | type = 'b'; | |
148 | else | |
149 | type = 'c'; | |
150 | ||
63dde9f8 GKH |
151 | /* sleep for a second or two to give the kernel a chance to |
152 | * create the dev file | |
153 | */ | |
154 | sleep(1); | |
155 | ||
ea733a2f GKH |
156 | class_dev = get_class_dev(device); |
157 | if (class_dev == NULL) | |
158 | goto exit; | |
159 | ||
160 | retval = namedev_name_device(class_dev, &attr); | |
161 | if (retval) | |
162 | return retval; | |
163 | ||
164 | retval = get_major_minor(class_dev, &major, &minor); | |
165 | if (retval) { | |
ca999860 | 166 | dbg("get_major_minor failed"); |
ea733a2f GKH |
167 | goto exit; |
168 | } | |
169 | ||
ca999860 | 170 | retval = udevdb_add_device(device, class_dev, attr.name, type, major, minor, attr.mode); |
ea733a2f | 171 | |
8e41d35d | 172 | if (retval != 0) |
ca999860 GKH |
173 | dbg("udevdb_add_device failed, but we are going to try to create the node anyway. " |
174 | "But remove might not work properly for this device."); | |
175 | ||
176 | sysfs_close_class_device(class_dev); | |
8e41d35d | 177 | |
ea733a2f GKH |
178 | return create_node(attr.name, type, major, minor, attr.mode); |
179 | ||
180 | exit: | |
181 | return retval; | |
182 | } | |
183 |