static int write_ar_header(archive_handle_t *handle) { char *fn; char fn_h[17]; /* 15 + "/" + NUL */ struct stat st; int fd; fn = llist_pop(&handle->accept); if (!fn) return -1; xstat(fn, &st); handle->file_header->mtime = st.st_mtime; handle->file_header->uid = st.st_uid; handle->file_header->gid = st.st_gid; handle->file_header->mode = st.st_mode; handle->file_header->size = st.st_size; handle->file_header->name = fn_h; //TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES... sprintf(fn_h, "%.15s/", bb_basename(fn)); output_ar_header(handle); fd = xopen(fn, O_RDONLY); bb_copyfd_exact_size(fd, handle->src_fd, st.st_size); close(fd); handle->offset += st.st_size; return 0; }
/* find_pid_by_name() * * Modified by Vladimir Oleynik for use with libbb/procps.c * This finds the pid of the specified process. * Currently, it's implemented by rummaging through * the proc filesystem. * * Returns a list of all matching PIDs * It is the caller's duty to free the returned pidlist. */ pid_t* find_pid_by_name(const char* procName) { pid_t* pidList; int i = 0; procps_status_t* p = NULL; pidList = xmalloc(sizeof(*pidList)); while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGV0))) { if ( /* we require comm to match and to not be truncated */ /* in Linux, if comm is 15 chars, it may be a truncated * name, so we don't allow that to match */ (!p->comm[sizeof(p->comm)-2] && strcmp(p->comm, procName) == 0) /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) /* TOOD: we can also try /proc/NUM/exe link, do we want that? */ ) { pidList = xrealloc(pidList, sizeof(*pidList) * (i+2)); pidList[i++] = p->pid; } } pidList[i] = 0; return pidList; }
static int comm_match(procps_status_t *p, const char *procName) { int argv1idx; const char *argv1; if (strncmp(p->comm, procName, 15) != 0) return 0; /* comm does not match */ /* In Linux, if comm is 15 chars, it is truncated. * (or maybe the name was exactly 15 chars, but there is * no way to know that) */ if (p->comm[14] == '\0') return 1; /* comm is not truncated - matches */ /* comm is truncated, but first 15 chars match. * This can be crazily_long_script_name.sh! * The telltale sign is basename(argv[1]) == procName */ if (!p->argv0) return 0; argv1idx = strlen(p->argv0) + 1; if (argv1idx >= p->argv_len) return 0; argv1 = p->argv0 + argv1idx; if (strcmp(bb_basename(argv1), procName) != 0) return 0; return 1; }
int sestatus_main(int argc, char **argv) { unsigned opts; const char *pol_path; int rc; opt_complementary = "?0"; /* no arguments are required. */ opts = getopt32(argv, "vb"); /* SELinux status: line */ rc = is_selinux_enabled(); if (rc < 0) goto error; printf(COL_FMT "%s\n", "SELinux status:", rc == 1 ? "enabled" : "disabled"); /* SELinuxfs mount: line */ if (!selinux_mnt) goto error; printf(COL_FMT "%s\n", "SELinuxfs mount:", selinux_mnt); /* Current mode: line */ rc = security_getenforce(); if (rc < 0) goto error; printf(COL_FMT "%s\n", "Current mode:", rc == 0 ? "permissive" : "enforcing"); /* Mode from config file: line */ if (selinux_getenforcemode(&rc) != 0) goto error; printf(COL_FMT "%s\n", "Mode from config file:", rc < 0 ? "disabled" : (rc == 0 ? "permissive" : "enforcing")); /* Policy version: line */ rc = security_policyvers(); if (rc < 0) goto error; printf(COL_FMT "%u\n", "Policy version:", rc); /* Policy from config file: line */ pol_path = selinux_policy_root(); if (!pol_path) goto error; printf(COL_FMT "%s\n", "Policy from config file:", bb_basename(pol_path)); if (opts & OPT_BOOLEAN) display_boolean(); if (opts & OPT_VERBOSE) display_verbose(); return 0; error: bb_perror_msg_and_die("libselinux returns unknown state"); }
/* Is this a valid filename (upper/lower alpha, digits, * underscores, and hyphens only?) */ static bool invalid_name(const char *c) { c = bb_basename(c); while (*c && (isalnum(*c) || *c == '_' || *c == '-')) c++; return *c; /* TRUE (!0) if terminating NUL is not reached */ }
int mktemp_main(int argc UNUSED_PARAM, char **argv) { const char *path; char *chp; unsigned opts; enum { OPT_d = 1 << 0, OPT_q = 1 << 1, OPT_t = 1 << 2, OPT_p = 1 << 3, OPT_u = 1 << 4, }; path = getenv("TMPDIR"); if (!path || path[0] == '\0') path = "/tmp"; opt_complementary = "?1"; /* 1 argument max */ opts = getopt32(argv, "dqtp:u", &path); chp = argv[optind]; if (!chp) { /* GNU coreutils 8.4: * bare "mktemp" -> "mktemp -t tmp.XXXXXX" */ chp = xstrdup("tmp.XXXXXX"); opts |= OPT_t; } #if 0 /* Don't allow directory separator in template */ if ((opts & OPT_t) && bb_basename(chp) != chp) { errno = EINVAL; goto error; } #endif if (opts & (OPT_t|OPT_p)) chp = concat_path_file(path, chp); if (opts & OPT_u) { chp = mktemp(chp); if (chp[0] == '\0') goto error; } else if (opts & OPT_d) { if (mkdtemp(chp) == NULL) goto error; } else { if (mkstemp(chp) < 0) goto error; } puts(chp); return EXIT_SUCCESS; error: if (opts & OPT_q) return EXIT_FAILURE; /* don't use chp as it gets mangled in case of error */ bb_perror_nomsg_and_die(); }
/* This finds the pid of the specified process. * Currently, it's implemented by rummaging through * the proc filesystem. * * Returns a list of all matching PIDs * It is the caller's duty to free the returned pidlist. * * Modified by Vladimir Oleynik for use with libbb/procps.c */ pid_t* FAST_FUNC find_pid_by_name(const char *procName) { pid_t* pidList; int i = 0; procps_status_t* p = NULL; pidList = xzalloc(sizeof(*pidList)); while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) { if (comm_match(p, procName) /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) /* or we require /proc/PID/exe link to match */ || (p->exe && strcmp(bb_basename(p->exe), procName) == 0) ) { pidList = xrealloc_vector(pidList, 2, i); pidList[i++] = p->pid; } } pidList[i] = 0; return pidList; }
int modinfo_main(int argc UNUSED_PARAM, char **argv) { struct modinfo_env env; char name[MODULE_NAME_LEN]; struct utsname uts; parser_t *parser; char *colon, *tokens[2]; unsigned opts; unsigned i; env.field = NULL; opt_complementary = "-1"; /* minimum one param */ opts = getopt32(argv, "nladvAsDumpF:0", &env.field); env.tags = opts & OPT_TAGS ? opts & OPT_TAGS : OPT_TAGS; argv += optind; uname(&uts); parser = config_open2( xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, uts.release, CONFIG_DEFAULT_DEPMOD_FILE), xfopen_for_read ); while (config_read(parser, tokens, 2, 1, "# \t", PARSE_NORMAL)) { colon = last_char_is(tokens[0], ':'); if (colon == NULL) continue; *colon = '\0'; filename2modname(bb_basename(tokens[0]), name); for (i = 0; argv[i]; i++) { if (fnmatch(argv[i], name, 0) == 0) { modinfo(tokens[0], uts.release, &env); argv[i] = (char *) ""; } } } if (ENABLE_FEATURE_CLEAN_UP) config_close(parser); for (i = 0; argv[i]; i++) { if (argv[i][0]) { modinfo(argv[i], uts.release, &env); } } return 0; }
int rmmod_main(int argc UNUSED_PARAM, char **argv) { int n, err; unsigned flags = O_NONBLOCK | O_EXCL; /* Parse command line. */ n = getopt32(argv, "wfas"); // -s ignored argv += optind; if (n & 1) // --wait flags &= ~O_NONBLOCK; if (n & 2) // --force flags |= O_TRUNC; if (n & 4) { /* Unload _all_ unused modules via NULL delete_module() call */ err = bb_delete_module(NULL, flags); if (err && err != EFAULT) bb_perror_msg_and_die("rmmod"); return EXIT_SUCCESS; } if (!*argv) bb_show_usage(); n = ENABLE_FEATURE_2_4_MODULES && get_linux_version_code() < KERNEL_VERSION(2,6,0); while (*argv) { char modname[MODULE_NAME_LEN]; const char *bname; bname = bb_basename(*argv++); if (n) safe_strncpy(modname, bname, MODULE_NAME_LEN); else filename2modname(bname, modname); err = bb_delete_module(modname, flags); if (err) bb_perror_msg_and_die("can't unload module '%s'", modname); } return EXIT_SUCCESS; }
static void display_verbose(void) { security_context_t con, _con; char *fc[50], *pc[50], *cterm; pid_t *pidList; int i; read_config(pc, ARRAY_SIZE(pc), fc, ARRAY_SIZE(fc)); /* process contexts */ puts("\nProcess contexts:"); /* current context */ if (getcon(&con) == 0) { printf(COL_FMT "%s\n", "Current context:", con); if (ENABLE_FEATURE_CLEAN_UP) freecon(con); } /* /sbin/init context */ if (getpidcon(1, &con) == 0) { printf(COL_FMT "%s\n", "Init context:", con); if (ENABLE_FEATURE_CLEAN_UP) freecon(con); } /* [process] context */ for (i = 0; pc[i] != NULL; i++) { pidList = find_pid_by_name(bb_basename(pc[i])); if (pidList[0] > 0 && getpidcon(pidList[0], &con) == 0) { printf(COL_FMT "%s\n", pc[i], con); if (ENABLE_FEATURE_CLEAN_UP) freecon(con); } if (ENABLE_FEATURE_CLEAN_UP) free(pidList); } /* files contexts */ puts("\nFile contexts:"); cterm = ttyname(0); puts(cterm); if (cterm && lgetfilecon(cterm, &con) >= 0) { printf(COL_FMT "%s\n", "Controlling term:", con); if (ENABLE_FEATURE_CLEAN_UP) freecon(con); } for (i=0; fc[i] != NULL; i++) { struct stat stbuf; if (lgetfilecon(fc[i], &con) < 0) continue; if (lstat(fc[i], &stbuf) == 0) { if (S_ISLNK(stbuf.st_mode)) { if (getfilecon(fc[i], &_con) >= 0) { printf(COL_FMT "%s -> %s\n", fc[i], _con, con); if (ENABLE_FEATURE_CLEAN_UP) freecon(_con); } } else { printf(COL_FMT "%s\n", fc[i], con); } } if (ENABLE_FEATURE_CLEAN_UP) freecon(con); } }
int install_main(int argc, char **argv) { struct stat statbuf; mode_t mode; uid_t uid; gid_t gid; char *arg, *last; const char *gid_str; const char *uid_str; const char *mode_str; int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; int opts; int min_args = 1; int ret = EXIT_SUCCESS; int isdir = 0; #if ENABLE_SELINUX security_context_t scontext; bool use_default_selinux_context = 1; #endif enum { OPT_c = 1 << 0, OPT_v = 1 << 1, OPT_b = 1 << 2, OPT_MKDIR_LEADING = 1 << 3, OPT_DIRECTORY = 1 << 4, OPT_PRESERVE_TIME = 1 << 5, OPT_STRIP = 1 << 6, OPT_GROUP = 1 << 7, OPT_MODE = 1 << 8, OPT_OWNER = 1 << 9, #if ENABLE_SELINUX OPT_SET_SECURITY_CONTEXT = 1 << 10, OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11, #endif }; #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS applet_long_options = install_longopts; #endif opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); /* -c exists for backwards compatibility, it's needed */ /* -v is ignored ("print name of each created directory") */ /* -b is ignored ("make a backup of each existing destination file") */ opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"), &gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext)); argc -= optind; argv += optind; #if ENABLE_SELINUX if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) { selinux_or_die(); use_default_selinux_context = 0; if (opts & OPT_PRESERVE_SECURITY_CONTEXT) { copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; } if (opts & OPT_SET_SECURITY_CONTEXT) { setfscreatecon_or_die(scontext); copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT; } } #endif /* preserve access and modification time, this is GNU behaviour, * BSD only preserves modification time */ if (opts & OPT_PRESERVE_TIME) { copy_flags |= FILEUTILS_PRESERVE_STATUS; } mode = 0755; /* GNU coreutils 6.10 compat */ if (opts & OPT_MODE) bb_parse_mode(mode_str, &mode); uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); last = argv[argc - 1]; if (!(opts & OPT_DIRECTORY)) { argv[argc - 1] = NULL; min_args++; /* coreutils install resolves link in this case, don't use lstat */ isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode); } if (argc < min_args) bb_show_usage(); while ((arg = *argv++) != NULL) { char *dest = last; if (opts & OPT_DIRECTORY) { dest = arg; /* GNU coreutils 6.9 does not set uid:gid * on intermediate created directories * (only on last one) */ if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) { ret = EXIT_FAILURE; goto next; } } else { if (opts & OPT_MKDIR_LEADING) { char *ddir = xstrdup(dest); bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR); /* errors are not checked. copy_file * will fail if dir is not created. */ free(ddir); } if (isdir) dest = concat_path_file(last, bb_basename(arg)); if (copy_file(arg, dest, copy_flags) != 0) { /* copy is not made */ ret = EXIT_FAILURE; goto next; } if (opts & OPT_STRIP) { char *args[4]; args[0] = (char*)"strip"; args[1] = (char*)"-p"; /* -p --preserve-dates */ args[2] = dest; args[3] = NULL; if (spawn_and_wait(args)) { bb_perror_msg("strip"); ret = EXIT_FAILURE; } } } /* Set the file mode (always, not only with -m). * GNU coreutils 6.10 is not affected by umask. */ if (chmod(dest, mode) == -1) { bb_perror_msg("can't change %s of %s", "permissions", dest); ret = EXIT_FAILURE; } #if ENABLE_SELINUX if (use_default_selinux_context) setdefaultfilecon(dest); #endif /* Set the user and group id */ if ((opts & (OPT_OWNER|OPT_GROUP)) && lchown(dest, uid, gid) == -1 ) { bb_perror_msg("can't change %s of %s", "ownership", dest); ret = EXIT_FAILURE; } next: if (ENABLE_FEATURE_CLEAN_UP && isdir) free(dest); } return ret; }
int microcom_main(int argc UNUSED_PARAM, char **argv) { int sfd; int nfd; struct pollfd pfd[2]; struct termios tio0, tiosfd, tio; char *device_lock_file; enum { OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@ OPT_s = 1 << 1, // baudrate OPT_d = 1 << 2, // wait for device response, ms OPT_t = 1 << 3, // timeout, ms }; speed_t speed = 9600; int delay = -1; int timeout = -1; unsigned opts; // fetch options opt_complementary = "=1:s+:d+:t+"; // exactly one arg, numeric options opts = getopt32(argv, "Xs:d:t:", &speed, &delay, &timeout); // argc -= optind; argv += optind; // try to create lock file in /var/lock device_lock_file = (char *)bb_basename(argv[0]); device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file); sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); if (sfd < 0) { // device already locked -> bail out if (errno == EEXIST) bb_perror_msg_and_die("can't create %s", device_lock_file); // can't create lock -> don't care if (ENABLE_FEATURE_CLEAN_UP) free(device_lock_file); device_lock_file = NULL; } else { // %4d to make concurrent mgetty (if any) happy. // Mgetty treats 4-bytes lock files as binary, // not text, PID. Making 5+ char file. Brrr... fdprintf(sfd, "%4d\n", getpid()); close(sfd); } // setup signals bb_signals(0 + (1 << SIGHUP) + (1 << SIGINT) + (1 << SIGTERM) + (1 << SIGPIPE) , signal_handler); // error exit code if we fail to open the device signalled = 1; // open device sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK); if (sfd < 0) goto done; fcntl(sfd, F_SETFL, 0); // put device to "raw mode" xget1(sfd, &tio, &tiosfd); // set device speed cfsetspeed(&tio, tty_value_to_baud(speed)); if (xset1(sfd, &tio, argv[0])) goto done; // put stdin to "raw mode" (if stdin is a TTY), // handle one character at a time if (isatty(STDIN_FILENO)) { xget1(STDIN_FILENO, &tio, &tio0); if (xset1(STDIN_FILENO, &tio, "stdin")) goto done; } // main loop: check with poll(), then read/write bytes across pfd[0].fd = sfd; pfd[0].events = POLLIN; pfd[1].fd = STDIN_FILENO; pfd[1].events = POLLIN; signalled = 0; nfd = 2; while (!signalled && safe_poll(pfd, nfd, timeout) > 0) { if (nfd > 1 && pfd[1].revents) { char c; // read from stdin -> write to device if (safe_read(STDIN_FILENO, &c, 1) < 1) { // don't poll stdin anymore if we got EOF/error nfd--; goto skip_write; } // do we need special processing? if (!(opts & OPT_X)) { // ^@ sends Break if (VINTR == c) { tcsendbreak(sfd, 0); goto skip_write; } // ^X exits if (24 == c) break; } write(sfd, &c, 1); if (delay >= 0) safe_poll(pfd, 1, delay); skip_write: ; } if (pfd[0].revents) { #define iobuf bb_common_bufsiz1 ssize_t len; // read from device -> write to stdout len = safe_read(sfd, iobuf, sizeof(iobuf)); if (len > 0) full_write(STDOUT_FILENO, iobuf, len); else { // EOF/error -> bail out signalled = SIGHUP; break; } } } // restore device mode tcsetattr(sfd, TCSAFLUSH, &tiosfd); if (isatty(STDIN_FILENO)) tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); done: if (device_lock_file) unlink(device_lock_file); return signalled; }
} } static int FAST_FUNC config_file_action(const char *filename, struct stat *statbuf UNUSED_PARAM, void *userdata UNUSED_PARAM, int depth) { char *tokens[3]; parser_t *p; struct module_entry *m; int rc = TRUE; const char *base, *ext; /* Skip files that begin with a "." */ base = bb_basename(filename); if (base[0] == '.') goto error; /* "man modprobe.d" from kmod version 22 suggests * that we shouldn't recurse into /etc/modprobe.d/dir/ * _subdirectories_: */ if (depth > 1) return SKIP; /* stop recursing */ //TODO: instead, can use dirAction in recursive_action() to SKIP dirs //on depth == 1 level. But that's more code... /* In dir recursion, skip files that do not end with a ".conf" * depth==0: read_config("modules.{symbols,alias}") must work, * "include FILE_NOT_ENDING_IN_CONF" must work too.
int microcom_main(int argc, char **argv) { struct pollfd pfd[2]; #define sfd (pfd[1].fd) char *device_lock_file = NULL; const char *s; const char *opt_s = "9600"; unsigned speed; int len; int exitcode = 1; struct termios tio0, tiosfd, tio; getopt32(argv, "s:", &opt_s); argc -= optind; argv += optind; if (!argv[0]) bb_show_usage(); speed = xatou(opt_s); // try to create lock file in /var/lock s = bb_basename(argv[0]); if (!s[0]) { errno = ENODEV; bb_perror_msg_and_die("can't lock device"); } device_lock_file = xasprintf("/var/lock/LCK..%s", s); sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); if (sfd < 0) { if (ENABLE_FEATURE_CLEAN_UP) free(device_lock_file); device_lock_file = NULL; if (errno == EEXIST) bb_perror_msg_and_die("can't lock device"); // We don't abort on other errors: /var/lock can be // non-writable or non-existent } else { // %4d to make mgetty happy. It treats 4-bytes lock files as binary, // not text, PID. Making 5+ char file. Brrr... s = xasprintf("%4d\n", getpid()); write(sfd, s, strlen(s)); if (ENABLE_FEATURE_CLEAN_UP) free((char*)s); close(sfd); } // open device sfd = open(argv[0], O_RDWR); if (sfd < 0) { bb_perror_msg("can't open device"); goto unlock_and_exit; } // put stdin to "raw mode", handle one character at a time tcgetattr(STDIN_FILENO, &tio0); tio = tio0; tio.c_lflag &= ~(ICANON|ECHO); tio.c_iflag &= ~(IXON|ICRNL); tio.c_oflag &= ~(ONLCR); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(STDIN_FILENO, TCSANOW, &tio)) { bb_perror_msg("can't tcsetattr for %s", "stdin"); goto unlock_and_exit; } /* same thing for modem (plus: set baud rate) - TODO: make CLI option */ tcgetattr(sfd, &tiosfd); tio = tiosfd; tio.c_lflag &= ~(ICANON|ECHO); tio.c_iflag &= ~(IXON|ICRNL); tio.c_oflag &= ~(ONLCR); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; cfsetispeed(&tio, tty_value_to_baud(speed)); cfsetospeed(&tio, tty_value_to_baud(speed)); if (tcsetattr(sfd, TCSANOW, &tio)) { bb_perror_msg("can't tcsetattr for %s", "device"); goto unlock_and_exit; } // disable SIGINT signal(SIGINT, SIG_IGN); // drain stdin tcflush(STDIN_FILENO, TCIFLUSH); printf("connected to '%s' (%d bps), exit with ctrl-X...\r\n", argv[0], speed); // main loop: check with poll(), then read/write bytes across pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; /*pfd[1].fd = sfd;*/ pfd[1].events = POLLIN; while (1) { int i; safe_poll(pfd, 2, -1); for (i = 0; i < 2; ++i) { if (pfd[i].revents & POLLIN) { len = read(pfd[i].fd, bb_common_bufsiz1, COMMON_BUFSIZE); if (len > 0) { if (!i && 24 == bb_common_bufsiz1[0]) goto done; // ^X exits write(pfd[1-i].fd, bb_common_bufsiz1, len); } } } } done: tcsetattr(sfd, TCSANOW, &tiosfd); tcsetattr(STDIN_FILENO, TCSANOW, &tio0); tcflush(STDIN_FILENO, TCIFLUSH); if (ENABLE_FEATURE_CLEAN_UP) close(sfd); exitcode = 0; unlock_and_exit: // delete lock file if (device_lock_file) { unlink(device_lock_file); if (ENABLE_FEATURE_CLEAN_UP) free(device_lock_file); } return exitcode; }
/* * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep. * It then fills every modules and aliases with their default options, found by parsing * modprobe.conf (or modules.conf, or conf.modules). */ static struct dep_t *build_dep(void) { int fd; struct utsname un; struct dep_t *first = NULL; struct dep_t *current = NULL; char *filename; int continuation_line = 0; int k_version; if (uname(&un)) bb_error_msg_and_die("can't determine kernel version"); k_version = 0; if (un.release[0] == '2') { k_version = un.release[2] - '0'; } filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, un.release); fd = open(filename, O_RDONLY); if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE, O_RDONLY); if (fd < 0) { bb_error_msg_and_die("cannot parse " CONFIG_DEFAULT_DEPMOD_FILE); } } while (reads(fd, line_buffer, sizeof(line_buffer))) { int l = strlen(line_buffer); char *p = 0; while (l > 0 && isspace(line_buffer[l-1])) { line_buffer[l-1] = '\0'; l--; } if (l == 0) { continuation_line = 0; continue; } /* Is this a new module dep description? */ if (!continuation_line) { /* find the dep beginning */ char *col = strchr(line_buffer, ':'); char *dot = col; if (col) { /* This line is a dep description */ const char *mods; char *modpath; char *mod; /* Find the beginning of the module file name */ *col = '\0'; mods = bb_basename(line_buffer); /* find the path of the module */ modpath = strchr(line_buffer, '/'); /* ... and this is the path */ if (!modpath) modpath = line_buffer; /* module with no path */ /* find the end of the module name in the file name */ if (ENABLE_FEATURE_2_6_MODULES && (k_version > 4) && (col[-3] == '.') && (col[-2] == 'k') && (col[-1] == 'o')) dot = col - 3; else if ((col[-2] == '.') && (col[-1] == 'o')) dot = col - 2; mod = xstrndup(mods, dot - mods); /* enqueue new module */ if (!current) { first = current = xzalloc(sizeof(struct dep_t)); } else { current->m_next = xzalloc(sizeof(struct dep_t)); current = current->m_next; } current->m_name = mod; current->m_path = xstrdup(modpath); /*current->m_options = NULL; - xzalloc did it*/ /*current->m_isalias = 0;*/ /*current->m_depcnt = 0;*/ /*current->m_deparr = 0;*/ /*current->m_next = 0;*/ p = col + 1; } else /* this line is not a dep description */ p = NULL; } else /* It's a dep description continuation */ p = line_buffer; /* p points to the first dependable module; if NULL, no dependable module */ if (p && (p = skip_whitespace(p))[0] != '\0') { char *end = &line_buffer[l-1]; const char *deps; char *dep; char *next; int ext = 0; while (isblank(*end) || (*end == '\\')) end--; do { /* search the end of the dependency */ next = strchr(p, ' '); if (next) { *next = '\0'; next--; } else next = end; /* find the beginning of the module file name */ deps = bb_basename(p); if (deps == p) deps = skip_whitespace(deps); /* find the end of the module name in the file name */ if (ENABLE_FEATURE_2_6_MODULES && (k_version > 4) && (next[-2] == '.') && (next[-1] == 'k') && (next[0] == 'o')) ext = 3; else if ((next[-1] == '.') && (next[0] == 'o')) ext = 2; /* Cope with blank lines */ if ((next-deps-ext+1) <= 0) continue; dep = xstrndup(deps, next - deps - ext + 1); /* Add the new dependable module name */ current->m_depcnt++; current->m_deparr = xrealloc(current->m_deparr, sizeof(char *) * current->m_depcnt); current->m_deparr[current->m_depcnt - 1] = dep; p = next + 2; } while (next < end); } /* is there other dependable module(s) ? */ continuation_line = (line_buffer[l-1] == '\\'); } /* while (reads(...)) */ close(fd); /* * First parse system-specific options and aliases * as they take precedence over the kernel ones. * >=2.6: we only care about modprobe.conf * <=2.4: we care about modules.conf and conf.modules */ if (ENABLE_FEATURE_2_6_MODULES && (fd = open("/etc/modprobe.conf", O_RDONLY)) < 0) if (ENABLE_FEATURE_2_4_MODULES && (fd = open("/etc/modules.conf", O_RDONLY)) < 0) if (ENABLE_FEATURE_2_4_MODULES) fd = open("/etc/conf.modules", O_RDONLY); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } /* Only 2.6 has a modules.alias file */ if (ENABLE_FEATURE_2_6_MODULES) { /* Parse kernel-declared module aliases */ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release); fd = open(filename, O_RDONLY); if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.alias", O_RDONLY); } if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } /* Parse kernel-declared symbol aliases */ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release); fd = open(filename, O_RDONLY); if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.symbols", O_RDONLY); } if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } } return first; }