/*
- * udevd.c - event listener and serializer
- *
* Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
* Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
*
- *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "udev.h"
#include "udev_rules.h"
#include "udevd.h"
+#include "udev_selinux.h"
static struct udev_rules rules;
static int udevd_sock = -1;
{
char filename[PATH_SIZE];
char filename_failed[PATH_SIZE];
- char target[PATH_SIZE];
size_t start, end, i;
struct udevd_uevent_msg *loop_msg;
+ int fd;
/* add location of queue files */
strlcpy(filename, udev_root, sizeof(filename));
case EVENT_QUEUED:
unlink(filename_failed);
delete_path(filename_failed);
-
- strlcpy(target, sysfs_path, sizeof(target));
- strlcat(target, msg->devpath, sizeof(target));
create_path(filename);
- symlink(target, filename);
+ fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
+ if (fd > 0)
+ close(fd);
return;
case EVENT_FINISHED:
case EVENT_FAILED:
int bufpos;
int i;
struct udevd_uevent_msg *msg;
- int major = 0;
- int minor = 0;
+ char *physdevdriver_key = NULL;
+ int maj = 0;
+ int min = 0;
msg = malloc(sizeof(struct udevd_uevent_msg) + buf_size);
if (msg == NULL)
msg->seqnum = strtoull(&key[7], NULL, 10);
else if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
msg->physdevpath = &key[12];
+ else if (strncmp(key, "PHYSDEVDRIVER=", 14) == 0)
+ physdevdriver_key = key;
else if (strncmp(key, "MAJOR=", 6) == 0)
- major = strtoull(&key[6], NULL, 10);
+ maj = strtoull(&key[6], NULL, 10);
else if (strncmp(key, "MINOR=", 6) == 0)
- minor = strtoull(&key[6], NULL, 10);
+ min = strtoull(&key[6], NULL, 10);
else if (strncmp(key, "TIMEOUT=", 8) == 0)
msg->timeout = strtoull(&key[8], NULL, 10);
}
- msg->devt = makedev(major, minor);
+ msg->devt = makedev(maj, min);
msg->envp[i++] = "UDEVD_EVENT=1";
+
+ if (msg->driver == NULL && msg->physdevpath == NULL && physdevdriver_key != NULL) {
+ /* for older kernels DRIVER is empty for a bus device, export PHYSDEVDRIVER as DRIVER */
+ msg->envp[i++] = &physdevdriver_key[7];
+ msg->driver = &physdevdriver_key[14];
+ }
+
msg->envp[i] = NULL;
if (msg->devpath == NULL || msg->action == NULL) {
static int init_udevd_socket(void)
{
struct sockaddr_un saddr;
- const int buffersize = 16 * 1024 * 1024;
socklen_t addrlen;
const int feature_on = 1;
int retval;
return -1;
}
- /* set receive buffersize */
- setsockopt(udevd_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
-
/* the bind takes care of ensuring only one copy running */
retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen);
if (retval < 0) {
const char *value;
int daemonize = 0;
int i;
- int rc = 0;
+ int rc = 1;
int maxfd;
- /* redirect std fd's, if the kernel forks us, we don't have them at all */
- fd = open("/dev/null", O_RDWR);
- if (fd >= 0) {
- if (fd != STDIN_FILENO)
- dup2(fd, STDIN_FILENO);
- if (fd != STDOUT_FILENO)
- dup2(fd, STDOUT_FILENO);
- if (fd != STDERR_FILENO)
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- close(fd);
- }
-
logging_init("udevd");
- if (fd < 0)
- err("fatal, could not open /dev/null: %s", strerror(errno));
-
udev_config_init();
+ selinux_init();
dbg("version %s", UDEV_VERSION);
- if (getuid() != 0) {
- err("need to be root, exit");
- goto exit;
- }
-
/* parse commandline options */
for (i = 1 ; i < argc; i++) {
char *arg = argv[i];
- if (strcmp(arg, "--daemon") == 0 || strcmp(arg, "-d") == 0) {
- info("will daemonize");
+ if (strcmp(arg, "--daemon") == 0 || strcmp(arg, "-d") == 0)
daemonize = 1;
+ else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
+ printf("Usage: udevd [--help] [--daemon]\n");
+ goto exit;
+ } else {
+ fprintf(stderr, "unrecognized option '%s'\n", arg);
+ err("unrecognized option '%s'\n", arg);
}
}
+ if (getuid() != 0) {
+ fprintf(stderr, "root privileges required\n");
+ err("root privileges required");
+ goto exit;
+ }
+
/* init sockets to receive events */
if (init_udevd_socket() < 0) {
if (errno == EADDRINUSE) {
- err("another udevd running, exit");
+ fprintf(stderr, "another udev daemon already running\n");
+ err("another udev daemon already running");
rc = 1;
} else {
- err("error initializing udevd socket: %s", strerror(errno));
+ fprintf(stderr, "error initializing udevd socket\n");
+ err("error initializing udevd socket");
rc = 2;
}
goto exit;
}
if (init_uevent_netlink_sock() < 0) {
- err("uevent socket not available");
+ fprintf(stderr, "error initializing netlink socket\n");
+ err("error initializing netlink socket");
rc = 3;
goto exit;
}
- /* parse the rules and keep it in memory */
+ /* parse the rules and keep them in memory */
sysfs_init();
udev_rules_init(&rules, 1);
goto exit;
default:
dbg("child [%u] running, parent exits", pid);
+ rc = 0;
goto exit;
}
}
+ /* redirect std fd's */
+ fd = open("/dev/null", O_RDWR);
+ if (fd >= 0) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO)
+ close(fd);
+ } else
+ err("error opening /dev/null: %s", strerror(errno));
+
/* set scheduling priority for the daemon */
setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
}
}
- /* rules changed, set by inotify or a signal*/
+ /* rules changed, set by inotify or a HUP signal */
if (reload_config) {
reload_config = 0;
udev_rules_cleanup(&rules);
msg_queue_manager();
}
}
+ rc = 0;
exit:
udev_rules_cleanup(&rules);