📄 devfsd.c
字号:
argv[0] = "/sbin/modprobe"; argv[1] = "-k"; argv[2] = "-C"; argv[3] = "/etc/modules.devfs"; argv[4] = device; argv[5] = NULL; snprintf (device, sizeof (device), "/dev/%s", info->devname); if (trace_level > 1) fprintf (stderr, "%s modprobe with name: \"%s\"\n", modprobe ? "Calling" : "Executing", device); if (modprobe != NULL) { char **oldenv = environ; environ = env; (*modprobe) (5, argv); environ = oldenv; return; } switch ( fork () ) { case 0: /* Child */ break; case -1: /* Error */ SYSLOG (LOG_ERR, "error forking\t%s\n", ERRSTRING); exit (2); /*break;*/ default: /* Parent */ wait (NULL); return; /*break;*/ } environ = env; execvp (argv[0], argv); SYSLOG (LOG_ERR, "error execing: \"%s\"\t%s\n", argv[0], ERRSTRING); _exit (1);} /* End Function action_modload */static void action_execute (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int numexpr)/* [SUMMARY] Execute a programme. <info> The devfs change. <entry> The config file entry. <regexpr> The number of subexpression (start, end) offsets within the device name. <numexpr> The number of elements within <<regexpr>>. [RETURNS] Nothing.*/{ unsigned int count; struct get_variable_info gv_info; char *argv[MAX_ARGS + 1]; char largv[MAX_ARGS + 1][STRING_LENGTH]; gv_info.info = info; gv_info.devname = info->devname; snprintf (gv_info.devpath, sizeof (gv_info.devpath), "%s/%s", mount_point, info->devname); if (trace_level > 1) fprintf (stderr, "Calling %s for \"%s\" | \"%s\":", entry->u.execute.argv[0], info->devname, gv_info.devpath); for (count = 0; entry->u.execute.argv[count] != NULL; ++count) { expand_expression (largv[count], STRING_LENGTH, entry->u.execute.argv[count], get_variable, &gv_info, gv_info.devname, regexpr, numexpr, NULL); argv[count] = largv[count]; if (trace_level > 1) fprintf (stderr, " '%s'", argv[count]); } if (trace_level > 1) fprintf (stderr, ". i.e. %d arg%s\n", count - 1, (count == 2) ? "" : "s"); argv[count] = NULL; switch ( fork () ) { case 0: /* Child */ break; case -1: /* Error */ SYSLOG (LOG_ERR, "error forking for programme: %s\t%s\n", argv[0], ERRSTRING); return; /*break;*/ default: /* Parent */ wait (NULL); return; /*break;*/ } execvp (argv[0], argv); SYSLOG (LOG_ERR, "error execing: \"%s\"\t%s\n", argv[0], ERRSTRING); _exit (1);} /* End Function action_execute */static void action_call_function (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int numexpr)/* [SUMMARY] Call a function. <info> The devfs change. <entry> The config file entry. <regexpr> The number of subexpression (start, end) offsets within the device name. <numexpr> The number of elements within <<regexpr>>. [RETURNS] Nothing.*/{ unsigned int count; struct get_variable_info gv_info; char *argv[MAX_ARGS + 1]; char largv[MAX_ARGS + 1][STRING_LENGTH]; gv_info.info = info; gv_info.devname = info->devname; snprintf (gv_info.devpath, sizeof (gv_info.devpath), "%s/%s", mount_point, info->devname); if (trace_level > 1) fprintf (stderr, "Calling %s in %s for \"%s\" | \"%s\":", entry->u.function.argv[0], entry->u.function.so->name, info->devname, gv_info.devpath); argv[0] = (char *) entry->u.function.so->name; for (count = 1; entry->u.function.argv[count] != NULL; ++count) { if (strcmp (entry->u.function.argv[count], "EVENT") == 0) argv[count] = (char *) info; else { expand_expression (largv[count], STRING_LENGTH, entry->u.function.argv[count], get_variable, &gv_info, gv_info.devname, regexpr, numexpr, NULL); argv[count] = largv[count]; if (trace_level > 1) fprintf (stderr, " '%s'", argv[count]); } } if (trace_level > 1) fprintf (stderr, ". i.e. %d arg%s\n", count - 1, (count == 2) ? "" : "s"); argv[count] = NULL; if (entry->action.what == AC_MFUNCTION) { if ( (*entry->u.function.func.m) (count, argv) == 0 ) return; } else { if ( (*entry->u.function.func.c) (argv[1], argv[2], argv[3], argv[4], argv[5]) == 0 ) return; } SYSLOG (LOG_ERR, "error calling: \"%s\" in \"%s\"\n", entry->u.function.argv[0], argv[0]);} /* End Function action_call_function */static void action_copy (const struct devfsd_notify_struct *info, const struct config_entry_struct *entry, const regmatch_t *regexpr, unsigned int numexpr)/* [SUMMARY] Copy permissions. <info> The devfs change. <entry> The config file entry. <regexpr> This list of subexpression (start, end) offsets within the device name. <numexpr> The number of elements in <<regexpr>>. [RETURNS] Nothing.*/{ mode_t new_mode; struct get_variable_info gv_info; struct stat source_stat, dest_stat; char source[STRING_LENGTH], destination[STRING_LENGTH]; if ( (info->type == DEVFSD_NOTIFY_CHANGE) && S_ISLNK (info->mode) ) return; gv_info.info = info; gv_info.devname = info->devname; snprintf (gv_info.devpath, sizeof (gv_info.devpath), "%s/%s", mount_point, info->devname); expand_expression (source, STRING_LENGTH, entry->u.copy.source, get_variable, &gv_info, gv_info.devname, regexpr, numexpr, NULL); expand_expression (destination, STRING_LENGTH, entry->u.copy.destination, get_variable, &gv_info, gv_info.devname, regexpr, numexpr, NULL); if (trace_level > 1) fprintf (stderr, "Copying %s to %s for \"%s\" | \"%s\"\n", source, destination, info->devname, gv_info.devpath); if ( !make_dir_tree (destination) ) { SYSLOG (LOG_ERR, "error making tree for: \"%s\"\n", destination); return; } if (lstat (source, &source_stat) != 0) return; if (lstat (destination, &dest_stat) != 0) dest_stat.st_mode = 0; new_mode = source_stat.st_mode & ~S_ISVTX; if (info->type == DEVFSD_NOTIFY_CREATE) new_mode |= S_ISVTX; else if ( (info->type == DEVFSD_NOTIFY_CHANGE) && (dest_stat.st_mode & S_ISVTX) ) new_mode |= S_ISVTX; if ( !copy_inode (destination, &dest_stat, new_mode, source,&source_stat) ) SYSLOG (LOG_ERR, "error copying: \"%s\" to \"%s\"\n", source, destination);} /* End Function action_copy */static void action_compat (const struct devfsd_notify_struct *info, unsigned int action)/* [SUMMARY] Process a compatibility request. <info> The devfs change. <action> The action to take. [RETURNS] Nothing.*/{ const char *compat_name = NULL; const char *dest_name = info->devname; char *ptr; char compat_buf[STRING_LENGTH], dest_buf[STRING_LENGTH]; static char function_name[] = "action_compat"; /* First construct compatibility name */ switch (action) { case AC_MKOLDCOMPAT: case AC_RMOLDCOMPAT: compat_name = get_old_name (info->devname, info->namelen, compat_buf, info->major, info->minor); break; case AC_MKNEWCOMPAT: case AC_RMNEWCOMPAT: if (strncmp (info->devname, "scsi/", 5) == 0) { int mode, host, bus, target, lun; sscanf (info->devname + 5, "host%d/bus%d/target%d/lun%d/", &host, &bus, &target, &lun); compat_name = compat_buf; snprintf (dest_buf, sizeof (dest_buf), "../%s", info->devname); dest_name = dest_buf; if (strncmp (ptr = (strrchr (info->devname, '/') + 1), "mt", 2) == 0) { char rewind = info->devname[info->namelen - 1]; if (rewind != 'n') rewind = '\0'; switch (ptr[2]) { default: mode = 0; break; case 'l': mode = 1; break; case 'm': mode = 2; break; case 'a': mode = 3; break; } sprintf (compat_buf, "st/c%db%dt%du%dm%d%c", host, bus, target, lun, mode, rewind); } else if (strcmp (info->devname + info->namelen - 7,"generic") == 0) sprintf (compat_buf, "sg/c%db%dt%du%d", host, bus, target, lun); else if (strcmp (info->devname + info->namelen - 2, "cd") == 0) sprintf (compat_buf, "sr/c%db%dt%du%d", host, bus, target, lun); else if (strcmp (info->devname + info->namelen - 4, "disc") == 0) sprintf (compat_buf, "sd/c%db%dt%du%d", host, bus, target, lun); else if (strncmp (ptr = (strrchr (info->devname, '/') + 1), "part", 4) == 0) sprintf ( compat_buf, "sd/c%db%dt%du%dp%d", host, bus, target, lun, atoi (ptr + 4) ); else compat_name = NULL; } else if (strncmp (info->devname, "ide/host", 8) == 0) { int host, bus, target, lun; sscanf (info->devname + 4, "host%d/bus%d/target%d/lun%d/", &host, &bus, &target, &lun); compat_name = compat_buf; snprintf (dest_buf, sizeof (dest_buf), "../%s", info->devname + 4); dest_name = dest_buf; if (strcmp (info->devname + info->namelen - 4, "disc") == 0) sprintf (compat_buf, "ide/hd/c%db%dt%du%d", host, bus, target, lun); else if (strncmp (ptr = (strrchr (info->devname, '/') + 1), "part", 4) == 0) sprintf ( compat_buf, "ide/hd/c%db%dt%du%dp%d", host, bus, target, lun, atoi (ptr + 4) ); else if (strcmp (info->devname + info->namelen - 2, "cd") == 0) sprintf (compat_buf, "ide/cd/c%db%dt%du%d", host, bus, target,lun); else if (strncmp (ptr = (strrchr (info->devname, '/') + 1), "mt", 2) == 0) snprintf (compat_buf, sizeof (compat_buf), "ide/mt/c%db%dt%du%d%s", host, bus, target, lun, ptr + 2); else compat_name = NULL; } break; } if (compat_name == NULL) return; /* Now decide what to do with it */ switch (action) { case AC_MKOLDCOMPAT: case AC_MKNEWCOMPAT: if (mksymlink (dest_name, compat_name) == 0) if (trace_level > 1) fprintf (stderr, "made symlink: \"%s\" for dev: %u,%u\n", compat_name, info->major, info->minor); break; case AC_RMOLDCOMPAT: case AC_RMNEWCOMPAT: if (unlink (compat_name) != 0) { SYSLOG (LOG_ERR, "%s: error unlinking: \"%s\"\t%s\n", function_name, compat_name, ERRSTRING); } else if (trace_level > 1) fprintf (stderr, "unlinked: \"%s\"\n", compat_name); break; }} /* End Function action_compat */static void do_restore (const char *dirname, int rootlen)/* [SUMMARY] Restore state from a directory. <dirname> The directory containing the backing store. <rootlen> The length of the root of the state directory hierarchy. [RETURNS] Nothing.*/{ DIR *dp; struct dirent *de; if ( ( dp = opendir (dirname) ) == NULL ) { SYSLOG (LOG_ERR, "Error opening directory \"%s\"\t%s\n", dirname, ERRSTRING); return; } while ( (de = readdir (dp) ) != NULL ) { mode_t new_mode; struct stat source_stat, dest_stat; char spath[STRING_LENGTH], dpath[STRING_LENGTH]; if ( (strcmp (de->d_name, ".") == 0) || (strcmp (de->d_name, "..") == 0) ) continue; snprintf (spath, sizeof spath, "%s/%s", dirname, de->d_name); if (lstat (spath, &source_stat) != 0) { SYSLOG (LOG_ERR, "Error lstat(2)ing file \"%s\"\t%s\n", spath, ERRSTRING); continue; } snprintf (dpath, sizeof dpath, "%s%s", mount_point, spath + rootlen); if (lstat (dpath, &dest_stat) != 0) dest_stat.st_mode = 0; new_mode = source_stat.st_mode & ~S_ISVTX; if ( S_ISLNK (source_stat.st_mode) || (source_stat.st_mode & S_ISVTX) ) copy_inode (dpath, &dest_stat, new_mode, spath, &source_stat); if ( S_ISDIR (source_stat.st_mode) ) do_restore (spath, rootlen); } closedir (dp);} /* End Function do_restore */static flag copy_inode (const char *destpath, const struct stat *dest_stat, mode_t new_mode, const char *sourcepath, const struct stat *source_stat)/* [SUMMARY] Copy an inode. <destpath> The destination path. An existing inode may be deleted. <dest_stat> The destination stat(2) information. <new_mode> The desired new mode for the destination. <sourcepath> The source path. <source_stat> The source stat(2) information. [RETURNS] TRUE on success, else FALSE.*/{ if ( (source_stat->st_mode & S_IFMT) == (dest_stat->st_mode & S_IFMT) ) { /* Same type */ if ( S_ISLNK (source_stat->st_mode) ) { int source_len, dest_len; char source_link[STRING_LENGTH], dest_link[STRING_LENGTH]; if ( ( source_len = readlink (sourcepath, source_link, STRING_LENGTH - 1) ) < 0 ) return (FALSE); source_link[source_len] = '\0'; if ( ( dest_len = readlink (destpath, dest_link, STRING_LENGTH - 1) ) < 0 ) return (FALSE); dest_link[dest_len] = '\0'; if ( (source_len != dest_len) || (strcmp (source_link, dest_link) != 0) ) { unlink (destpath); symlink (source_link, destpath); } return (TRUE); } /* Else not a symlink */ if (new_mode != dest_stat->st_mode) chmod (destpath, new_mode & ~S_IFMT); if ( (source_stat->st_uid != dest_stat->st_uid) || (source_stat->st_gid != dest_stat->st_gid) ) chown (destpath, source_stat->st_uid, source_stat->st_gid); return (TRUE); } /* Different types: unlink and create */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -