From: Harald Hoyer <harald@redhat.com>
To: linux-hotplug@vger.kernel.org
Subject: Re: waiting for an unknown set of udev /dev entries to complete
Date: Wed, 23 Nov 2005 16:27:51 +0000 [thread overview]
Message-ID: <43849887.9050305@redhat.com> (raw)
In-Reply-To: <20051118223045.GA28401@us.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 591 bytes --]
Pozsar Balazs wrote:
> I still think, the best solution would be:
> - udevd itself triggers all the uevents
> - when it finished processing all these events, only then daemonizes
> itself.
> So the udevd startup script could be nothing more than:
> udevd --daemon
>
> Nice daemons always have this kind of behavior: they does not fork
> and return immediately, but return if the daemon successfully started
> and initalized itself. For a good example, see hald.
>
>
/signed
you may test:
ftp://people.redhat.com/harald/udev/udev-075-5.src.rpm
which has the attached patch :)
[-- Attachment #2: udev-075-daemon.patch --]
[-- Type: text/x-patch, Size: 9802 bytes --]
--- udev-075/udevd.c.daemon 2005-11-23 14:21:40.000000000 +0100
+++ udev-075/udevd.c 2005-11-23 15:41:41.000000000 +0100
@@ -42,14 +42,16 @@
#include <linux/types.h>
#include <linux/netlink.h>
-#include "list.h"
+#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
+#include "udev_sysfs.h"
#include "udev.h"
#include "udev_version.h"
-#include "udev_rules.h"
+#include "logging.h"
#include "udev_utils.h"
+#include "udev_rules.h"
+#include "list.h"
#include "udevd.h"
-#include "logging.h"
struct udev_rules rules;
static int udevd_sock;
@@ -71,6 +73,277 @@
static LIST_HEAD(running_list);
+struct device {
+ struct list_head node;
+ char path[PATH_SIZE];
+ char subsys[NAME_SIZE];
+};
+
+/* sort files in lexical order */
+static int device_list_insert(const char *path, char *subsystem, struct list_head *device_list)
+{
+ struct device *loop_device;
+ struct device *new_device;
+ const char *devpath = &path[strlen(sysfs_path)];
+
+ dbg("insert: '%s'\n", devpath);
+
+ list_for_each_entry(loop_device, device_list, node) {
+ if (strcmp(loop_device->path, devpath) > 0) {
+ break;
+ }
+ }
+
+ new_device = malloc(sizeof(struct device));
+ if (new_device == NULL) {
+ dbg("error malloc");
+ return -ENOMEM;
+ }
+
+ strlcpy(new_device->path, devpath, sizeof(new_device->path));
+ strlcpy(new_device->subsys, subsystem, sizeof(new_device->subsys));
+ list_add_tail(&new_device->node, &loop_device->node);
+ dbg("add '%s' from subsys '%s'", new_device->path, new_device->subsys);
+ return 0;
+}
+
+/* list of devices that we should run last due to any one of a number of reasons */
+static char *last_list[] = {
+ "/block/dm", /* on here because dm wants to have the block devices around before it */
+ NULL,
+};
+
+/* list of devices that we should run first due to any one of a number of reasons */
+static char *first_list[] = {
+ "/class/mem",
+ "/class/tty",
+ "/bus",
+ NULL,
+};
+
+static int add_device(const char *devpath, const char *subsystem)
+{
+ char filename[PATH_SIZE];
+ int fd;
+
+ snprintf(filename, sizeof(filename), "%s/%s/uevent", sysfs_path, devpath);
+ filename[sizeof(filename)-1] = '\0';
+
+ dbg("Trigger %s", filename);
+ fd = open(filename, O_WRONLY);
+ if (fd > 0) {
+ write(fd, "add\n", 4);
+ close(fd);
+ }
+ else return 1;
+
+ return 0;
+}
+
+static void do_exec_list(struct list_head *device_list)
+{
+ struct device *loop_device;
+ struct device *tmp_device;
+ int i;
+
+ /* handle the "first" type devices first */
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ for (i = 0; first_list[i] != NULL; i++) {
+ if (strncmp(loop_device->path, first_list[i], strlen(first_list[i])) == 0) {
+ add_device(loop_device->path, loop_device->subsys);
+ list_del(&loop_device->node);
+ free(loop_device);
+ break;
+ }
+ }
+ }
+
+ /* handle the devices we are allowed to, excluding the "last" type devices */
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ int found = 0;
+ for (i = 0; last_list[i] != NULL; i++) {
+ if (strncmp(loop_device->path, last_list[i], strlen(last_list[i])) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ add_device(loop_device->path, loop_device->subsys);
+ list_del(&loop_device->node);
+ free(loop_device);
+ }
+
+ /* handle the rest of the devices left over, if any */
+ list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
+ add_device(loop_device->path, loop_device->subsys);
+ list_del(&loop_device->node);
+ free(loop_device);
+ }
+}
+
+static int has_devt(const char *path)
+{
+ char filename[PATH_SIZE];
+ struct stat statbuf;
+
+ snprintf(filename, sizeof(filename), "%s/uevent", path);
+ filename[sizeof(filename)-1] = '\0';
+
+ if (stat(filename, &statbuf) == 0)
+ return 1;
+
+ return 0;
+}
+
+static void udev_scan_block(struct list_head *device_list)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+
+ snprintf(base, sizeof(base), "%s/block", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[PATH_SIZE];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
+ dirname[sizeof(dirname)-1] = '\0';
+ if (has_devt(dirname))
+ device_list_insert(dirname, "block", device_list);
+ else
+ continue;
+
+ /* look for partitions */
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[PATH_SIZE];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
+ dirname2[sizeof(dirname2)-1] = '\0';
+
+ if (has_devt(dirname2))
+ device_list_insert(dirname2, "block", device_list);
+ }
+ closedir(dir2);
+ }
+ }
+ closedir(dir);
+ }
+}
+
+static void udev_scan_bus(struct list_head *device_list)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+
+ snprintf(base, sizeof(base), "%s/bus", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[PATH_SIZE];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "%s/%s/devices", base, dent->d_name);
+ dirname[sizeof(dirname)-1] = '\0';
+
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[PATH_SIZE];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
+ dirname2[sizeof(dirname2)-1] = '\0';
+
+ if (has_devt(dirname2))
+ device_list_insert(dirname2, dent->d_name, device_list);
+ }
+ closedir(dir2);
+ }
+ }
+ closedir(dir);
+ }
+}
+
+
+static void udev_scan_class(struct list_head *device_list)
+{
+ char base[PATH_SIZE];
+ DIR *dir;
+ struct dirent *dent;
+
+ snprintf(base, sizeof(base), "%s/class", sysfs_path);
+ base[sizeof(base)-1] = '\0';
+
+ dir = opendir(base);
+ if (dir != NULL) {
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char dirname[PATH_SIZE];
+ DIR *dir2;
+ struct dirent *dent2;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
+ dirname[sizeof(dirname)-1] = '\0';
+
+ dir2 = opendir(dirname);
+ if (dir2 != NULL) {
+ for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+ char dirname2[PATH_SIZE];
+
+ if (dent2->d_name[0] == '.')
+ continue;
+
+ snprintf(dirname2, sizeof(dirname2), "%s/%s", dirname, dent2->d_name);
+ dirname2[sizeof(dirname2)-1] = '\0';
+
+ if (has_devt(dirname2))
+ device_list_insert(dirname2, dent->d_name, device_list);
+ }
+ closedir(dir2);
+ }
+ }
+ closedir(dir);
+ }
+}
+
+static int udevstart(void)
+{
+ LIST_HEAD(device_list);
+ udev_scan_bus(&device_list);
+ udev_scan_class(&device_list);
+ udev_scan_block(&device_list);
+ do_exec_list(&device_list);
+ return 0;
+}
+
+
+
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
{
@@ -691,6 +964,41 @@
return 0;
}
+
+static int do_daemonize(void)
+{
+ pid_t pid;
+ int rc = 0;
+
+ pid = fork();
+ switch (pid) {
+ case 0:
+ dbg("daemonized fork running");
+ break;
+ case -1:
+ err("fork of daemon failed: %s", strerror(errno));
+ rc = 4;
+ goto exit;
+ default:
+ dbg("child [%u] running, parent exits", pid);
+ exit(0);
+ }
+
+ /* set scheduling priority for the daemon */
+ setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
+
+ chdir("/");
+ umask(022);
+
+ /* become session leader */
+ sid = setsid();
+ dbg("our session is %d", sid);
+
+ exit:
+ return rc;
+
+}
+
int main(int argc, char *argv[], char *envp[])
{
int retval;
@@ -702,6 +1010,10 @@
int i;
int rc = 0;
int maxfd;
+ int daemonized = 0;
+
+ struct timeval timeout = { 0, 200000 };
+ struct timeval *ptimeout = &timeout;
/* redirect std fd's, if the kernel forks us, we don't have them at all */
fd = open("/dev/null", O_RDWR);
@@ -762,24 +1074,6 @@
/* parse the rules and keep it in memory */
udev_rules_init(&rules, 1);
- if (daemonize) {
- pid_t pid;
-
- pid = fork();
- switch (pid) {
- case 0:
- dbg("daemonized fork running");
- break;
- case -1:
- err("fork of daemon failed: %s", strerror(errno));
- rc = 4;
- goto exit;
- default:
- dbg("child [%u] running, parent exits", pid);
- goto exit;
- }
- }
-
/* set scheduling priority for the daemon */
setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
@@ -859,6 +1153,8 @@
maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]);
maxfd = UDEV_MAX(maxfd, inotify_fd);
+ udevstart();
+
while (!udev_exit) {
struct uevent_msg *msg;
int fdcount;
@@ -870,13 +1166,30 @@
if (inotify_fd > 0)
FD_SET(inotify_fd, &readfds);
- fdcount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+ fdcount = select(maxfd+1, &readfds, NULL, NULL, ptimeout);
+
if (fdcount < 0) {
if (errno != EINTR)
err("error in select: %s", strerror(errno));
continue;
}
+ if (ptimeout) {
+ ptimeout->tv_sec = 0;
+ ptimeout->tv_usec = 200000;
+ }
+
+ if (fdcount == 0) {
+ if (list_empty(&running_list)) {
+ if (daemonized == 0 && daemonize) {
+ do_daemonize();
+ daemonized++;
+ }
+ ptimeout = NULL;
+ }
+ continue;
+ }
+
/* get user socket message */
if (FD_ISSET(udevd_sock, &readfds)) {
msg = get_udevd_msg();
next prev parent reply other threads:[~2005-11-23 16:27 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-11-18 22:30 waiting for an unknown set of udev /dev entries to complete Patrick Mansfield
2005-11-20 6:03 ` Kay Sievers
2005-11-20 17:25 ` Patrick Mansfield
2005-11-20 18:23 ` Kay Sievers
2005-11-20 20:10 ` Pozsar Balazs
2005-11-20 20:23 ` Marco d'Itri
2005-11-20 23:32 ` Kay Sievers
2005-11-20 23:53 ` Kay Sievers
2005-11-21 0:01 ` Marco d'Itri
2005-11-22 23:13 ` Kay Sievers
2005-11-23 8:26 ` Scott James Remnant
2005-11-23 10:54 ` Pozsar Balazs
2005-11-23 16:27 ` Harald Hoyer [this message]
2005-11-23 16:50 ` Kay Sievers
2005-11-23 17:25 ` Pozsar Balazs
2005-11-23 17:46 ` Kay Sievers
2005-11-23 18:16 ` Pozsar Balazs
2005-11-23 18:39 ` Kay Sievers
2005-11-23 21:33 ` Patrick Mansfield
2005-11-28 22:09 ` Pozsar Balazs
2005-11-29 10:44 ` Kay Sievers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=43849887.9050305@redhat.com \
--to=harald@redhat.com \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.