]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev_node.c
fix typo in error message
[thirdparty/systemd.git] / udev_node.c
CommitLineData
ea733a2f 1/*
a4d5ca64 2 * udev-node.c - device node handling
ea733a2f 3 *
ea733a2f 4 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
e8d569b4 5 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
ea733a2f
GKH
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
1aa1e248 25#include <stddef.h>
ea733a2f
GKH
26#include <fcntl.h>
27#include <unistd.h>
28#include <errno.h>
67f69ae1 29#include <grp.h>
32ff5bca 30#include <sys/stat.h>
10950dfe 31#include <sys/types.h>
ea733a2f
GKH
32
33#include "udev.h"
e5e322bc 34#include "udev_rules.h"
fbda4a34 35#include "udev_selinux.h"
9825617b 36
ea733a2f 37
a4d5ca64 38int udev_node_mknod(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid)
50e5de03 39{
49747bdc
KS
40 struct stat stats;
41 int retval = 0;
42
1aa1e248 43 if (major(devt) != 0 && strcmp(udev->dev->subsystem, "block") == 0)
57663b36 44 mode |= S_IFBLK;
1aa1e248 45 else
57663b36 46 mode |= S_IFCHR;
57663b36 47
49747bdc
KS
48 if (stat(file, &stats) != 0)
49 goto create;
50
1aa1e248 51 /* preserve node with already correct numbers, to prevent changing the inode number */
57663b36 52 if ((stats.st_mode & S_IFMT) == (mode & S_IFMT) && (stats.st_rdev == devt)) {
e688ad2d 53 info("preserve file '%s', because it has correct dev_t", file);
1aa1e248 54 selinux_setfilecon(file, udev->dev->kernel_name, stats.st_mode);
49747bdc
KS
55 goto perms;
56 }
57
58 if (unlink(file) != 0)
df4e89bf 59 err("unlink(%s) failed: %s", file, strerror(errno));
49747bdc
KS
60 else
61 dbg("already present file '%s' unlinked", file);
50e5de03 62
49747bdc 63create:
1aa1e248 64 selinux_setfscreatecon(file, udev->dev->kernel_name, mode);
7e720bd4 65 retval = mknod(file, mode, devt);
4d772639 66 selinux_resetfscreatecon();
50e5de03 67 if (retval != 0) {
ff3e4bed 68 err("mknod(%s, %#o, %u, %u) failed: %s",
7e720bd4 69 file, mode, major(devt), minor(devt), strerror(errno));
bbbe503e 70 goto exit;
50e5de03
KS
71 }
72
49747bdc
KS
73perms:
74 dbg("chmod(%s, %#o)", file, mode);
75 if (chmod(file, mode) != 0) {
df4e89bf 76 err("chmod(%s, %#o) failed: %s", file, mode, strerror(errno));
bbbe503e 77 goto exit;
50e5de03
KS
78 }
79
80 if (uid != 0 || gid != 0) {
49747bdc
KS
81 dbg("chown(%s, %u, %u)", file, uid, gid);
82 if (chown(file, uid, gid) != 0) {
df4e89bf 83 err("chown(%s, %u, %u) failed: %s",
49747bdc 84 file, uid, gid, strerror(errno));
bbbe503e 85 goto exit;
50e5de03
KS
86 }
87 }
88
bbbe503e
KS
89exit:
90 return retval;
50e5de03
KS
91}
92
a4d5ca64 93int udev_node_add(struct udevice *udev)
97853b4f 94{
63f61c5c 95 char filename[PATH_SIZE];
e48fc108 96 struct name_entry *name_loop;
783272f0
KS
97 uid_t uid;
98 gid_t gid;
3d150dfb 99 int tail;
e48fc108 100 int i;
a4d5ca64
KS
101 int retval = 0;
102
103 selinux_init();
3d150dfb 104
63f61c5c
KS
105 snprintf(filename, sizeof(filename), "%s/%s", udev_root, udev->name);
106 filename[sizeof(filename)-1] = '\0';
5840bc63 107
3d150dfb 108 /* create parent directories if needed */
6a24dc74 109 if (strchr(udev->name, '/'))
3d150dfb 110 create_path(filename);
218eae87 111
783272f0
KS
112 if (strcmp(udev->owner, "root") == 0)
113 uid = 0;
114 else {
c19a6b30 115 char *endptr;
783272f0 116 unsigned long id;
6d564166 117
783272f0 118 id = strtoul(udev->owner, &endptr, 10);
765cbd97 119 if (endptr[0] == '\0')
c19a6b30 120 uid = (uid_t) id;
57e1a277
KS
121 else
122 uid = lookup_user(udev->owner);
c19a6b30
KS
123 }
124
783272f0
KS
125 if (strcmp(udev->group, "root") == 0)
126 gid = 0;
127 else {
c19a6b30 128 char *endptr;
783272f0 129 unsigned long id;
6d564166 130
783272f0 131 id = strtoul(udev->group, &endptr, 10);
765cbd97 132 if (endptr[0] == '\0')
c19a6b30 133 gid = (gid_t) id;
57e1a277 134 else
68c2c0b5 135 gid = lookup_group(udev->group);
c19a6b30
KS
136 }
137
ad27f5b3
KS
138 info("creating device node '%s', major = '%d', minor = '%d', " "mode = '%#o', uid = '%d', gid = '%d'",
139 filename, major(udev->devt), minor(udev->devt), udev->mode, uid, gid);
140
141 if (!udev->test_run)
a4d5ca64
KS
142 if (udev_node_mknod(udev, filename, udev->devt, udev->mode, uid, gid) != 0) {
143 retval = -1;
144 goto exit;
145 }
ad27f5b3
KS
146
147 setenv("DEVNAME", filename, 1);
50e5de03 148
bbbe503e 149 /* create all_partitions if requested */
fd9efc00 150 if (udev->partitions) {
fb6e4c28 151 char partitionname[PATH_SIZE];
1aa1e248 152 char *attr;
6d564166
KS
153 int range;
154
155 /* take the maximum registered minor range */
1aa1e248 156 attr = sysfs_attr_get_value(udev->dev->devpath, "range");
6d564166 157 if (attr) {
1aa1e248 158 range = atoi(attr);
6d564166
KS
159 if (range > 1)
160 udev->partitions = range-1;
161 }
7a947ce5
KS
162 info("creating device partition nodes '%s[1-%i]'", filename, udev->partitions);
163 if (!udev->test_run) {
164 for (i = 1; i <= udev->partitions; i++) {
7e720bd4
KS
165 dev_t part_devt;
166
63f61c5c
KS
167 snprintf(partitionname, sizeof(partitionname), "%s%d", filename, i);
168 partitionname[sizeof(partitionname)-1] = '\0';
15139b8a 169 part_devt = makedev(major(udev->devt), minor(udev->devt) + i);
a4d5ca64 170 udev_node_mknod(udev, partitionname, part_devt, udev->mode, uid, gid);
ab2e5bd9 171 }
50e5de03 172 }
3d150dfb
KS
173 }
174
bbbe503e 175 /* create symlink(s) if requested */
fb6e4c28
KS
176 if (!list_empty(&udev->symlink_list)) {
177 char symlinks[512] = "";
178
179 list_for_each_entry(name_loop, &udev->symlink_list, node) {
fb6e4c28
KS
180 char linktarget[PATH_SIZE];
181
182 snprintf(filename, sizeof(filename), "%s/%s", udev_root, name_loop->name);
183 filename[sizeof(filename)-1] = '\0';
184
185 dbg("symlink '%s' to node '%s' requested", filename, udev->name);
186 if (!udev->test_run)
187 if (strchr(filename, '/'))
188 create_path(filename);
189
190 /* optimize relative link */
191 linktarget[0] = '\0';
192 i = 0;
193 tail = 0;
194 while (udev->name[i] && (udev->name[i] == name_loop->name[i])) {
195 if (udev->name[i] == '/')
196 tail = i+1;
197 i++;
198 }
199 while (name_loop->name[i] != '\0') {
200 if (name_loop->name[i] == '/')
201 strlcat(linktarget, "../", sizeof(linktarget));
202 i++;
203 }
3d150dfb 204
fb6e4c28
KS
205 strlcat(linktarget, &udev->name[tail], sizeof(linktarget));
206
207 info("creating symlink '%s' to '%s'", filename, linktarget);
208 if (!udev->test_run) {
209 unlink(filename);
210 selinux_setfscreatecon(filename, NULL, S_IFLNK);
a4d5ca64
KS
211 if (symlink(linktarget, filename) != 0)
212 err("symlink(%s, %s) failed: %s", linktarget, filename, strerror(errno));
fb6e4c28 213 selinux_resetfscreatecon();
fb6e4c28 214 }
3d150dfb 215
fb6e4c28
KS
216 strlcat(symlinks, filename, sizeof(symlinks));
217 strlcat(symlinks, " ", sizeof(symlinks));
4763256c 218 }
fb6e4c28
KS
219
220 remove_trailing_chars(symlinks, ' ');
221 setenv("DEVLINKS", symlinks, 1);
c19a6b30
KS
222 }
223
a4d5ca64
KS
224exit:
225 selinux_exit();
226 return retval;
ea733a2f
GKH
227}
228
a4d5ca64 229int udev_node_remove(struct udevice *udev)
f61d732a 230{
a4d5ca64
KS
231 char filename[PATH_SIZE];
232 char partitionname[PATH_SIZE];
233 struct name_entry *name_loop;
234 struct stat stats;
f61d732a 235 int retval;
a4d5ca64
KS
236 int i;
237 int num;
f61d732a 238
a4d5ca64
KS
239 if (!list_empty(&udev->symlink_list)) {
240 char symlinks[512] = "";
bbbe503e 241
a4d5ca64
KS
242 list_for_each_entry(name_loop, &udev->symlink_list, node) {
243 snprintf(filename, sizeof(filename), "%s/%s", udev_root, name_loop->name);
244 filename[sizeof(filename)-1] = '\0';
f61d732a 245
a4d5ca64
KS
246 if (stat(filename, &stats) != 0) {
247 dbg("symlink '%s' not found", filename);
248 continue;
249 }
250 if (udev->devt && stats.st_rdev != udev->devt) {
251 info("symlink '%s' points to a different device, skip removal", filename);
252 continue;
253 }
f61d732a 254
a4d5ca64
KS
255 info("removing symlink '%s'", filename);
256 unlink(filename);
f61d732a 257
a4d5ca64
KS
258 if (strchr(filename, '/'))
259 delete_path(filename);
f61d732a 260
a4d5ca64
KS
261 strlcat(symlinks, filename, sizeof(symlinks));
262 strlcat(symlinks, " ", sizeof(symlinks));
263 }
ea733a2f 264
a4d5ca64
KS
265 remove_trailing_chars(symlinks, ' ');
266 if (symlinks[0] != '\0')
267 setenv("DEVLINKS", symlinks, 1);
268 }
5d24c6ca 269
a4d5ca64
KS
270 snprintf(filename, sizeof(filename), "%s/%s", udev_root, udev->name);
271 filename[sizeof(filename)-1] = '\0';
9b28a52a 272
a4d5ca64
KS
273 if (stat(filename, &stats) != 0) {
274 dbg("device node '%s' not found", filename);
275 return -1;
276 }
277 if (udev->devt && stats.st_rdev != udev->devt) {
278 info("device node '%s' points to a different device, skip removal", filename);
279 return -1;
280 }
281
282 info("removing device node '%s'", filename);
283 retval = unlink_secure(filename);
284 if (retval)
285 return retval;
286
287 setenv("DEVNAME", filename, 1);
288
289 num = udev->partitions;
290 if (num > 0) {
291 info("removing all_partitions '%s[1-%i]'", filename, num);
292 if (num > 255) {
293 info("garbage from udev database, skip all_partitions removal");
294 return -1;
295 }
296 for (i = 1; i <= num; i++) {
297 snprintf(partitionname, sizeof(partitionname), "%s%d", filename, i);
298 partitionname[sizeof(partitionname)-1] = '\0';
299 unlink_secure(partitionname);
5d24c6ca 300 }
f61d732a 301 }
ea733a2f 302
a4d5ca64
KS
303 if (strchr(udev->name, '/'))
304 delete_path(filename);
305
ea733a2f
GKH
306 return retval;
307}