From mboxrd@z Thu Jan 1 00:00:00 1970 From: Harald Hoyer Date: Wed, 23 Nov 2005 16:27:51 +0000 Subject: Re: waiting for an unknown set of udev /dev entries to complete Message-Id: <43849887.9050305@redhat.com> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------080605020408040700050200" List-Id: References: <20051118223045.GA28401@us.ibm.com> In-Reply-To: <20051118223045.GA28401@us.ibm.com> To: linux-hotplug@vger.kernel.org This is a multi-part message in MIME format. --------------080605020408040700050200 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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 :) --------------080605020408040700050200 Content-Type: text/x-patch; name="udev-075-daemon.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="udev-075-daemon.patch" --- 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 #include -#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(); --------------080605020408040700050200-- ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel