📄 devfsd.c
字号:
unsigned long *event_mask);static void process_config_line (CONST char *line, unsigned long *event_mask);static void *dlsym_nofail (const char *file, void *handle, char *symbol);static int process_yp_line (int instatus, char *inkey, int inkeylen, char *inval, int invallen, char *indata);static void load_libnsl (void);static flag do_servicing (int fd, unsigned long event_mask);static void service_name (const struct devfsd_notify_struct *info);static void action_permissions (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry);static void action_modload (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry);static void action_execute (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int numexpr);static void action_call_function (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int numexpr);static void action_copy (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int number);static void action_compat (const struct devfsd_notify_struct *info, unsigned int action);static void free_config ();static void do_restore (const char *dirname, int rootlen);static flag copy_inode (const char *destpath, const struct stat *deststat, mode_t new_mode, const char *sourcepath, const struct stat *sourcestat);static void do_debug (int fd);static uid_t get_uid (const char *string);static gid_t get_gid (const char *string);static mode_t get_mode (const char *string);static void signal_handler (int sig);static CONST char *get_variable (CONST char *variable, void *info);static void do_open_syslog ();static void do_scan_and_service (CONST char *dirname);static flag make_dir_tree (const char *path);static struct shared_object *get_shared_object (CONST char *name);static flag expand_expression(char *output, unsigned int outsize, const char *input, const char *(*get_variable)(const char *variable, void *info), void *info, const char *devname, const regmatch_t *ex, unsigned int numexp, FILE *errfp);static void expand_regexp (char *output, size_t outsize, const char *input, const char *devname, const regmatch_t *ex, unsigned int numex, FILE *errfp);/* Private data */static struct config_entry_struct *first_config = NULL;static struct config_entry_struct *last_config = NULL;static struct shared_object *first_so = NULL;static const char *mount_point = NULL;static flag no_syslog = FALSE;static char trace_level = 0;static flag debug_protocol = FALSE;static volatile flag caught_signal = FALSE;static volatile flag caught_sighup = FALSE;static struct initial_symlink_struct{ char *dest; char *name;} initial_symlinks[] ={ {"/proc/self/fd", "fd"}, {"fd/0", "stdin"}, {"fd/1", "stdout"}, {"fd/2", "stderr"}, {NULL, NULL},};static int (*my_yp_all) (char *domain, char *map, struct ypall_callback *callback); /* = NULL */static int (*my_yp_get_default_domain) (char **domainptr); /* = NULL */static struct event_type{ unsigned int type; /* The DEVFSD_NOTIFY_* value */ CONST char *config_name; /* The name used in the config file */ CONST char *debug_name; /* The name used when debugging the protocol */} event_types[] ={ {DEVFSD_NOTIFY_REGISTERED, "REGISTER", "registered"}, {DEVFSD_NOTIFY_UNREGISTERED, "UNREGISTER", "unregistered"}, {DEVFSD_NOTIFY_ASYNC_OPEN, "ASYNC_OPEN", "asynchronously opened"}, {DEVFSD_NOTIFY_CLOSE, "CLOSE", "closed"}, {DEVFSD_NOTIFY_LOOKUP, "LOOKUP", "lookup"}, {DEVFSD_NOTIFY_CHANGE, "CHANGE", "changed"}, {DEVFSD_NOTIFY_CREATE, "CREATE", "created"}, {DEVFSD_NOTIFY_DELETE, "DELETE", "deleted"}, {0xffffffff, NULL, NULL}};/* Public functions follow */int main (int argc, char **argv){ flag print_version = FALSE; flag debug_devfs = FALSE; flag do_daemon = TRUE; flag no_polling = FALSE; int fd, proto_rev, count; unsigned int devfs_debug_mask; unsigned long event_mask = 0; struct sigaction new_action; struct stat statbuf; static char usage[] = "devfsd mntpnt [-v] [-d] [-t num] [-D mask] [-fg] [-np]"; if (argc < 2) { fprintf (stderr, "Usage:\t%s\n", usage); exit (1); } for (count = 2; count < argc; ++count) { if (strcmp (argv[count], "-v") == 0) print_version = TRUE; else if (strcmp (argv[count], "-d") == 0) { debug_protocol = TRUE; no_syslog = TRUE; } else if ( (strcmp (argv[count], "-t") == 0) && (count + 1 < argc) ) trace_level = atoi (argv[++count]); else if ( (strcmp (argv[count], "-D") == 0) && (++count < argc) ) { devfs_debug_mask = strtol (argv[count], NULL, 0); debug_devfs = TRUE; } else if (strcmp (argv[count], "-fg") == 0) do_daemon = FALSE; else if (strcmp (argv[count], "-np") == 0) no_polling = TRUE; else { fprintf (stderr, "Usage:\t%s\n", usage); exit (1); } } if (trace_level > 0) no_syslog = TRUE; mount_point = argv[1]; if (chdir (mount_point) != 0) { fprintf (stderr, "Error changing directory to: \"%s\"\t%s\n", mount_point, ERRSTRING); exit (1); } /* Open dummy stdin, stdout and stderr if required, so that closing in do_open_syslog() doesn't close other files */ do fd = open ("/dev/null", O_RDWR, 0); while ( (fd >= 0) && (fd < 3) ); close (fd); if ( ( fd = open (".devfsd", O_RDONLY, 0) ) < 0 ) { fprintf (stderr, "Error opening file: \".devfsd\"\t%s\n", ERRSTRING); exit (1); } if (fcntl (fd, F_SETFD, FD_CLOEXEC) != 0) fprintf (stderr, "Error setting close on exec for .devfsd\t%s\n", ERRSTRING); if (ioctl (fd, DEVFSDIOC_GET_PROTO_REV, &proto_rev) != 0) { fprintf (stderr, "Error getting protocol revision\t%s\n", ERRSTRING); exit (1); } if (!debug_devfs) setup_initial_entries (); if (!print_version && !debug_protocol && !debug_devfs) { if (stat (CONFIG_FILE, &statbuf) != 0) { fprintf (stderr, "device management daemon exiting as no %s\n", CONFIG_FILE); exit (0); } if (statbuf.st_size == 0) { fprintf (stderr, "device management daemon exiting as %s is empty\n", CONFIG_FILE); exit (0); } } if ( print_version || (trace_level > 1) || debug_protocol || (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev) ) { fprintf (stderr, "devfsd: Linux device filesystem daemon v%s\n", DEVFSD_VERSION); fprintf (stderr, "(C) 1998-2001 Richard Gooch <rgooch@atnf.csiro.au>\n\n"); fprintf (stderr, "Daemon protocol revision:\t%d\n", DEVFSD_PROTOCOL_REVISION_DAEMON); fprintf (stderr, "Kernel-side protocol revision:\t%d\n", proto_rev); if (DEVFSD_PROTOCOL_REVISION_DAEMON != proto_rev) { fprintf (stderr, "Protocol mismatch!\n"); exit (1); } } if (print_version) exit (0); if (debug_devfs) { if (ioctl (fd, DEVFSDIOC_SET_DEBUG_MASK, &devfs_debug_mask) != 0) { fprintf (stderr, "Error setting debug mask\t%s\n", ERRSTRING); exit (1); } exit (0); } /* Tell kernel we are special (i.e. we get to see hidden entries) */ if (ioctl (fd, DEVFSDIOC_SET_EVENT_MASK, 0) != 0) { fprintf (stderr, "Error setting event mask\t%s\n", ERRSTRING); exit (1); } if (debug_protocol) do_debug (fd); sigemptyset (&new_action.sa_mask); new_action.sa_flags = 0; /* Set up SIGHUP and SIGUSR1 handlers */ new_action.sa_handler = signal_handler; if (sigaction (SIGHUP, &new_action, NULL) != 0) { fprintf (stderr, "Error setting SIGHUP handler\t%s\n", ERRSTRING); exit (1); } if (sigaction (SIGUSR1, &new_action, NULL) != 0) { fprintf (stderr, "Error setting SIGUSR1 handler\t%s\n", ERRSTRING); exit (1); } if (trace_level < 1) fprintf (stderr, "Started device management daemon v%s for %s\n", DEVFSD_VERSION, mount_point); else fprintf (stderr, "Started device management daemon v%s for %s at trace level %d\n", DEVFSD_VERSION, mount_point, trace_level); /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */ umask (0); read_config (CONFIG_FILE, FALSE, &event_mask); /* Do the scan before forking, so that boot scripts see the finished product */ do_scan_and_service (mount_point); if (no_polling) exit (0); if (do_daemon) { /* Release so that the child can grab it */ if (ioctl (fd, DEVFSDIOC_RELEASE_EVENT_QUEUE, 0) != 0) { fprintf (stderr, "Error releasing event queue\t%s\n", ERRSTRING); exit (1); } switch ( fork () ) { case 0: /* Child */ break; case -1: /* Error */ perror ("devfsd"); exit (2); /*break;*/ default: /* Parent */ exit (0); /*break;*/ } setsid (); /* Prevent hangups and become pgrp leader */ } else setpgid (0, 0); /* Become process group leader */ do_open_syslog (); while (TRUE) { flag do_scan = do_servicing (fd, event_mask); free_config (); read_config (CONFIG_FILE, FALSE, &event_mask); if (do_scan) do_scan_and_service (mount_point); }} /* End Function main *//* Private functions follow */static void setup_initial_entries (){ struct initial_symlink_struct *curr; for (curr = initial_symlinks; curr->dest != NULL; ++curr) symlink (curr->dest, curr->name);} /* End Function setup_initial_entries */static void read_config (CONST char *location, flag optional, unsigned long *event_mask)/* [SUMMARY] Read a configuration database. <location> The location to read the database from. Either a filename or a YP(NIS) map name prefixed with '+'. <optional> If TRUE, the routine will silently ignore a missing config file. <event_mask> The event mask is written here. This is not initialised. [RETURNS] Nothing.*/{ if (location[0] == '+') { /* It's a YP map */ struct ypall_callback ypall_cbk; char *domainname = NULL; if (my_yp_all == NULL) load_libnsl (); /* If no domain: fail silently (probably too early) */ if ( (*my_yp_get_default_domain) (&domainname) != 0 ) return; if (domainname == NULL) return; ypall_cbk.foreach = ( int (*) () ) process_yp_line; ypall_cbk.data = (char *) event_mask; if ( (*my_yp_all) (domainname, (char *) location + 1,&ypall_cbk) == 0 ) { if (syslog_is_open) SYSLOG (LOG_INFO, "read map: \"%s\"\n", location + 1); return; } if (optional) return; SYSLOG (LOG_ERR, "error reading map: \"%s\"\n", location + 1); exit (1); } read_config_file (location, optional, event_mask);} /* End Function read_config */static void read_config_file (CONST char *path, flag optional, unsigned long *event_mask)/* [SUMMARY] Read a configuration database. <path> The path to read the database from. If this is a directory, all entries in that directory will be read (except hidden entries). <optional> If TRUE, the routine will silently ignore a missing config file. <event_mask> The event mask is written here. This is not initialised. [RETURNS] Nothing.*/{ struct stat statbuf; FILE *fp; char buf[STRING_LENGTH]; if (stat (path, &statbuf) != 0) { if ( optional && (errno == ENOENT) ) return; SYSLOG (LOG_ERR, "error opening file: \"%s\"\t%s\n", path, ERRSTRING); exit (1); } if ( S_ISDIR (statbuf.st_mode) ) { DIR *dp; struct dirent *de; if ( ( dp = opendir (path) ) == NULL ) { SYSLOG (LOG_ERR, "error opening directory: \"%s\"\t%s\n", path, ERRSTRING); exit (1); } while ( ( de = readdir (dp) ) != NULL ) { char fname[STRING_LENGTH]; if (de->d_name[0] == '.') continue; snprintf (fname, STRING_LENGTH, "%s/%s", path, de->d_name); read_config_file (fname, optional, event_mask); } closedir (dp); return; } if ( ( fp = fopen (path, "r") ) == NULL ) { if ( optional && (errno == ENOENT) ) return; SYSLOG (LOG_ERR, "error opening file: \"%s\"\t%s\n", path, ERRSTRING); exit (1); } if (trace_level > 2) fprintf (stderr, "Reading file: \"%s\"\n", path); while (fgets (buf, STRING_LENGTH, fp) != NULL) { char *line; buf[strlen (buf) - 1] = '\0'; /* Skip whitespace */ for (line = buf; isspace (*line); ++line); if (line[0] == '\0') continue; if (line[0] == '#') continue; process_config_line (line, event_mask); } fclose (fp); if (syslog_is_open) SYSLOG (LOG_INFO, "read config file: \"%s\"\n", path);} /* End Function read_config_file */static void process_config_line (CONST char *line, unsigned long *event_mask)/* [SUMMARY] Process a line from a configuration file. <line> The configuration line. <event_mask> The event mask is written here. This is not initialised. [RETURNS] Nothing.*/{ int err, num_args, count; struct config_entry_struct *new; char p[MAX_ARGS][STRING_LENGTH]; char when[STRING_LENGTH], what[STRING_LENGTH]; char name[STRING_LENGTH], tmp[STRING_LENGTH]; for (count = 0; count < MAX_ARGS; ++count) p[count][0] = '\0'; num_args = sscanf (line, "%s %s %s %s %s %s %s %s %s %s", when, name, what, p[0], p[1], p[2], p[3], p[4], p[5], p[6]); if (strcasecmp (when, "CLEAR_CONFIG") == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -