]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev-add.c
[PATCH] make config files, sysfs root, and udev root configurable from config variables
[thirdparty/systemd.git] / udev-add.c
CommitLineData
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
ea733a2f
GKH
37/*
38 * Right now the major/minor of a device is stored in a file called
39 * "dev" in sysfs.
40 * The number is stored as:
727d1ba5 41 * MM:mm
ea733a2f
GKH
42 * MM is the major
43 * mm is the minor
727d1ba5 44 * The value is in decimal.
ea733a2f
GKH
45 */
46static int get_major_minor(struct sysfs_class_device *class_dev, int *major, int *minor)
47{
ea256f90 48 int retval = -ENODEV;
ea733a2f
GKH
49
50 char *dev;
51
52 dev = sysfs_get_value_from_attributes(class_dev->directory->attributes, "dev");
53 if (dev == NULL)
ea256f90 54 goto exit;
ea733a2f
GKH
55
56 dbg("dev = %s", dev);
57
ea256f90
GKH
58 if (sscanf(dev, "%u:%u", major, minor) != 2)
59 goto exit;
ea733a2f
GKH
60
61 dbg("found major = %d, minor = %d", *major, *minor);
62
63 retval = 0;
ea256f90 64exit:
ea733a2f
GKH
65 return retval;
66}
67
68/*
69 * We also want to add some permissions here, and possibly some symlinks
70 */
5840bc63 71static int create_node(struct udevice *dev)
ea733a2f 72{
ea733a2f
GKH
73 char filename[255];
74 int retval = 0;
5840bc63 75
c056c514 76 strncpy(filename, udev_root, sizeof(filename));
5840bc63
GKH
77 strncat(filename, dev->name, sizeof(filename));
78
79 switch (dev->type) {
1331c889 80 case 'b':
5840bc63 81 dev->mode |= S_IFBLK;
1331c889
GKH
82 break;
83 case 'c':
84 case 'u':
5840bc63 85 dev->mode |= S_IFCHR;
1331c889
GKH
86 break;
87 case 'p':
5840bc63 88 dev->mode |= S_IFIFO;
1331c889
GKH
89 break;
90 default:
5840bc63 91 dbg("unknown node type %c\n", dev->type);
1331c889
GKH
92 return -EINVAL;
93 }
0abf54fc 94
5840bc63
GKH
95 dbg("mknod(%s, %#o, %u, %u)", filename, dev->mode, dev->major, dev->minor);
96 retval = mknod(filename, dev->mode, makedev(dev->major, dev->minor));
1331c889
GKH
97 if (retval)
98 dbg("mknod(%s, %#o, %u, %u) failed with error '%s'",
5840bc63
GKH
99 filename, dev->mode, dev->major, dev->minor, strerror(errno));
100
101 // FIXME set the ownership of the node
ea733a2f
GKH
102 return retval;
103}
104
d7e954a4 105static struct sysfs_class_device *get_class_dev(char *device_name)
ea733a2f
GKH
106{
107 char dev_path[SYSFS_PATH_MAX];
63dde9f8
GKH
108 struct sysfs_class_device *class_dev = NULL;
109
ea733a2f
GKH
110 strcpy(dev_path, sysfs_path);
111 strcat(dev_path, device_name);
112
113 dbg("looking at %s", dev_path);
114
115 /* open up the sysfs class device for this thing... */
116 class_dev = sysfs_open_class_device(dev_path);
117 if (class_dev == NULL) {
118 dbg ("sysfs_open_class_device failed");
63dde9f8 119 goto exit;
ea733a2f
GKH
120 }
121 dbg("class_dev->name = %s", class_dev->name);
122
63dde9f8 123exit:
ea733a2f
GKH
124 return class_dev;
125}
126
29fd7e67
GKH
127/* wait for the "dev" file to show up in the directory in sysfs.
128 * If it doesn't happen in about 10 seconds, give up.
129 */
130#define SECONDS_TO_WAIT_FOR_DEV 10
5840bc63 131int sleep_for_dev(char *path)
29fd7e67
GKH
132{
133 char filename[SYSFS_PATH_MAX + 6];
134 struct stat buf;
135 int loop = 0;
136 int retval = -ENODEV;
137
138 strcpy(filename, sysfs_path);
5840bc63 139 strcat(filename, path);
29fd7e67
GKH
140 strcat(filename, "/dev");
141
142 while (loop < SECONDS_TO_WAIT_FOR_DEV) {
143 dbg("looking for %s", filename);
144 retval = stat(filename, &buf);
145 if (retval == 0) {
146 retval = 0;
147 goto exit;
148 }
149
150 /* sleep for a second or two to give the kernel a chance to
151 * create the dev file */
152 sleep(1);
153 }
154 retval = -ENODEV;
155exit:
156 return retval;
157}
158
5840bc63 159int udev_add_device(char *path, char *subsystem)
ea733a2f
GKH
160{
161 struct sysfs_class_device *class_dev;
5840bc63 162 struct udevice dev;
ea733a2f 163 struct device_attr attr;
ea733a2f
GKH
164 int retval = -EINVAL;
165
ea733a2f
GKH
166 /* for now, the block layer is the only place where block devices are */
167 if (strcmp(subsystem, "block") == 0)
5840bc63 168 dev.type = 'b';
ea733a2f 169 else
5840bc63 170 dev.type = 'c';
ea733a2f 171
5840bc63 172 retval = sleep_for_dev(path);
29fd7e67
GKH
173 if (retval)
174 goto exit;
63dde9f8 175
5840bc63 176 class_dev = get_class_dev(path);
ea733a2f
GKH
177 if (class_dev == NULL)
178 goto exit;
179
180 retval = namedev_name_device(class_dev, &attr);
181 if (retval)
182 return retval;
183
5840bc63 184 retval = get_major_minor(class_dev, &dev.major, &dev.minor);
ea733a2f 185 if (retval) {
ca999860 186 dbg("get_major_minor failed");
ea733a2f
GKH
187 goto exit;
188 }
189
5840bc63
GKH
190 strcpy(dev.name, attr.name);
191 strcpy(dev.owner, attr.owner);
192 strcpy(dev.group, attr.group);
193 dev.mode = attr.mode;
194
195 retval = udevdb_add_dev(path, &dev);
8e41d35d 196 if (retval != 0)
5840bc63 197 dbg("udevdb_add_dev failed, but we are going to try to create the node anyway. "
ca999860
GKH
198 "But remove might not work properly for this device.");
199
200 sysfs_close_class_device(class_dev);
8e41d35d 201
5840bc63
GKH
202 dbg("name = %s", dev.name);
203 retval = create_node(&dev);
ea733a2f
GKH
204
205exit:
206 return retval;
207}
208