]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev_utils.c
added translated (jp) version of writing udev rules file.
[thirdparty/systemd.git] / udev_utils.c
CommitLineData
c81b35c0
KS
1/*
2 * udev_lib - generic stuff used by udev
3 *
4 * Copyright (C) 2004 Kay Sievers <kay@vrfy.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21
22#include <stdlib.h>
23#include <stdio.h>
4a539daf 24#include <stddef.h>
c81b35c0
KS
25#include <unistd.h>
26#include <fcntl.h>
4a539daf 27#include <errno.h>
9f8dfa19 28#include <ctype.h>
4a539daf 29#include <dirent.h>
fb39f056 30#include <sys/wait.h>
c81b35c0
KS
31#include <sys/stat.h>
32#include <sys/mman.h>
d402af7d 33#include <sys/utsname.h>
c81b35c0 34
63f61c5c 35#include "udev_libc_wrapper.h"
c81b35c0 36#include "udev.h"
4a539daf 37#include "logging.h"
9af5bb2f 38#include "udev_utils.h"
4a539daf 39#include "list.h"
c81b35c0
KS
40
41
fb39f056 42int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action)
f61d732a 43{
9ed47a9f
KS
44 char *pos;
45
fc2aa296 46 memset(udev, 0x00, sizeof(struct udevice));
e48fc108 47 INIT_LIST_HEAD(&udev->symlink_list);
821d0ec8 48 INIT_LIST_HEAD(&udev->run_list);
8825e9e7 49
03cfa139 50 if (subsystem)
63f61c5c 51 strlcpy(udev->subsystem, subsystem, sizeof(udev->subsystem));
03cfa139 52
821d0ec8
KS
53 if (action)
54 strlcpy(udev->action, action, sizeof(udev->action));
55
9ed47a9f 56 if (devpath) {
63f61c5c 57 strlcpy(udev->devpath, devpath, sizeof(udev->devpath));
18614ab2 58 remove_trailing_char(udev->devpath, '/');
7b9b1839 59
03cfa139 60 if (strncmp(udev->devpath, "/block/", 7) == 0)
e6764498 61 udev->type = DEV_BLOCK;
03cfa139 62 else if (strncmp(udev->devpath, "/class/net/", 11) == 0)
e6764498 63 udev->type = DEV_NET;
03cfa139 64 else if (strncmp(udev->devpath, "/class/", 7) == 0)
e6764498 65 udev->type = DEV_CLASS;
03cfa139 66 else if (strncmp(udev->devpath, "/devices/", 9) == 0)
e6764498 67 udev->type = DEV_DEVICE;
03cfa139
KS
68
69 /* get kernel name */
70 pos = strrchr(udev->devpath, '/');
71 if (pos) {
63f61c5c 72 strlcpy(udev->kernel_name, &pos[1], sizeof(udev->kernel_name));
03cfa139
KS
73 dbg("kernel_name='%s'", udev->kernel_name);
74
75 /* Some block devices have '!' in their name, change that to '/' */
76 pos = udev->kernel_name;
77 while (pos[0] != '\0') {
78 if (pos[0] == '!')
79 pos[0] = '/';
80 pos++;
81 }
82
83 /* get kernel number */
84 pos = &udev->kernel_name[strlen(udev->kernel_name)];
85 while (isdigit(pos[-1]))
86 pos--;
63f61c5c 87 strlcpy(udev->kernel_number, pos, sizeof(udev->kernel_number));
03cfa139
KS
88 dbg("kernel_number='%s'", udev->kernel_number);
89 }
90 }
65ab1334 91
1bbff4f0
KS
92 if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
93 udev->mode = 0660;
94 strcpy(udev->owner, "root");
95 strcpy(udev->group, "root");
96 }
9ed47a9f 97
9ed47a9f 98 return 0;
7a947ce5
KS
99}
100
e48fc108
KS
101void udev_cleanup_device(struct udevice *udev)
102{
103 struct name_entry *name_loop;
104 struct name_entry *temp_loop;
105
106 list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) {
107 list_del(&name_loop->node);
108 free(name_loop);
109 }
110}
111
85925517 112int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel)
d402af7d 113{
85925517
MB
114 static unsigned int kversion = 0;
115 static unsigned int kpatchlevel;
116 static unsigned int ksublevel;
d402af7d
KS
117
118 if (kversion == 0) {
a4f0cc79 119 struct utsname uts;
d402af7d
KS
120 if (uname(&uts) != 0)
121 return -1;
122
123 if (sscanf (uts.release, "%u.%u.%u", &kversion, &kpatchlevel, &ksublevel) != 3) {
124 kversion = 0;
125 return -1;
126 }
127 }
128
129 if (kversion >= version && kpatchlevel >= patchlevel && ksublevel >= sublevel)
130 return 1;
131 else
132 return 0;
133}
134
2b41e68a
KS
135int create_path(const char *path)
136{
63f61c5c 137 char p[PATH_SIZE];
2b41e68a
KS
138 char *pos;
139 struct stat stats;
140
141 strcpy (p, path);
142 pos = strrchr(p, '/');
143 if (pos == p || pos == NULL)
144 return 0;
145
146 while (pos[-1] == '/')
147 pos--;
148
149 pos[0] = '\0';
150
151 dbg("stat '%s'\n", p);
152 if (stat (p, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR)
153 return 0;
154
155 if (create_path (p) != 0)
156 return -1;
157
158 dbg("mkdir '%s'\n", p);
159 return mkdir(p, 0755);
160}
161
c1ab0461 162/* Reset permissions on the device node, before unlinking it to make sure,
866bb547 163 * that permisions of possible hard links will be removed too.
c1ab0461
KS
164 */
165int unlink_secure(const char *filename)
166{
167 int retval;
168
169 retval = chown(filename, 0, 0);
170 if (retval)
171 dbg("chown(%s, 0, 0) failed with error '%s'", filename, strerror(errno));
172
173 retval = chmod(filename, 0000);
174 if (retval)
175 dbg("chmod(%s, 0000) failed with error '%s'", filename, strerror(errno));
176
177 retval = unlink(filename);
178 if (errno == ENOENT)
179 retval = 0;
180
181 if (retval)
182 dbg("unlink(%s) failed with error '%s'", filename, strerror(errno));
183
184 return retval;
185}
186
c81b35c0
KS
187int file_map(const char *filename, char **buf, size_t *bufsize)
188{
189 struct stat stats;
190 int fd;
191
192 fd = open(filename, O_RDONLY);
193 if (fd < 0) {
194 return -1;
195 }
196
197 if (fstat(fd, &stats) < 0) {
686cecf2 198 close(fd);
c81b35c0
KS
199 return -1;
200 }
201
202 *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0);
203 if (*buf == MAP_FAILED) {
686cecf2 204 close(fd);
c81b35c0
KS
205 return -1;
206 }
207 *bufsize = stats.st_size;
208
209 close(fd);
210
211 return 0;
212}
213
214void file_unmap(char *buf, size_t bufsize)
215{
216 munmap(buf, bufsize);
217}
218
9f8dfa19
KS
219/* return number of chars until the next newline, skip escaped newline */
220size_t buf_get_line(const char *buf, size_t buflen, size_t cur)
c81b35c0 221{
9f8dfa19
KS
222 int escape = 0;
223 size_t count;
224
225 for (count = cur; count < buflen; count++) {
226 if (!escape && buf[count] == '\n')
227 break;
c81b35c0 228
9f8dfa19
KS
229 if (buf[count] == '\\')
230 escape = 1;
231 else
232 escape = 0;
233 }
c81b35c0
KS
234
235 return count - cur;
236}
237
18614ab2
KS
238void replace_untrusted_chars(char *string)
239{
240 size_t len;
241
242 for (len = 0; string[len] != '\0'; len++) {
243 if (strchr(";,~\\()\'", string[len])) {
244 info("replace '%c' in '%s'", string[len], string);
245 string[len] = '_';
246 }
247 }
248}
249
250void remove_trailing_char(char *path, char c)
aef6bb13 251{
e39515ac 252 size_t len;
aef6bb13
KS
253
254 len = strlen(path);
18614ab2 255 while (len > 0 && path[len-1] == c)
e39515ac 256 path[--len] = '\0';
aef6bb13
KS
257}
258
f0308095 259int name_list_add(struct list_head *name_list, const char *name, int sort)
4a539daf 260{
9ed47a9f
KS
261 struct name_entry *loop_name;
262 struct name_entry *new_name;
263
264 list_for_each_entry(loop_name, name_list, node) {
265 /* avoid doubles */
266 if (strcmp(loop_name->name, name) == 0) {
267 dbg("'%s' is already in the list", name);
268 return 0;
4a539daf 269 }
9ed47a9f
KS
270 if (sort && strcmp(loop_name->name, name) > 0)
271 break;
4a539daf
KS
272 }
273
9ed47a9f
KS
274 new_name = malloc(sizeof(struct name_entry));
275 if (new_name == NULL) {
4a539daf
KS
276 dbg("error malloc");
277 return -ENOMEM;
278 }
279
63f61c5c 280 strlcpy(new_name->name, name, sizeof(new_name->name));
9ed47a9f 281 list_add_tail(&new_name->node, &loop_name->node);
f0308095 282
4a539daf
KS
283 return 0;
284}
285
aef6bb13 286/* calls function for every file found in specified directory */
67747e1d 287int add_matching_files(struct list_head *name_list, const char *dirname, const char *suffix)
4a539daf
KS
288{
289 struct dirent *ent;
290 DIR *dir;
291 char *ext;
67747e1d 292 char filename[PATH_SIZE];
4a539daf
KS
293
294 dbg("open directory '%s'", dirname);
295 dir = opendir(dirname);
296 if (dir == NULL) {
297 dbg("unable to open '%s'", dirname);
298 return -1;
299 }
300
301 while (1) {
302 ent = readdir(dir);
303 if (ent == NULL || ent->d_name[0] == '\0')
304 break;
305
306 if ((ent->d_name[0] == '.') || (ent->d_name[0] == COMMENT_CHARACTER))
307 continue;
308
67747e1d 309 /* look for file matching with specified suffix */
4a539daf
KS
310 ext = strrchr(ent->d_name, '.');
311 if (ext == NULL)
312 continue;
313
314 if (strcmp(ext, suffix) != 0)
315 continue;
316
317 dbg("put file '%s/%s' in list", dirname, ent->d_name);
4a539daf 318
67747e1d 319 snprintf(filename, sizeof(filename), "%s/%s", dirname, ent->d_name);
63f61c5c 320 filename[sizeof(filename)-1] = '\0';
67747e1d 321 name_list_add(name_list, filename, 1);
4a539daf
KS
322 }
323
324 closedir(dir);
325 return 0;
326}
fb39f056
KS
327
328int execute_command(const char *command, const char *subsystem)
329{
330 int retval;
331 pid_t pid;
332 char arg[PATH_SIZE];
333 char *argv[(PATH_SIZE / 2) + 1];
334 char *pos;
335 int devnull;
336 int i;
337
338 strlcpy(arg, command, sizeof(arg));
339 i = 0;
340 if (strchr(arg, ' ')) {
341 pos = arg;
342 while (pos != NULL) {
343 if (pos[0] == '\'') {
344 /* don't separate if in apostrophes */
345 pos++;
346 argv[i] = strsep(&pos, "\'");
347 while (pos && pos[0] == ' ')
348 pos++;
349 } else {
350 argv[i] = strsep(&pos, " ");
351 }
352 dbg("arg[%i] '%s'", i, argv[i]);
353 i++;
354 }
355 argv[i] = NULL;
356 dbg("execute '%s' with parsed arguments", arg);
357 } else {
358 argv[0] = arg;
359 argv[1] = (char *) subsystem;
360 argv[2] = NULL;
361 dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]);
362 }
363
364 pid = fork();
365 switch (pid) {
366 case 0:
367 /* child */
368 devnull = open("/dev/null", O_RDWR);
369 if (devnull >= 0) {
370 dup2(devnull, STDIN_FILENO);
371 dup2(devnull, STDOUT_FILENO);
372 dup2(devnull, STDERR_FILENO);
373 close(devnull);
374 }
375 retval = execv(arg, argv);
376 err("exec of child failed");
377 _exit(1);
378 case -1:
379 dbg("fork of child failed");
380 break;
381 return -1;
382 default:
383 waitpid(pid, NULL, 0);
384 }
385
386 return 0;
387}