udevd.c revision 225cb03bd851adc6d269b13bdf2b1bfded2b96b9
9f26fa2217bcad38a6a92a06a598f6c3a3d1b18eKay Sievers * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
9f26fa2217bcad38a6a92a06a598f6c3a3d1b18eKay Sievers * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
6db01ccb784c924d883c020996da05469aee8ebdKay Sievers * This program is free software; you can redistribute it and/or modify it
d086fe4e085d216652b70e575e59302810035989Kay Sievers * under the terms of the GNU General Public License as published by the
d086fe4e085d216652b70e575e59302810035989Kay Sievers * Free Software Foundation version 2 of the License.
d086fe4e085d216652b70e575e59302810035989Kay Sievers * This program is distributed in the hope that it will be useful, but
d086fe4e085d216652b70e575e59302810035989Kay Sievers * WITHOUT ANY WARRANTY; without even the implied warranty of
d086fe4e085d216652b70e575e59302810035989Kay Sievers * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9cb48731b29f508178731b45b0643c816800c05eKay Sievers * General Public License for more details.
9cb48731b29f508178731b45b0643c816800c05eKay Sievers * You should have received a copy of the GNU General Public License along
9cb48731b29f508178731b45b0643c816800c05eKay Sievers * with this program; if not, write to the Free Software Foundation, Inc.,
9cb48731b29f508178731b45b0643c816800c05eKay Sievers * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
424a19f8a2061c6b058283228734010b2fa24db4Lennart Poetteringstatic volatile int sigchilds_waiting;
424a19f8a2061c6b058283228734010b2fa24db4Lennart Poetteringstatic volatile int udev_exit;
67f3c40265471056d1e532c6d6e36a521b0a780aLennart Poetteringstatic volatile int reload_config;
a1cccad1fe88ddd6943e18af97cf7f466296970fLennart Poetteringvoid log_message(int priority, const char *format, ...)
802840582c71e9679637a4631866ce2d179f03c5Lennart Poetteringstatic void asmlinkage udev_event_sig_handler(int signum)
d87be9b0af81a6e07d4fb3028e45c4409100dc26Lennart Poetteringstatic int udev_event_process(struct udevd_uevent_msg *msg)
d87be9b0af81a6e07d4fb3028e45c4409100dc26Lennart Poettering /* set signal handlers */
88f89a9b6d25dfcb89691727c8cdaf01f4090b72Lennart Poettering act.sa_handler = (void (*)(int)) udev_event_sig_handler;
88f89a9b6d25dfcb89691727c8cdaf01f4090b72Lennart Poettering /* reset to default */
88f89a9b6d25dfcb89691727c8cdaf01f4090b72Lennart Poettering /* trigger timeout to prevent hanging processes */
88f89a9b6d25dfcb89691727c8cdaf01f4090b72Lennart Poettering /* reconstruct event environment from message */
1946b0bd55b356ea25bd747cb338a4b31fabeecfLennart Poettering strlcpy(udev->action, msg->action, sizeof(udev->action));
cde9cb343ae101660dd36992cae730b63c7cd617Lennart Poettering sysfs_device_set_values(udev->dev, msg->devpath, msg->subsystem, msg->driver);
c0d6e764d107a81a6439c41edbe92790623ed7deLennart Poettering retval = udev_device_event(&rules, udev);
c0ca7aeec963207b6fa5ee39bd204cb26cba4023Lennart Poettering /* run programs collected by RUN-key*/
c0ca7aeec963207b6fa5ee39bd204cb26cba4023Lennart Poettering if (retval == 0 && !udev->ignore_device && udev_run)
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poetteringstatic void export_event_state(struct udevd_uevent_msg *msg, enum event_state state)
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering /* location of queue file */
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering snprintf(filename, sizeof(filename), "%s/"EVENT_QUEUE_DIR"/%llu", udev_root, msg->seqnum);
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering /* location of failed file */
0790b9fed42eefc4e22dbbe2337cba9713b7848cLennart Poettering strlcpy(filename_failed, udev_root, sizeof(filename_failed));
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering strlcat(filename_failed, "/", sizeof(filename_failed));
df1c8f6ac8a45913104b5eeb44f4574689fedd50Lennart Poettering start = strlcat(filename_failed, EVENT_FAILED_DIR"/", sizeof(filename_failed));
5aea932fd54db835b77709ddeba30732648aae53Lennart Poettering strlcat(filename_failed, msg->devpath, sizeof(filename_failed));
5aea932fd54db835b77709ddeba30732648aae53Lennart Poettering path_encode(&filename_failed[start], sizeof(filename_failed) - start);
4d9909c93e9c58789c71b34555a1908307c6849eLennart Poettering /* "move" event - rename failed file to current name, do not delete failed */
47ae7201b1df43bd3da83a19e38483b0e5694c99Lennart Poettering strlcpy(filename_failed_old, udev_root, sizeof(filename_failed_old));
47ae7201b1df43bd3da83a19e38483b0e5694c99Lennart Poettering strlcat(filename_failed_old, "/", sizeof(filename_failed_old));
941e990db1f2682abaa2966b1c48602901d0c599Lennart Poettering start = strlcat(filename_failed_old, EVENT_FAILED_DIR"/", sizeof(filename_failed_old));
941e990db1f2682abaa2966b1c48602901d0c599Lennart Poettering strlcat(filename_failed_old, msg->devpath_old, sizeof(filename_failed_old));
decab96090593d617bfd576cb68253a6e082309bLennart Poettering path_encode(&filename_failed_old[start], sizeof(filename) - start);
919a7f39e6aa4a93b8348ec2586e313c40f49e52Lennart Poettering if (rename(filename_failed_old, filename_failed) == 0)
919a7f39e6aa4a93b8348ec2586e313c40f49e52Lennart Poettering info("renamed devpath, moved failed state of '%s' to %s'",
68f160039eb78fe122cfe0d4c49695ae91f6f0d1Lennart Poettering /* move failed event to the failed directory */
c66d36e5b5ae81f3c5297d6dacadc13c88c530f6Lennart Poettering /* clean up possibly empty queue directory */
461b1822321d6be0d7fd8be29bf3b4993ebd1b85Lennart Poetteringstatic void msg_queue_delete(struct udevd_uevent_msg *msg)
9946996cda11a18b44d82344676e5a0e96339408Lennart Poettering /* mark as failed, if "add" event returns non-zero */
d1970645411ea1cc083ea1668e0d446252dc1505Lennart Poettering if (msg->exitstatus && strcmp(msg->action, "add") == 0)
5231084b479455e6cc892ec3c37c9f599c5bea58Lennart Poetteringstatic void udev_event_run(struct udevd_uevent_msg *msg)
347e1b6df028ebb1589146c167add8d37a3d4244Kay Sievers info("seq %llu finished with %i", msg->seqnum, retval);
24f3a374b9588a6e409ba58b40bdd684050decf3Lennart Poettering err("fork of child failed: %s", strerror(errno));
069cfc85f876bb6966cb5a9bbe0235f5064622cdLennart Poettering /* get SIGCHLD in main loop */
069cfc85f876bb6966cb5a9bbe0235f5064622cdLennart Poettering info("seq %llu forked, pid [%d], '%s' '%s', %ld seconds old",
7b63bde1ed0d4f30c799c9b4737fa926465929f9Lennart Poettering msg->seqnum, pid, msg->action, msg->subsystem, time(NULL) - msg->queue_time);
f7f21d33db5dfe88dc8175c61dada44013347729Lennart Poetteringstatic void msg_queue_insert(struct udevd_uevent_msg *msg)
a26336da875a6657d404d1e44b86ae067c34b110Kay Sievers strlcat(filename, "/" EVENT_SEQNUM, sizeof(filename));
e85647f73e235c2a6ea412cb8d841e092c373501Lennart Poettering fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
465349c06d994dd2cc6b6fc4109ac0b9952d500aLennart Poettering len = sprintf(str, "%llu\n", msg->seqnum);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering info("seq %llu queued, '%s' '%s'", msg->seqnum, msg->action, msg->subsystem);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering /* run one event after the other in debug mode */
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering list_add_tail(&msg->node, &running_list);
e85647f73e235c2a6ea412cb8d841e092c373501Lennart Poettering /* run all events with a timeout set immediately */
a888b352eb53b07daa24fa859ceeb254336b293dLennart Poettering list_add_tail(&msg->node, &running_list);
762f91fa600b3b2887e3b088cd700216a85e3c81Kay Sievers if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
18b754d345ecb0b15e369978aaffa72e9814b86aKay Sieversstatic int cpu_count(void)
18da49531e4c6b31bd2439b4d738dc1bb9660af1Lennart Poettering while (fgets(buf, sizeof(buf), f) != NULL) {
18da49531e4c6b31bd2439b4d738dc1bb9660af1Lennart Poettering if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3]))
53ed2eeb2e709a6c0d152d7bdf2d9a4b9f997a16Lennart Poettering while (fgets(buf, sizeof(buf), f) != NULL) {
a6e87e90ede66815989ba2db92a07102a69906feLennart Poettering if (sscanf(buf, "procs_running %u", &value) == 1) {
a558d00381291afd6a81f7df07269fe76eeae556Lennart Poettering/* return the number of process es in our session, count only until limit */
a558d00381291afd6a81f7df07269fe76eeae556Lennart Poetteringstatic int running_processes_in_session(pid_t session, int limit)
87a8baa35d6d65ac3b58ae8e26e338e67f8ae8edLennart Poettering /* read process info from /proc */
87a8baa35d6d65ac3b58ae8e26e338e67f8ae8edLennart Poettering for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
b011116d1829bde044a638cbabfb070a7e0e8fa7Kay Sievers snprintf(procdir, sizeof(procdir), "/proc/%s/stat", dent->d_name);
7d441ddb5ca090b5a97f58ac4b4d97b3e84fa81eLennart Poettering /* skip ugly program name */
d3c7d7dd77b2b72315164b672462825cef6c0f9aKay Sievers if (sscanf(pos, "%c %d %d %d ", &state, &ppid, &pgrp, &sess) != 4)
1d6702e8d3877c0bebf3ac817dc45ff72f5ecfa9Lennart Poettering /* count only processes in our session */
71092d70af35567dd154d3de2ce04ce62e157a7cLennart Poettering /* count only running, no sleeping processes */
d3fc81bd6a5a046b22600ac1204df220c93d2c15Lennart Poetteringstatic int compare_devpath(const char *running, const char *waiting)
71092d70af35567dd154d3de2ce04ce62e157a7cLennart Poettering for (i = 0; i < PATH_SIZE; i++) {
8d0e38a2b966799af884e78a54fd6a2dffa44788Lennart Poettering /* identical device event found */
f28f1daf754a9a07de90e6fc4ada581bf5de677dLennart Poettering if (running[i] == '\0' && waiting[i] == '\0')
f28f1daf754a9a07de90e6fc4ada581bf5de677dLennart Poettering /* parent device event found */
88a07670cfa974a605c7c7b520b8a3135fce37f9Lennart Poettering if (running[i] == '\0' && waiting[i] == '/')
916abb21d0a6653e0187b91591e492026886b0a4Lennart Poettering /* child device event found */
916abb21d0a6653e0187b91591e492026886b0a4Lennart Poettering if (running[i] == '/' && waiting[i] == '\0')
b23de6af893c11da4286bc416455cd0926d1532eLennart Poettering /* no matching event */
68c7d001f4117f0c3d0a4582e32cbb03ae5fac57Lennart Poettering/* lookup event for identical, parent, child, or physical device */
7a2a0b907b5cc60f5d9a871997d7d6e7f62bf4d8Lennart Poetteringstatic int devpath_busy(struct udevd_uevent_msg *msg, int limit)
8bbabc447b1d913bd21faf97c7b17d20d315d2b4Lennart Poettering /* check exec-queue which may still contain delayed events we depend on */
8bbabc447b1d913bd21faf97c7b17d20d315d2b4Lennart Poettering list_for_each_entry(loop_msg, &exec_list, node) {
abdf7993161a2762df6887fdb5a5f0f4f5da24cfLennart Poettering /* skip ourself and all later events */
b9a2a36b519ccd79c4198e7dda4e657d597a14adLennart Poettering /* check our old name */
ba1a55152c50dfbcd3d4a64353b95f4a2f37985eLennart Poettering if (strcmp(loop_msg->devpath , msg->devpath_old) == 0)
3f7a8c4e9f1d3ce48919e24eb2c9d56dd6fd88d8Kay Sievers /* check identical, parent, or child device event */
f9276855a1d270b6c3f857cdaf2c4b49920c2228Lennart Poettering if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) {
f9276855a1d270b6c3f857cdaf2c4b49920c2228Lennart Poettering dbg("%llu, device event still pending %llu (%s)",
260abb780a135e4cae8c10715c7e85675efc345aLennart Poettering msg->seqnum, loop_msg->seqnum, loop_msg->devpath);
a8f11321c209830a35edd0357e8def5d4437d854Lennart Poettering /* check physical device event (special case of parent) */
a8f11321c209830a35edd0357e8def5d4437d854Lennart Poettering if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0)
21bdae12e11ae20460715475d8a0c991f15464acLennart Poettering if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) {
21bdae12e11ae20460715475d8a0c991f15464acLennart Poettering dbg("%llu, physical device event still pending %llu (%s)",