#include "udev.h"
#include "udev_rules.h"
#include "udevd.h"
+#include "udev_selinux.h"
static struct udev_rules rules;
static int udevd_sock = -1;
if (udev == NULL)
return -1;
strlcpy(udev->action, msg->action, sizeof(udev->action));
- sysfs_device_set_values(udev->dev, msg->devpath, msg->subsystem);
+ sysfs_device_set_values(udev->dev, msg->devpath, msg->subsystem, msg->driver);
udev->devt = msg->devt;
retval = udev_device_event(&rules, udev);
run_exec_q = 1;
}
-/* runs event and removes event from run queue when finished */
+static int mem_size_mb(void)
+{
+ int f;
+ char buf[8192];
+ long int len;
+ const char *pos;
+ long int memsize;
+
+ f = open("/proc/meminfo", O_RDONLY);
+ if (f == -1)
+ return -1;
+
+ len = read(f, buf, sizeof(buf)-1);
+ close(f);
+
+ if (len <= 0)
+ return -1;
+ buf[len] = '\0';
+
+ pos = strstr(buf, "MemTotal: ");
+ if (pos == NULL)
+ return -1;
+
+ if (sscanf(pos, "MemTotal: %ld kB", &memsize) != 1)
+ return -1;
+
+ return memsize / 1024;
+}
+
+static int cpu_count(void)
+{
+ int f;
+ char buf[32768];
+ int len;
+ const char *pos;
+ int count = 0;
+
+ f = open("/proc/stat", O_RDONLY);
+ if (f == -1)
+ return -1;
+
+ len = read(f, buf, sizeof(buf)-1);
+ close(f);
+ if (len <= 0)
+ return -1;
+ buf[len] = '\0';
+
+ pos = strstr(buf, "cpu");
+ if (pos == NULL)
+ return -1;
+
+ while (pos != NULL) {
+ if (strncmp(pos, "cpu", 3) == 0 &&isdigit(pos[3]))
+ count++;
+ pos = strstr(&pos[3], "cpu");
+ }
+
+ if (count == 0)
+ return -1;
+ return count;
+}
+
static int running_processes(void)
{
int f;
len = read(f, buf, sizeof(buf)-1);
close(f);
-
if (len <= 0)
return -1;
- else
- buf[len] = '\0';
+ buf[len] = '\0';
pos = strstr(buf, "procs_running ");
if (pos == NULL)
int bufpos;
int i;
struct udevd_uevent_msg *msg;
+ char *physdevdriver_key = NULL;
int major = 0;
int minor = 0;
msg->devpath = &key[8];
else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
msg->subsystem = &key[10];
+ else if (strncmp(key, "DRIVER=", 7) == 0)
+ msg->driver = &key[7];
else if (strncmp(key, "SEQNUM=", 7) == 0)
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);
else if (strncmp(key, "MINOR=", 6) == 0)
}
msg->devt = makedev(major, minor);
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) {
info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval);
max_childs = *intval;
break;
+ case UDEVD_CTRL_SET_MAX_CHILDS_RUNNING:
+ intval = (int *) ctrl_msg.buf;
+ info("udevd message (UDEVD_SET_MAX_CHILDS_RUNNING) received, max_childs=%i", *intval);
+ max_childs_running = *intval;
+ break;
case UDEVD_CTRL_RELOAD_RULES:
info("udevd message (RELOAD_RULES) received");
reload_config = 1;
break;
default:
- dbg("unknown message type");
+ err("unknown control message type");
}
}
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");
+ fprintf(stderr, "root privileges required\n");
+ err("root privileges required");
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);
}
}
/* 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);
value = getenv("UDEVD_MAX_CHILDS");
if (value)
max_childs = strtoul(value, NULL, 10);
- else
- max_childs = UDEVD_MAX_CHILDS;
+ else {
+ int memsize = mem_size_mb();
+ if (memsize > 0)
+ max_childs = 128 + (memsize / 4);
+ else
+ max_childs = UDEVD_MAX_CHILDS;
+ }
info("initialize max_childs to %u", max_childs);
/* start to throttle forking if maximum number of _running_ childs is reached */
value = getenv("UDEVD_MAX_CHILDS_RUNNING");
if (value)
max_childs_running = strtoull(value, NULL, 10);
- else
- max_childs_running = UDEVD_MAX_CHILDS_RUNNING;
+ else {
+ int cpus = cpu_count();
+ if (cpus > 0)
+ max_childs_running = 8 + (8 * cpus);
+ else
+ max_childs_running = UDEVD_MAX_CHILDS_RUNNING;
+ }
info("initialize max_childs_running to %u", max_childs_running);
/* clear environment for forked event processes */
}
}
- /* 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);