]>
Commit | Line | Data |
---|---|---|
c81b35c0 | 1 | /* |
44b49d37 | 2 | * libudev - interface to udev device information |
c81b35c0 | 3 | * |
fc206fbe | 4 | * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org> |
c81b35c0 | 5 | * |
44b49d37 KS |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
c81b35c0 KS |
10 | */ |
11 | ||
c81b35c0 KS |
12 | #include <stdlib.h> |
13 | #include <stdio.h> | |
4a539daf | 14 | #include <stddef.h> |
c81b35c0 | 15 | #include <unistd.h> |
01618658 | 16 | #include <string.h> |
c81b35c0 | 17 | #include <fcntl.h> |
4a539daf | 18 | #include <errno.h> |
9f8dfa19 | 19 | #include <ctype.h> |
3a020a85 KS |
20 | #include <pwd.h> |
21 | #include <grp.h> | |
257bb4cd | 22 | #include <sys/param.h> |
c81b35c0 | 23 | |
44b49d37 KS |
24 | #include "libudev.h" |
25 | #include "libudev-private.h" | |
c81b35c0 | 26 | |
51f43b53 | 27 | static int create_path(struct udev *udev, const char *path, bool selinux) |
4a539daf | 28 | { |
912541b0 KS |
29 | char p[UTIL_PATH_SIZE]; |
30 | char *pos; | |
31 | struct stat stats; | |
32 | int err; | |
33 | ||
34 | util_strscpy(p, sizeof(p), path); | |
35 | pos = strrchr(p, '/'); | |
36 | if (pos == NULL) | |
37 | return 0; | |
38 | while (pos != p && pos[-1] == '/') | |
39 | pos--; | |
40 | if (pos == p) | |
41 | return 0; | |
42 | pos[0] = '\0'; | |
43 | ||
912541b0 KS |
44 | if (stat(p, &stats) == 0) { |
45 | if ((stats.st_mode & S_IFMT) == S_IFDIR) | |
46 | return 0; | |
47 | else | |
48 | return -ENOTDIR; | |
49 | } | |
50 | ||
51 | err = util_create_path(udev, p); | |
52 | if (err != 0) | |
53 | return err; | |
54 | ||
912541b0 KS |
55 | if (selinux) |
56 | udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755); | |
57 | err = mkdir(p, 0755); | |
58 | if (err != 0) { | |
59 | err = -errno; | |
60 | if (err == -EEXIST && stat(p, &stats) == 0) { | |
61 | if ((stats.st_mode & S_IFMT) == S_IFDIR) | |
62 | err = 0; | |
63 | else | |
64 | err = -ENOTDIR; | |
65 | } | |
66 | } | |
67 | if (selinux) | |
68 | udev_selinux_resetfscreatecon(udev); | |
69 | return err; | |
a390e6f7 | 70 | } |
4a539daf | 71 | |
51f43b53 KS |
72 | int util_create_path(struct udev *udev, const char *path) |
73 | { | |
912541b0 | 74 | return create_path(udev, path, false); |
51f43b53 KS |
75 | } |
76 | ||
77 | int util_create_path_selinux(struct udev *udev, const char *path) | |
78 | { | |
912541b0 | 79 | return create_path(udev, path, true); |
51f43b53 KS |
80 | } |
81 | ||
54808d77 | 82 | int util_delete_path(struct udev *udev, const char *path) |
a390e6f7 | 83 | { |
912541b0 KS |
84 | char p[UTIL_PATH_SIZE]; |
85 | char *pos; | |
86 | int err = 0; | |
87 | ||
88 | if (path[0] == '/') | |
89 | while(path[1] == '/') | |
90 | path++; | |
91 | util_strscpy(p, sizeof(p), path); | |
92 | pos = strrchr(p, '/'); | |
93 | if (pos == p || pos == NULL) | |
94 | return 0; | |
95 | ||
96 | for (;;) { | |
97 | *pos = '\0'; | |
98 | pos = strrchr(p, '/'); | |
99 | ||
100 | /* don't remove the last one */ | |
101 | if ((pos == p) || (pos == NULL)) | |
102 | break; | |
103 | ||
104 | err = rmdir(p); | |
105 | if (err < 0) { | |
106 | if (errno == ENOENT) | |
107 | err = 0; | |
108 | break; | |
109 | } | |
110 | } | |
111 | return err; | |
b8476286 KS |
112 | } |
113 | ||
54808d77 | 114 | uid_t util_lookup_user(struct udev *udev, const char *user) |
3a020a85 | 115 | { |
912541b0 | 116 | char *endptr; |
912541b0 KS |
117 | struct passwd pwbuf; |
118 | struct passwd *pw; | |
119 | uid_t uid; | |
fc863dea KS |
120 | size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); |
121 | char *buf = alloca(buflen); | |
912541b0 KS |
122 | |
123 | if (strcmp(user, "root") == 0) | |
124 | return 0; | |
125 | uid = strtoul(user, &endptr, 10); | |
126 | if (endptr[0] == '\0') | |
127 | return uid; | |
128 | ||
129 | errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw); | |
130 | if (pw != NULL) | |
131 | return pw->pw_uid; | |
132 | if (errno == 0 || errno == ENOENT || errno == ESRCH) | |
133 | err(udev, "specified user '%s' unknown\n", user); | |
134 | else | |
135 | err(udev, "error resolving user '%s': %m\n", user); | |
136 | return 0; | |
90024521 | 137 | } |
3a020a85 | 138 | |
37ed4f56 | 139 | gid_t util_lookup_group(struct udev *udev, const char *group) |
90024521 | 140 | { |
912541b0 | 141 | char *endptr; |
912541b0 KS |
142 | struct group grbuf; |
143 | struct group *gr; | |
144 | gid_t gid = 0; | |
fc863dea | 145 | size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); |
b49d9b50 | 146 | char *buf = NULL; |
912541b0 KS |
147 | |
148 | if (strcmp(group, "root") == 0) | |
149 | return 0; | |
150 | gid = strtoul(group, &endptr, 10); | |
151 | if (endptr[0] == '\0') | |
152 | return gid; | |
912541b0 KS |
153 | gid = 0; |
154 | for (;;) { | |
155 | char *newbuf; | |
156 | ||
157 | newbuf = realloc(buf, buflen); | |
158 | if (!newbuf) | |
159 | break; | |
160 | buf = newbuf; | |
161 | errno = getgrnam_r(group, &grbuf, buf, buflen, &gr); | |
162 | if (gr != NULL) { | |
163 | gid = gr->gr_gid; | |
164 | } else if (errno == ERANGE) { | |
165 | buflen *= 2; | |
166 | continue; | |
167 | } else if (errno == 0 || errno == ENOENT || errno == ESRCH) { | |
168 | err(udev, "specified group '%s' unknown\n", group); | |
169 | } else { | |
170 | err(udev, "error resolving group '%s': %m\n", group); | |
171 | } | |
172 | break; | |
173 | } | |
174 | free(buf); | |
175 | return gid; | |
90024521 | 176 | } |
d0db192f | 177 | |
14f40256 KS |
178 | /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */ |
179 | int util_resolve_subsys_kernel(struct udev *udev, const char *string, | |
912541b0 | 180 | char *result, size_t maxsize, int read_value) |
14f40256 | 181 | { |
912541b0 KS |
182 | char temp[UTIL_PATH_SIZE]; |
183 | char *subsys; | |
184 | char *sysname; | |
185 | struct udev_device *dev; | |
186 | char *attr; | |
187 | ||
188 | if (string[0] != '[') | |
189 | return -1; | |
190 | ||
191 | util_strscpy(temp, sizeof(temp), string); | |
192 | ||
193 | subsys = &temp[1]; | |
194 | ||
195 | sysname = strchr(subsys, '/'); | |
196 | if (sysname == NULL) | |
197 | return -1; | |
198 | sysname[0] = '\0'; | |
199 | sysname = &sysname[1]; | |
200 | ||
201 | attr = strchr(sysname, ']'); | |
202 | if (attr == NULL) | |
203 | return -1; | |
204 | attr[0] = '\0'; | |
205 | attr = &attr[1]; | |
206 | if (attr[0] == '/') | |
207 | attr = &attr[1]; | |
208 | if (attr[0] == '\0') | |
209 | attr = NULL; | |
210 | ||
211 | if (read_value && attr == NULL) | |
212 | return -1; | |
213 | ||
214 | dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); | |
215 | if (dev == NULL) | |
216 | return -1; | |
217 | ||
218 | if (read_value) { | |
219 | const char *val; | |
220 | ||
221 | val = udev_device_get_sysattr_value(dev, attr); | |
222 | if (val != NULL) | |
223 | util_strscpy(result, maxsize, val); | |
224 | else | |
225 | result[0] = '\0'; | |
baa30fbc | 226 | dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); |
912541b0 KS |
227 | } else { |
228 | size_t l; | |
229 | char *s; | |
230 | ||
231 | s = result; | |
232 | l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); | |
233 | if (attr != NULL) | |
234 | util_strpcpyl(&s, l, "/", attr, NULL); | |
baa30fbc | 235 | dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); |
912541b0 KS |
236 | } |
237 | udev_device_unref(dev); | |
238 | return 0; | |
14f40256 | 239 | } |