]>
git.ipfire.org Git - thirdparty/systemd.git/blob - udev_utils.c
2 * udev_lib - generic stuff used by udev
4 * Copyright (C) 2004 Kay Sievers <kay@vrfy.org>
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.
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.
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.
34 #include <sys/utsname.h>
36 #include "udev_libc_wrapper.h"
39 #include "udev_utils.h"
43 int udev_init_device(struct udevice
*udev
, const char* devpath
, const char *subsystem
, const char *action
)
47 memset(udev
, 0x00, sizeof(struct udevice
));
48 INIT_LIST_HEAD(&udev
->symlink_list
);
49 INIT_LIST_HEAD(&udev
->run_list
);
50 INIT_LIST_HEAD(&udev
->env_list
);
53 strlcpy(udev
->subsystem
, subsystem
, sizeof(udev
->subsystem
));
56 strlcpy(udev
->action
, action
, sizeof(udev
->action
));
59 strlcpy(udev
->devpath
, devpath
, sizeof(udev
->devpath
));
60 remove_trailing_char(udev
->devpath
, '/');
62 if (strncmp(udev
->devpath
, "/block/", 7) == 0)
63 udev
->type
= DEV_BLOCK
;
64 else if (strncmp(udev
->devpath
, "/class/net/", 11) == 0)
66 else if (strncmp(udev
->devpath
, "/class/", 7) == 0)
67 udev
->type
= DEV_CLASS
;
68 else if (strncmp(udev
->devpath
, "/devices/", 9) == 0)
69 udev
->type
= DEV_DEVICE
;
72 pos
= strrchr(udev
->devpath
, '/');
74 strlcpy(udev
->kernel_name
, &pos
[1], sizeof(udev
->kernel_name
));
75 dbg("kernel_name='%s'", udev
->kernel_name
);
77 /* Some block devices have '!' in their name, change that to '/' */
78 pos
= udev
->kernel_name
;
79 while (pos
[0] != '\0') {
85 /* get kernel number */
86 pos
= &udev
->kernel_name
[strlen(udev
->kernel_name
)];
87 while (isdigit(pos
[-1]))
89 strlcpy(udev
->kernel_number
, pos
, sizeof(udev
->kernel_number
));
90 dbg("kernel_number='%s'", udev
->kernel_number
);
94 if (udev
->type
== DEV_BLOCK
|| udev
->type
== DEV_CLASS
) {
96 strcpy(udev
->owner
, "root");
97 strcpy(udev
->group
, "root");
103 void udev_cleanup_device(struct udevice
*udev
)
105 struct name_entry
*name_loop
;
106 struct name_entry
*temp_loop
;
108 list_for_each_entry_safe(name_loop
, temp_loop
, &udev
->symlink_list
, node
) {
109 list_del(&name_loop
->node
);
112 list_for_each_entry_safe(name_loop
, temp_loop
, &udev
->run_list
, node
) {
113 list_del(&name_loop
->node
);
116 list_for_each_entry_safe(name_loop
, temp_loop
, &udev
->env_list
, node
) {
117 list_del(&name_loop
->node
);
122 int string_is_true(const char *str
)
124 if (strcasecmp(str
, "true") == 0)
126 if (strcasecmp(str
, "yes") == 0)
128 if (strcasecmp(str
, "1") == 0)
133 int log_priority(const char *priority
)
138 prio
= strtol(priority
, &endptr
, 10);
139 if (endptr
[0] == '\0')
141 if (strncasecmp(priority
, "err", 3) == 0)
143 if (strcasecmp(priority
, "info") == 0)
145 if (strcasecmp(priority
, "debug") == 0)
147 if (string_is_true(priority
))
153 int kernel_release_satisfactory(unsigned int version
, unsigned int patchlevel
, unsigned int sublevel
)
155 static unsigned int kversion
= 0;
156 static unsigned int kpatchlevel
;
157 static unsigned int ksublevel
;
161 if (uname(&uts
) != 0)
164 if (sscanf (uts
.release
, "%u.%u.%u", &kversion
, &kpatchlevel
, &ksublevel
) != 3) {
170 if (kversion
>= version
&& kpatchlevel
>= patchlevel
&& ksublevel
>= sublevel
)
176 int create_path(const char *path
)
183 pos
= strrchr(p
, '/');
184 if (pos
== p
|| pos
== NULL
)
187 while (pos
[-1] == '/')
192 dbg("stat '%s'\n", p
);
193 if (stat (p
, &stats
) == 0 && (stats
.st_mode
& S_IFMT
) == S_IFDIR
)
196 if (create_path (p
) != 0)
199 dbg("mkdir '%s'\n", p
);
200 return mkdir(p
, 0755);
203 /* Reset permissions on the device node, before unlinking it to make sure,
204 * that permisions of possible hard links will be removed too.
206 int unlink_secure(const char *filename
)
210 retval
= chown(filename
, 0, 0);
212 dbg("chown(%s, 0, 0) failed with error '%s'", filename
, strerror(errno
));
214 retval
= chmod(filename
, 0000);
216 dbg("chmod(%s, 0000) failed with error '%s'", filename
, strerror(errno
));
218 retval
= unlink(filename
);
223 dbg("unlink(%s) failed with error '%s'", filename
, strerror(errno
));
228 int file_map(const char *filename
, char **buf
, size_t *bufsize
)
233 fd
= open(filename
, O_RDONLY
);
238 if (fstat(fd
, &stats
) < 0) {
243 *buf
= mmap(NULL
, stats
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
244 if (*buf
== MAP_FAILED
) {
248 *bufsize
= stats
.st_size
;
255 void file_unmap(void *buf
, size_t bufsize
)
257 munmap(buf
, bufsize
);
260 /* return number of chars until the next newline, skip escaped newline */
261 size_t buf_get_line(const char *buf
, size_t buflen
, size_t cur
)
266 for (count
= cur
; count
< buflen
; count
++) {
267 if (!escape
&& buf
[count
] == '\n')
270 if (buf
[count
] == '\\')
279 void replace_untrusted_chars(char *string
)
283 for (len
= 0; string
[len
] != '\0'; len
++) {
284 if (strchr(";,~\\()\'", string
[len
])) {
285 info("replace '%c' in '%s'", string
[len
], string
);
291 void remove_trailing_char(char *path
, char c
)
296 while (len
> 0 && path
[len
-1] == c
)
300 int name_list_add(struct list_head
*name_list
, const char *name
, int sort
)
302 struct name_entry
*loop_name
;
303 struct name_entry
*new_name
;
305 list_for_each_entry(loop_name
, name_list
, node
) {
307 if (strcmp(loop_name
->name
, name
) == 0) {
308 dbg("'%s' is already in the list", name
);
314 list_for_each_entry(loop_name
, name_list
, node
) {
315 if (sort
&& strcmp(loop_name
->name
, name
) > 0)
319 new_name
= malloc(sizeof(struct name_entry
));
320 if (new_name
== NULL
) {
325 strlcpy(new_name
->name
, name
, sizeof(new_name
->name
));
326 dbg("adding '%s'", new_name
->name
);
327 list_add_tail(&new_name
->node
, &loop_name
->node
);
332 int name_list_key_add(struct list_head
*name_list
, const char *key
, const char *value
)
334 struct name_entry
*loop_name
;
335 struct name_entry
*new_name
;
337 list_for_each_entry(loop_name
, name_list
, node
) {
338 if (strncmp(loop_name
->name
, key
, strlen(key
)) == 0) {
339 dbg("key already present '%s', replace it", loop_name
->name
);
340 snprintf(loop_name
->name
, sizeof(loop_name
->name
), "%s=%s", key
, value
);
341 loop_name
->name
[sizeof(loop_name
->name
)-1] = '\0';
346 new_name
= malloc(sizeof(struct name_entry
));
347 if (new_name
== NULL
) {
352 snprintf(new_name
->name
, sizeof(new_name
->name
), "%s=%s", key
, value
);
353 new_name
->name
[sizeof(new_name
->name
)-1] = '\0';
354 dbg("adding '%s'", new_name
->name
);
355 list_add_tail(&new_name
->node
, &loop_name
->node
);
360 /* calls function for every file found in specified directory */
361 int add_matching_files(struct list_head
*name_list
, const char *dirname
, const char *suffix
)
366 char filename
[PATH_SIZE
];
368 dbg("open directory '%s'", dirname
);
369 dir
= opendir(dirname
);
371 dbg("unable to open '%s'", dirname
);
377 if (ent
== NULL
|| ent
->d_name
[0] == '\0')
380 if ((ent
->d_name
[0] == '.') || (ent
->d_name
[0] == COMMENT_CHARACTER
))
383 /* look for file matching with specified suffix */
384 ext
= strrchr(ent
->d_name
, '.');
388 if (strcmp(ext
, suffix
) != 0)
391 dbg("put file '%s/%s' in list", dirname
, ent
->d_name
);
393 snprintf(filename
, sizeof(filename
), "%s/%s", dirname
, ent
->d_name
);
394 filename
[sizeof(filename
)-1] = '\0';
395 name_list_add(name_list
, filename
, 1);
402 int execute_program(const char *command
, const char *subsystem
,
403 char *result
, size_t ressize
, size_t *reslen
)
412 char *argv
[(sizeof(arg
) / 2) + 1];
417 strlcpy(arg
, command
, sizeof(arg
));
419 if (strchr(arg
, ' ')) {
421 while (pos
!= NULL
) {
422 if (pos
[0] == '\'') {
423 /* don't separate if in apostrophes */
425 argv
[i
] = strsep(&pos
, "\'");
426 while (pos
&& pos
[0] == ' ')
429 argv
[i
] = strsep(&pos
, " ");
431 dbg("arg[%i] '%s'", i
, argv
[i
]);
435 dbg("execute '%s' with parsed arguments", arg
);
438 argv
[1] = (char *) subsystem
;
440 dbg("execute '%s' with subsystem '%s' argument", arg
, argv
[1]);
444 if (pipe(pipefds
) != 0) {
453 /* child dup2 write side of pipe to STDOUT */
454 devnull
= open("/dev/null", O_RDWR
);
456 dup2(devnull
, STDIN_FILENO
);
458 dup2(devnull
, STDOUT_FILENO
);
459 dup2(devnull
, STDERR_FILENO
);
463 dup2(pipefds
[1], STDOUT_FILENO
);
465 err("exec of program failed");
468 err("fork of '%s' failed", arg
);
471 /* parent reads from pipefds[0] */
476 count
= read(pipefds
[0], result
+ len
, ressize
- len
-1);
478 err("read failed with '%s'", strerror(errno
));
487 if (len
>= ressize
-1) {
488 err("ressize %ld too short", (long)ressize
);
498 waitpid(pid
, &status
, 0);
500 if (!WIFEXITED(status
) || (WEXITSTATUS(status
) != 0)) {
501 dbg("exec program status 0x%x", status
);