1/* 2 * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com> 3 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation version 2 of the License. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 */ 19 20#include <stdio.h> 21#include <stddef.h> 22#include <stdlib.h> 23#include <string.h> 24#include <fcntl.h> 25#include <ctype.h> 26#include <errno.h> 27#include <signal.h> 28#include <unistd.h> 29#include <syslog.h> 30 31#include "udev.h" 32#include "udev_rules.h" 33#include "udev_selinux.h" 34 35#ifdef USE_LOG 36void log_message(int priority, const char *format, ...) 37{ 38 va_list args; 39 40 if (priority > udev_log_priority) 41 return; 42 43 va_start(args, format); 44 vsyslog(priority, format, args); 45 va_end(args); 46} 47#endif 48 49static void asmlinkage sig_handler(int signum) 50{ 51 switch (signum) { 52 case SIGALRM: 53 exit(1); 54 case SIGINT: 55 case SIGTERM: 56 exit(20 + signum); 57 } 58} 59 60int main(int argc, char *argv[], char *envp[]) 61{ 62 struct sysfs_device *dev; 63 struct udevice *udev; 64 const char *maj, *min; 65 struct udev_rules rules; 66 const char *action; 67 const char *devpath; 68 const char *subsystem; 69 struct sigaction act; 70 int devnull; 71 int retval = -EINVAL; 72 73 if (argc == 2 && strcmp(argv[1], "-V") == 0) { 74 printf("%s\n", UDEV_VERSION); 75 exit(0); 76 } 77 78 /* set std fd's to /dev/null, /sbin/hotplug forks us, we don't have them at all */ 79 devnull = open("/dev/null", O_RDWR); 80 if (devnull >= 0) { 81 if (devnull != STDIN_FILENO) 82 dup2(devnull, STDIN_FILENO); 83 if (devnull != STDOUT_FILENO) 84 dup2(devnull, STDOUT_FILENO); 85 if (devnull != STDERR_FILENO) 86 dup2(devnull, STDERR_FILENO); 87 if (devnull > STDERR_FILENO) 88 close(devnull); 89 } 90 91 logging_init("udev"); 92 if (devnull < 0) 93 err("open /dev/null failed: %s", strerror(errno)); 94 udev_config_init(); 95 selinux_init(); 96 dbg("version %s", UDEV_VERSION); 97 98 /* set signal handlers */ 99 memset(&act, 0x00, sizeof(act)); 100 act.sa_handler = (void (*)(int)) sig_handler; 101 sigemptyset (&act.sa_mask); 102 act.sa_flags = 0; 103 sigaction(SIGALRM, &act, NULL); 104 sigaction(SIGINT, &act, NULL); 105 sigaction(SIGTERM, &act, NULL); 106 107 /* trigger timeout to prevent hanging processes */ 108 alarm(UDEV_ALARM_TIMEOUT); 109 110 action = getenv("ACTION"); 111 devpath = getenv("DEVPATH"); 112 subsystem = getenv("SUBSYSTEM"); 113 /* older kernels passed the SUBSYSTEM only as argument */ 114 if (subsystem == NULL && argc == 2) 115 subsystem = argv[1]; 116 117 if (action == NULL || subsystem == NULL || devpath == NULL) { 118 err("action, subsystem or devpath missing"); 119 goto exit; 120 } 121 122 /* export log_priority , as called programs may want to do the same as udev */ 123 if (udev_log_priority) { 124 char priority[32]; 125 126 sprintf(priority, "%i", udev_log_priority); 127 setenv("UDEV_LOG", priority, 1); 128 } 129 130 sysfs_init(); 131 udev_rules_init(&rules, 0); 132 133 dev = sysfs_device_get(devpath); 134 if (dev == NULL) { 135 info("unable to open '%s'", devpath); 136 goto fail; 137 } 138 139 udev = udev_device_init(NULL); 140 if (udev == NULL) 141 goto fail; 142 143 /* override built-in sysfs device */ 144 udev->dev = dev; 145 strlcpy(udev->action, action, sizeof(udev->action)); 146 147 /* get dev_t from environment, which is needed for "remove" to work, "add" works also from sysfs */ 148 maj = getenv("MAJOR"); 149 min = getenv("MINOR"); 150 if (maj != NULL && min != NULL) 151 udev->devt = makedev(atoi(maj), atoi(min)); 152 else 153 udev->devt = udev_device_get_devt(udev); 154 155 retval = udev_device_event(&rules, udev); 156 157 if (retval == 0 && !udev->ignore_device && udev_run) { 158 struct name_entry *name_loop; 159 160 dbg("executing run list"); 161 list_for_each_entry(name_loop, &udev->run_list, node) { 162 if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0) 163 pass_env_to_socket(&name_loop->name[strlen("socket:")], devpath, action); 164 else { 165 char program[PATH_SIZE]; 166 167 strlcpy(program, name_loop->name, sizeof(program)); 168 udev_rules_apply_format(udev, program, sizeof(program)); 169 run_program(program, udev->dev->subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO)); 170 } 171 } 172 } 173 174 udev_device_cleanup(udev); 175fail: 176 udev_rules_cleanup(&rules); 177 sysfs_cleanup(); 178 selinux_exit(); 179 180exit: 181 logging_close(); 182 if (retval != 0) 183 return 1; 184 return 0; 185} 186