static void connection_status(void) { /* "only 1 client max" desn't need this */ if (cmax > 1) bb_error_msg("status %u/%u", cnum, cmax); }
/* * Read commands until we are told to stop. */ static void doCommands(void) { const char *cp; char *endbuf, *newname, buf[USERSIZE]; int len, num1, num2, have1, have2; while (TRUE) { printf(": "); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) return; len = strlen(buf); if (len == 0) return; endbuf = &buf[len - 1]; if (*endbuf != '\n') { bb_error_msg("command line too long"); do { len = fgetc(stdin); } while ((len != EOF) && (len != '\n')); continue; } while ((endbuf > buf) && isblank(endbuf[-1])) endbuf--; *endbuf = '\0'; cp = buf; while (isblank(*cp)) cp++; have1 = FALSE; have2 = FALSE; if ((curNum == 0) && (lastNum > 0)) { curNum = 1; curLine = lines.next; } if (!getNum(&cp, &have1, &num1)) continue; while (isblank(*cp)) cp++; if (*cp == ',') { cp++; if (!getNum(&cp, &have2, &num2)) continue; if (!have1) num1 = 1; if (!have2) num2 = lastNum; have1 = TRUE; have2 = TRUE; } if (!have1) num1 = curNum; if (!have2) num2 = num1; switch (*cp++) { case 'a': addLines(num1 + 1); break; case 'c': deleteLines(num1, num2); addLines(num1); break; case 'd': deleteLines(num1, num2); break; case 'f': if (*cp && !isblank(*cp)) { bb_error_msg("bad file command"); break; } while (isblank(*cp)) cp++; if (*cp == '\0') { if (fileName) printf("\"%s\"\n", fileName); else printf("No file name\n"); break; } newname = strdup(cp); if (newname == NULL) { bb_error_msg("no memory for file name"); break; } if (fileName) free(fileName); fileName = newname; break; case 'i': addLines(num1); break; case 'k': while (isblank(*cp)) cp++; if ((*cp < 'a') || (*cp > 'a') || cp[1]) { bb_error_msg("bad mark name"); break; } marks[*cp - 'a'] = num2; break; case 'l': printLines(num1, num2, TRUE); break; case 'p': printLines(num1, num2, FALSE); break; case 'q': while (isblank(*cp)) cp++; if (have1 || *cp) { bb_error_msg("bad quit command"); break; } if (!dirty) return; printf("Really quit? "); fflush(stdout); buf[0] = '\0'; fgets(buf, sizeof(buf), stdin); cp = buf; while (isblank(*cp)) cp++; if ((*cp == 'y') || (*cp == 'Y')) return; break; case 'r': if (*cp && !isblank(*cp)) { bb_error_msg("bad read command"); break; } while (isblank(*cp)) cp++; if (*cp == '\0') { bb_error_msg("no file name"); break; } if (!have1) num1 = lastNum; if (readLines(cp, num1 + 1)) break; if (fileName == NULL) fileName = strdup(cp); break; case 's': subCommand(cp, num1, num2); break; case 'w': if (*cp && !isblank(*cp)) { bb_error_msg("bad write command"); break; } while (isblank(*cp)) cp++; if (!have1) { num1 = 1; num2 = lastNum; } if (*cp == '\0') cp = fileName; if (cp == NULL) { bb_error_msg("no file name specified"); break; } writeLines(cp, num1, num2); break; case 'z': switch (*cp) { case '-': printLines(curNum-21, curNum, FALSE); break; case '.': printLines(curNum-11, curNum+10, FALSE); break; default: printLines(curNum, curNum+21, FALSE); break; } break; case '.': if (have1) { bb_error_msg("no arguments allowed"); break; } printLines(curNum, curNum, FALSE); break; case '-': if (setCurNum(curNum - 1)) printLines(curNum, curNum, FALSE); break; case '=': printf("%d\n", num1); break; case '\0': if (have1) { printLines(num2, num2, FALSE); break; } if (setCurNum(curNum + 1)) printLines(curNum, curNum, FALSE); break; default: bb_error_msg("unimplemented command"); break; } } }
//TODO: use more efficient setvar() which takes a pointer to malloced "VAR=VAL" //string. hush naturally has it, and ash has setvareq(). //Here we can simply store "VAR=" at buffer start and store read data directly //after "=", then pass buffer to setvar() to consume. const char* FAST_FUNC shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), char **argv, const char *ifs, int read_flags, const char *opt_n, const char *opt_p, const char *opt_t, const char *opt_u ) { unsigned err; unsigned end_ms; /* -t TIMEOUT */ int fd; /* -u FD */ int nchars; /* -n NUM */ char **pp; char *buffer; struct termios tty, old_tty; const char *retval; int bufpos; /* need to be able to hold -1 */ int startword; smallint backslash; errno = err = 0; pp = argv; while (*pp) { if (!is_well_formed_var_name(*pp, '\0')) { /* Mimic bash message */ bb_error_msg("read: '%s': not a valid identifier", *pp); return (const char *)(uintptr_t)1; } pp++; } nchars = 0; /* if != 0, -n is in effect */ if (opt_n) { nchars = bb_strtou(opt_n, NULL, 10); if (nchars < 0 || errno) return "invalid count"; /* note: "-n 0": off (bash 3.2 does this too) */ } end_ms = 0; if (opt_t) { end_ms = bb_strtou(opt_t, NULL, 10); if (errno || end_ms > UINT_MAX / 2048) return "invalid timeout"; end_ms *= 1000; #if 0 /* even bash has no -t N.NNN support */ ts.tv_sec = bb_strtou(opt_t, &p, 10); ts.tv_usec = 0; /* EINVAL means number is ok, but not terminated by NUL */ if (*p == '.' && errno == EINVAL) { char *p2; if (*++p) { int scale; ts.tv_usec = bb_strtou(p, &p2, 10); if (errno) return "invalid timeout"; scale = p2 - p; /* normalize to usec */ if (scale > 6) return "invalid timeout"; while (scale++ < 6) ts.tv_usec *= 10; } } else if (ts.tv_sec < 0 || errno) { return "invalid timeout"; } if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ return "invalid timeout"; } #endif /* if 0 */ } fd = STDIN_FILENO; if (opt_u) { fd = bb_strtou(opt_u, NULL, 10); if (fd < 0 || errno) return "invalid file descriptor"; } if (opt_p && isatty(fd)) { fputs(opt_p, stderr); fflush_all(); } if (ifs == NULL) ifs = defifs; if (nchars || (read_flags & BUILTIN_READ_SILENT)) { tcgetattr(fd, &tty); old_tty = tty; if (nchars) { tty.c_lflag &= ~ICANON; // Setting it to more than 1 breaks poll(): // it blocks even if there's data. !?? //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; /* reads would block only if < 1 char is available */ tty.c_cc[VMIN] = 1; /* no timeout (reads block forever) */ tty.c_cc[VTIME] = 0; } if (read_flags & BUILTIN_READ_SILENT) { tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); } /* This forces execution of "restoring" tcgetattr later */ read_flags |= BUILTIN_READ_SILENT; /* if tcgetattr failed, tcsetattr will fail too. * Ignoring, it's harmless. */ tcsetattr(fd, TCSANOW, &tty); } retval = (const char *)(uintptr_t)0; startword = 1; backslash = 0; if (end_ms) /* NB: end_ms stays nonzero: */ end_ms = ((unsigned)monotonic_ms() + end_ms) | 1; buffer = NULL; bufpos = 0; do { char c; struct pollfd pfd[1]; int timeout; if ((bufpos & 0xff) == 0) buffer = xrealloc(buffer, bufpos + 0x101); timeout = -1; if (end_ms) { timeout = end_ms - (unsigned)monotonic_ms(); if (timeout <= 0) { /* already late? */ retval = (const char *)(uintptr_t)1; goto ret; } } /* We must poll even if timeout is -1: * we want to be interrupted if signal arrives, * regardless of SA_RESTART-ness of that signal! */ errno = 0; pfd[0].fd = fd; pfd[0].events = POLLIN; if (poll(pfd, 1, timeout) != 1) { /* timed out, or EINTR */ err = errno; retval = (const char *)(uintptr_t)1; goto ret; } if (read(fd, &buffer[bufpos], 1) != 1) { err = errno; retval = (const char *)(uintptr_t)1; break; } c = buffer[bufpos]; if (c == '\0') continue; if (backslash) { backslash = 0; if (c != '\n') goto put; continue; } if (!(read_flags & BUILTIN_READ_RAW) && c == '\\') { backslash = 1; continue; } if (c == '\n') break; /* $IFS splitting. NOT done if we run "read" * without variable names (bash compat). * Thus, "read" and "read REPLY" are not the same. */ if (argv[0]) { /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ const char *is_ifs = strchr(ifs, c); if (startword && is_ifs) { if (isspace(c)) continue; /* it is a non-space ifs char */ startword--; if (startword == 1) /* first one? */ continue; /* yes, it is not next word yet */ } startword = 0; if (argv[1] != NULL && is_ifs) { buffer[bufpos] = '\0'; bufpos = 0; setvar(*argv, buffer); argv++; /* can we skip one non-space ifs char? (2: yes) */ startword = isspace(c) ? 2 : 1; continue; } } put: bufpos++; } while (--nchars); if (argv[0]) { /* Remove trailing space $IFS chars */ while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL) continue; buffer[bufpos + 1] = '\0'; /* Use the remainder as a value for the next variable */ setvar(*argv, buffer); /* Set the rest to "" */ while (*++argv) setvar(*argv, ""); } else { /* Note: no $IFS removal */ buffer[bufpos] = '\0'; setvar("REPLY", buffer); } ret: free(buffer); if (read_flags & BUILTIN_READ_SILENT) tcsetattr(fd, TCSANOW, &old_tty); errno = err; return retval; }
static int prtdepend(const char *base_dir, const char *module_dir, int nflag) { FILE *dep = stdout; FILE *generic_string = stdout; MODULE **tbdep; MODULE *ptmod; int i; int ret = 0; int skipchars; /* For depmod -a in image of a tree */ char *tmdn; tmdn = concat_path_file(module_dir, "modules.dep"); if (!nflag) { dep = fopen(tmdn, "w"); } skipchars = strlen(base_dir); tbdep = (MODULE **)alloca(sizeof(MODULE) * n_modules); ptmod = modules; for (i = 0; i < n_modules; i++, ptmod++) { SYMBOL **undefs = ptmod->undefs.symtab; int n_undefs = ptmod->undefs.n_syms; int nbdepmod = 0; int nberr = 0; int e; int m; /* Don't print a dependency list for the _kernel_ ... */ if (strcmp(ptmod->name, "-") == 0) continue; /* Look for unresolved symbols in this module */ for (e = 0; e < n_undefs; e++, undefs++) { MODULE *mod = (*undefs)->module; if ((*undefs)->status == SYM_RESOLVED) { /* Resolved by self or exported kernel symbol */ if (strcmp(mod->name, ptmod->name) == 0 || strcmp(mod->name, "-") == 0) continue; /* No duplicate dependencies, please */ for (m = 0; m < nbdepmod; m++) { if (tbdep[m] == mod) break; } if (m == nbdepmod) tbdep[nbdepmod++] = mod; } else { /* Kludge to preserve old depmod behaviour without -u. * 2.4.13 change to keep going had the unwanted side * effect of always treating unresolved symbols as an * error. Use the error() routine but do not count * any errors. Remove in 2.5. */ if (!flag_quiet && nberr == 0) bb_error_msg("*** Unresolved symbols in %s", ptmod->name); if (!flag_quiet && flag_showerror) bb_error_msg("\t%s", (*undefs)->name); nberr++; if (flag_unresolved_error) ret = 1; } } fprintf(dep, "%s:", ptmod->name + skipchars); for (m = 0; m < nbdepmod; m++) { if (m != 0 /*&& (m & 3) == 0*/) fprintf(dep, " \\\n"); fprintf(dep, "\t%s", tbdep[m]->name + skipchars); } fprintf(dep, "\n\n"); } if (generic_string != stdout) fclose(generic_string); /* Close depfile last, it's timestamp is critical */ if (dep != stdout) fclose(dep); return ret; }
/* * Parse a line number argument if it is present. This is a sum * or difference of numbers, '.', '$', 'x, or a search string. * Returns TRUE if successful (whether or not there was a number). * Returns FALSE if there was a parsing error, with a message output. * Whether there was a number is returned indirectly, as is the number. * The character pointer which stopped the scan is also returned. */ static int getNum(const char **retcp, int *retHaveNum, int *retNum) { const char *cp; char *endStr, str[USERSIZE]; int haveNum, value, num, sign; cp = *retcp; haveNum = FALSE; value = 0; sign = 1; while (TRUE) { while (isblank(*cp)) cp++; switch (*cp) { case '.': haveNum = TRUE; num = curNum; cp++; break; case '$': haveNum = TRUE; num = lastNum; cp++; break; case '\'': cp++; if ((*cp < 'a') || (*cp > 'z')) { bb_error_msg("bad mark name"); return FALSE; } haveNum = TRUE; num = marks[*cp++ - 'a']; break; case '/': strcpy(str, ++cp); endStr = strchr(str, '/'); if (endStr) { *endStr++ = '\0'; cp += (endStr - str); } else cp = ""; num = searchLines(str, curNum, lastNum); if (num == 0) return FALSE; haveNum = TRUE; break; default: if (!isdigit(*cp)) { *retcp = cp; *retHaveNum = haveNum; *retNum = value; return TRUE; } num = 0; while (isdigit(*cp)) num = num * 10 + *cp++ - '0'; haveNum = TRUE; break; } value += num * sign; while (isblank(*cp)) cp++; switch (*cp) { case '-': sign = -1; cp++; break; case '+': sign = 1; cp++; break; default: *retcp = cp; *retHaveNum = haveNum; *retNum = value; return TRUE; } } }
int i2cget_main(int argc UNUSED_PARAM, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1); const char *const optstr = "fy"; int bus_num, bus_addr, data_addr = -1, status; int mode = I2C_SMBUS_BYTE, pec = 0, fd; unsigned opts; opt_complementary = "-2:?4"; /* from 2 to 4 args */ opts = getopt32(argv, optstr); argv += optind; bus_num = i2c_bus_lookup(argv[0]); bus_addr = i2c_parse_bus_addr(argv[1]); if (argv[2]) { data_addr = i2c_parse_data_addr(argv[2]); mode = I2C_SMBUS_BYTE_DATA; if (argv[3]) { switch (argv[3][0]) { case 'b': /* Already set */ break; case 'w': mode = I2C_SMBUS_WORD_DATA; break; case 'c': mode = I2C_SMBUS_BYTE; break; default: bb_error_msg("invalid mode"); bb_show_usage(); } pec = argv[3][1] == 'p'; } } fd = i2c_dev_open(bus_num); check_read_funcs(fd, mode, data_addr, pec); i2c_set_slave_addr(fd, bus_addr, opts & opt_f); if (!(opts & opt_y)) confirm_action(bus_addr, mode, data_addr, pec); if (pec) i2c_set_pec(fd, 1); switch (mode) { case I2C_SMBUS_BYTE: if (data_addr >= 0) { status = i2c_smbus_write_byte(fd, data_addr); if (status < 0) bb_error_msg("warning - write failed"); } status = i2c_smbus_read_byte(fd); break; case I2C_SMBUS_WORD_DATA: status = i2c_smbus_read_word_data(fd, data_addr); break; default: /* I2C_SMBUS_BYTE_DATA */ status = i2c_smbus_read_byte_data(fd, data_addr); } close(fd); if (status < 0) bb_perror_msg_and_die("read failed"); printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status); return 0; }
/* * Read the symbols in an object and register them in the symbol table. * Return -1 if there is an error. */ static int loadobj(const char *objname, int ignore_suffix) { static char *currdir; static int currdir_len; int fp; MODULE *mod; SYMBOL *undefs[5000]; SYMBOL *defsym[5000]; struct obj_file *f; struct obj_section *sect; struct obj_symbol *objsym; int i; int is_2_2; int ksymtab; int len; int n_undefs = 0; int n_defsym = 0; char *p; void *image; unsigned long m_size; p = strrchr(objname, '/'); len = 1 + (int)(p - objname); if ((fp = open(objname, O_RDONLY)) < 0) return 1; if (!(f = obj_load(fp, ET_REL, objname))) { close(fp); return -1; } close(fp); /* * Allow arch code to define _GLOBAL_OFFSET_TABLE_ */ arch_create_got(f); /* * If we have changed base directory * then use the defined symbols from modules * in the _same_ directory to resolve whatever * undefined symbols there are. * * This strategy ensures that we will have * as correct dependencies as possible, * even if the same symbol is defined by * other modules in other directories. */ if (currdir_len != len || currdir == NULL || strncmp(currdir, objname, len) != 0) { if (currdir) resolve(); currdir = bb_xstrdup(objname); currdir_len = len; } mod = modules + n_modules++; mod->name = bb_xstrdup(objname); if ((sect = obj_find_section(f, "__ksymtab")) != NULL) ksymtab = sect->idx; /* Only in 2.2 (or at least not 2.0) */ else ksymtab = -1; if (sect || obj_find_section(f, ".modinfo") || obj_find_symbol(f, "__this_module")) is_2_2 = 1; else is_2_2 = 0; for (i = 0; i < HASH_BUCKETS; ++i) { for (objsym = f->symtab[i]; objsym; objsym = objsym->next) { if (objsym->secidx == SHN_UNDEF) { if (ELFW(ST_BIND)(objsym->info) != STB_WEAK && objsym->r_type /* assumes that R_arch_NONE is always 0 on all arch */) { undefs[n_undefs++] = addsym(objsym->name, mod, SYM_UNDEF, ignore_suffix); } continue; } /* else */ if (is_2_2 && ksymtab != -1) { /* A 2.2 module using EXPORT_SYMBOL */ if (objsym->secidx == ksymtab && ELFW(ST_BIND)(objsym->info) == STB_GLOBAL) { /* Ignore leading "__ksymtab_" */ defsym[n_defsym++] = addsym(objsym->name + 10, mod, SYM_DEFINED, ignore_suffix); } continue; } /* else */ if (is_2_2) { /* * A 2.2 module _not_ using EXPORT_SYMBOL * It might still want to export symbols, * although strictly speaking it shouldn't... * (Seen in pcmcia) */ if (ELFW(ST_BIND)(objsym->info) == STB_GLOBAL) { defsym[n_defsym++] = addsym(objsym->name, mod, SYM_DEFINED, ignore_suffix); } continue; } /* else */ /* Not undefined or 2.2 ksymtab entry */ if (objsym->secidx < SHN_LORESERVE /* * The test below is removed for 2.0 compatibility * since some 2.0-modules (correctly) hide the * symbols it exports via register_symtab() */ /* && ELFW(ST_BIND)(objsym->info) == STB_GLOBAL */ ) { defsym[n_defsym++] = addsym(objsym->name, mod, SYM_DEFINED, ignore_suffix); } } } /* * Finalize the information about a module. */ mod->defsym.n_syms = n_defsym; if (n_defsym > 0) { int size = n_defsym * sizeof(SYMBOL *); mod->defsym.symtab = (SYMBOL **)xmalloc(size); memcpy(mod->defsym.symtab, defsym, size); } else mod->defsym.symtab = NULL; mod->undefs.n_syms = n_undefs; if (n_undefs > 0) { int size = n_undefs * sizeof(SYMBOL *); mod->undefs.symtab = (SYMBOL **) xmalloc(size); memcpy(mod->undefs.symtab, undefs, size); mod->resolved = 0; } else { mod->undefs.symtab = NULL; mod->resolved = 1; } /* Do a pseudo relocation to base address 0x1000 (arbitrary). * All undefined symbols are treated as absolute 0. This builds * enough of a module to allow extraction of internal data such * as device tables. */ obj_clear_undefineds(f); obj_allocate_commons(f); m_size = obj_load_size(f); if (!obj_relocate(f, 0x1000)) { bb_error_msg("depmod obj_relocate failed\n"); return(-1); } extract_generic_string(f, mod); image = xmalloc(m_size); obj_create_image(f, image); free(image); obj_free(f); return 0; }
int su_main(int argc UNUSED_PARAM, char **argv) { unsigned flags; char *opt_shell = NULL; char *opt_command = NULL; const char *opt_username = "******"; struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; #if ENABLE_FEATURE_UTMP char user_buf[64]; #endif const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); //argc -= optind; argv += optind; if (argv[0] && LONE_DASH(argv[0])) { flags |= SU_OPT_l; argv++; } /* get user if specified */ if (argv[0]) { opt_username = argv[0]; argv++; } if (ENABLE_FEATURE_SU_SYSLOG) { /* The utmp entry (via getlogin) is probably the best way to * identify the user, especially if someone su's from a su-shell. * But getlogin can fail -- usually due to lack of utmp entry. * in this case resort to getpwuid. */ #if ENABLE_FEATURE_UTMP old_user = user_buf; if (getlogin_r(user_buf, sizeof(user_buf)) != 0) #endif { pw = getpwuid(cur_uid); old_user = pw ? xstrdup(pw->pw_name) : ""; } tty = xmalloc_ttyname(2); if (!tty) { tty = "none"; } openlog(applet_name, 0, LOG_AUTH); } pw = xgetpwnam(opt_username); if (cur_uid == 0 || ask_and_check_password(pw) > 0) { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); } else { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '-', tty, old_user, opt_username); bb_do_delay(LOGIN_FAIL_DELAY); bb_error_msg_and_die("incorrect password"); } if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { closelog(); } if (!opt_shell && (flags & SU_OPT_mp)) { /* -s SHELL is not given, but "preserve env" opt is */ opt_shell = getenv("SHELL"); } #if ENABLE_FEATURE_SU_CHECKS_SHELLS if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) { /* The user being su'd to has a nonstandard shell, and so is * probably a uucp account or has restricted access. Don't * compromise the account by allowing access with a standard * shell. */ bb_error_msg("using restricted shell"); opt_shell = NULL; /* ignore -s PROG */ } /* else: user can run whatever he wants via "su -s PROG USER". * This is safe since PROG is run under user's uid/gid. */ #endif if (!opt_shell) opt_shell = pw->pw_shell; change_identity(pw); setup_environment(opt_shell, ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV) + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR), pw); IF_SELINUX(set_current_security_context(NULL);)
int kill_main(int argc, char **argv) { char *arg; pid_t pid; int signo = SIGTERM, errors = 0, quiet = 0; #if !ENABLE_KILLALL && !ENABLE_KILLALL5 #define killall 0 #define killall5 0 #else /* How to determine who we are? find 3rd char from the end: * kill, killall, killall5 * ^i ^a ^l - it's unique * (checking from the start is complicated by /bin/kill... case) */ const char char3 = argv[0][strlen(argv[0]) - 3]; #define killall (ENABLE_KILLALL && char3 == 'a') #define killall5 (ENABLE_KILLALL5 && char3 == 'l') #endif /* Parse any options */ argc--; arg = *++argv; if (argc < 1 || arg[0] != '-') { goto do_it_now; } /* The -l option, which prints out signal names. * Intended usage in shell: * echo "Died of SIG`kill -l $?`" * We try to mimic what kill from coreutils-6.8 does */ if (arg[1] == 'l' && arg[2] == '\0') { if (argc == 1) { /* Print the whole signal list */ print_signames(); return 0; } /* -l <sig list> */ while ((arg = *++argv)) { if (isdigit(arg[0])) { signo = bb_strtou(arg, NULL, 10); if (errno) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } /* Exitcodes >= 0x80 are to be treated * as "killed by signal (exitcode & 0x7f)" */ puts(get_signame(signo & 0x7f)); /* TODO: 'bad' signal# - coreutils says: * kill: 127: invalid signal * we just print "127" instead */ } else { signo = get_signum(arg); if (signo < 0) { bb_error_msg("unknown signal '%s'", arg); return EXIT_FAILURE; } printf("%d\n", signo); } } /* If they specified -l, we are all done */ return EXIT_SUCCESS; } /* The -q quiet option */ if (killall && arg[1] == 'q' && arg[2] == '\0') { quiet = 1; arg = *++argv; argc--; if (argc < 1) bb_show_usage(); if (arg[0] != '-') goto do_it_now; } /* -SIG */ signo = get_signum(&arg[1]); if (signo < 0) { /* || signo > MAX_SIGNUM ? */ bb_error_msg("bad signal name '%s'", &arg[1]); return EXIT_FAILURE; } arg = *++argv; argc--; do_it_now: if (killall5) { pid_t sid; procps_status_t* p = NULL; /* Now stop all processes */ kill(-1, SIGSTOP); /* Find out our own session id */ pid = getpid(); sid = getsid(pid); /* Now kill all processes except our session */ while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { if (p->sid != sid && p->pid != pid && p->pid != 1) kill(p->pid, signo); } /* And let them continue */ kill(-1, SIGCONT); return 0; } /* Pid or name is required for kill/killall */ if (argc < 1) { bb_error_msg("you need to specify whom to kill"); return EXIT_FAILURE; } if (killall) { /* Looks like they want to do a killall. Do that */ pid = getpid(); while (arg) { pid_t* pidList; pidList = find_pid_by_name(arg); if (*pidList == 0) { errors++; if (!quiet) bb_error_msg("%s: no process killed", arg); } else { pid_t *pl; for (pl = pidList; *pl; pl++) { if (*pl == pid) continue; if (kill(*pl, signo) == 0) continue; errors++; if (!quiet) bb_perror_msg("cannot kill pid %u", (unsigned)*pl); } } free(pidList); arg = *++argv; } return errors; } /* Looks like they want to do a kill. Do that */ while (arg) { /* Support shell 'space' trick */ if (arg[0] == ' ') arg++; pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("bad pid '%s'", arg); errors++; } else if (kill(pid, signo) != 0) { bb_perror_msg("cannot kill pid %d", (int)pid); errors++; } arg = *++argv; } return errors; }
int sulogin_main(int argc UNUSED_PARAM, char **argv) { int timeout = 0; struct passwd *pwd; const char *shell; /* Note: sulogin is not a suid app. It is meant to be run by init * for single user / emergency mode. init starts it as root. * Normal users (potentially malisious ones) can only run it under * their UID, therefore no paranoia here is warranted: * $LD_LIBRARY_PATH in env, TTY = /dev/sda * are no more dangerous here than in e.g. cp applet. */ logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); getopt32(argv, "t:+", &timeout); argv += optind; if (argv[0]) { close(0); close(1); dup(xopen(argv[0], O_RDWR)); close(2); dup(0); } pwd = getpwuid(0); if (!pwd) { bb_error_msg_and_die("no password entry for root"); } while (1) { int r; r = ask_and_check_password_extended(pwd, timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):" ); if (r < 0) { /* ^D, ^C, timeout, or read error */ bb_error_msg("normal startup"); return 0; } if (r > 0) { break; } bb_do_delay(LOGIN_FAIL_DELAY); bb_error_msg("Login incorrect"); } bb_error_msg("starting shell for system maintenance"); IF_SELINUX(renew_current_security_context()); shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); if (!shell) shell = pwd->pw_shell; /* Exec login shell with no additional parameters. Never returns. */ run_shell(shell, 1, NULL); }
/* * Builds the dependency list (aka stack) of a module. * head: the highest module in the stack (last to insmod, first to rmmod) * tail: the lowest module in the stack (first to insmod, last to rmmod) */ static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t **tail ) { struct mod_list_t *find; struct dep_t *dt; struct mod_opt_t *opt = 0; char *path = 0; /* Search for the given module name amongst all dependency rules. * The module name in a dependency rule can be a shell pattern, * so try to match the given module name against such a pattern. * Of course if the name in the dependency rule is a plain string, * then we consider it a pattern, and matching will still work. */ for ( dt = depend; dt; dt = dt-> m_next ) { if ( fnmatch ( dt-> m_name, mod, 0 ) == 0) { break; } } if( !dt ) { bb_error_msg ("module %s not found.", mod); return; } // resolve alias names while ( dt-> m_isalias ) { if ( dt-> m_depcnt == 1 ) { struct dep_t *adt; for ( adt = depend; adt; adt = adt-> m_next ) { if ( strcmp ( adt-> m_name, dt-> m_deparr [0] ) == 0 ) break; } if ( adt ) { /* This is the module we are aliased to */ struct mod_opt_t *opts = dt-> m_options; /* Option of the alias are appended to the options of the module */ while( opts ) { adt-> m_options = append_option( adt-> m_options, opts-> m_opt_val ); opts = opts-> m_next; } dt = adt; } else { bb_error_msg ("module %s not found.", mod); return; } } else { bb_error_msg ("Bad alias %s", dt-> m_name); return; } } mod = dt-> m_name; path = dt-> m_path; opt = dt-> m_options; // search for duplicates for ( find = *head; find; find = find-> m_next ) { if ( !strcmp ( mod, find-> m_name )) { // found -> dequeue it if ( find-> m_prev ) find-> m_prev-> m_next = find-> m_next; else *head = find-> m_next; if ( find-> m_next ) find-> m_next-> m_prev = find-> m_prev; else *tail = find-> m_prev; break; // there can be only one duplicate } } if ( !find ) { // did not find a duplicate find = (struct mod_list_t *) xmalloc ( sizeof(struct mod_list_t)); find-> m_name = mod; find-> m_path = path; find-> m_options = opt; } // enqueue at tail if ( *tail ) (*tail)-> m_next = find; find-> m_prev = *tail; find-> m_next = 0; if ( !*head ) *head = find; *tail = find; if ( dt ) { int i; /* Add all dependable module for that new module */ for ( i = 0; i < dt-> m_depcnt; i++ ) check_dep ( dt-> m_deparr [i], head, tail ); } }
static void warn3x(const char *m1, const char *m2, const char *m3) { bb_error_msg("%s: warning: %s%s%s", svdir, m1, m2, m3); }
static void sig_term_handler(int sig) { if (verbose) bb_error_msg("got signal %u, exit", sig); kill_myself_with_sig(sig); }
int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) { char *str_C, *str_t; char *user; struct hcc *hccp; const char *instructs; char *msg_per_host = NULL; unsigned len_per_host = len_per_host; /* gcc */ #ifndef SSLSVD struct bb_uidgid_t ugid; #endif bool tcp; uint16_t local_port; char *preset_local_hostname = NULL; char *remote_hostname = remote_hostname; /* for compiler */ char *remote_addr = remote_addr; /* for compiler */ len_and_sockaddr *lsa; len_and_sockaddr local, remote; socklen_t sa_len; int pid; int sock; int conn; unsigned backlog = 20; unsigned opts; INIT_G(); tcp = (applet_name[0] == 't'); /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */ opt_complementary = "-3:i--i:ph:vv:b+:c+"; #ifdef SSLSVD opts = getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose ); #else /* "+": stop on first non-option */ opts = getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &verbose ); #endif if (opts & OPT_C) { /* -C n[:message] */ max_per_host = bb_strtou(str_C, &str_C, 10); if (str_C[0]) { if (str_C[0] != ':') bb_show_usage(); msg_per_host = str_C + 1; len_per_host = strlen(msg_per_host); } } if (max_per_host > cmax) max_per_host = cmax; if (opts & OPT_u) { xget_uidgid(&ugid, user); } #ifdef SSLSVD if (opts & OPT_U) ssluser = optarg; if (opts & OPT_slash) root = optarg; if (opts & OPT_Z) cert = optarg; if (opts & OPT_K) key = optarg; #endif argv += optind; if (!argv[0][0] || LONE_CHAR(argv[0], '0')) argv[0] = (char*)"0.0.0.0"; /* Per-IP flood protection is not thought-out for UDP */ if (!tcp) max_per_host = 0; bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */ #ifdef SSLSVD sslser = user; client = 0; if ((getuid() == 0) && !(opts & OPT_u)) { xfunc_exitcode = 100; bb_error_msg_and_die(bb_msg_you_must_be_root); } if (opts & OPT_u) if (!uidgid_get(&sslugid, ssluser, 1)) { if (errno) { bb_perror_msg_and_die("can't get user/group: %s", ssluser); } bb_error_msg_and_die("unknown user/group %s", ssluser); } if (!cert) cert = "./cert.pem"; if (!key) key = cert; if (matrixSslOpen() < 0) fatal("can't initialize ssl"); if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) { if (client) fatal("can't read cert, key, or ca file"); fatal("can't read cert or key file"); } if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0) fatal("can't create ssl session"); #endif sig_block(SIGCHLD); signal(SIGCHLD, sig_child_handler); bb_signals(BB_FATAL_SIGS, sig_term_handler); signal(SIGPIPE, SIG_IGN); if (max_per_host) ipsvd_perhost_init(cmax); local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0); lsa = xhost2sockaddr(argv[0], local_port); argv += 2; sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); sa_len = lsa->len; /* I presume sockaddr len stays the same */ xbind(sock, &lsa->u.sa, sa_len); if (tcp) { xlisten(sock, backlog); close_on_exec_on(sock); } else { /* udp: needed for recv_from_to to work: */ socket_want_pktinfo(sock); } /* ndelay_off(sock); - it is the default I think? */ #ifndef SSLSVD if (opts & OPT_u) { /* drop permissions */ xsetgid(ugid.gid); xsetuid(ugid.uid); } #endif if (verbose) { char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa); if (opts & OPT_u) bb_error_msg("listening on %s, starting, uid %u, gid %u", addr, (unsigned)ugid.uid, (unsigned)ugid.gid); else bb_error_msg("listening on %s, starting", addr); free(addr); } /* Main accept() loop */ again: hccp = NULL; while (cnum >= cmax) wait_for_any_sig(); /* expecting SIGCHLD */ /* Accept a connection to fd #0 */ again1: close(0); again2: sig_unblock(SIGCHLD); local.len = remote.len = sa_len; if (tcp) { conn = accept(sock, &remote.u.sa, &remote.len); } else { /* In case recv_from_to won't be able to recover local addr. * Also sets port - recv_from_to is unable to do it. */ local = *lsa; conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.u.sa, &local.u.sa, sa_len); } sig_block(SIGCHLD); if (conn < 0) { if (errno != EINTR) bb_perror_msg(tcp ? "accept" : "recv"); goto again2; } xmove_fd(tcp ? conn : sock, 0); if (max_per_host) { /* Drop connection immediately if cur_per_host > max_per_host * (minimizing load under SYN flood) */ remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa); cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp); if (cur_per_host > max_per_host) { /* ipsvd_perhost_add detected that max is exceeded * (and did not store ip in connection table) */ free(remote_addr); if (msg_per_host) { /* don't block or test for errors */ send(0, msg_per_host, len_per_host, MSG_DONTWAIT); } goto again1; } /* NB: remote_addr is not leaked, it is stored in conn table */ } if (!tcp) { /* Voodoo magic: making udp sockets each receive its own * packets is not trivial, and I still not sure * I do it 100% right. * 1) we have to do it before fork() * 2) order is important - is it right now? */ /* Open new non-connected UDP socket for further clients... */ sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); /* Make plain write/send work for old socket by supplying default * destination address. This also restricts incoming packets * to ones coming from this remote IP. */ xconnect(0, &remote.u.sa, sa_len); /* hole? at this point we have no wildcard udp socket... * can this cause clients to get "port unreachable" icmp? * Yup, time window is very small, but it exists (is it?) */ /* ..."open new socket", continued */ xbind(sock, &lsa->u.sa, sa_len); socket_want_pktinfo(sock); /* Doesn't work: * we cannot replace fd #0 - we will lose pending packet * which is already buffered for us! And we cannot use fd #1 * instead - it will "intercept" all following packets, but child * does not expect data coming *from fd #1*! */ #if 0 /* Make it so that local addr is fixed to localp->u.sa * and we don't accidentally accept packets to other local IPs. */ /* NB: we possibly bind to the _very_ same_ address & port as the one * already bound in parent! This seems to work in Linux. * (otherwise we can move socket to fd #0 only if bind succeeds) */ close(0); set_nport(localp, htons(local_port)); xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0); setsockopt_reuseaddr(0); /* crucial */ xbind(0, &localp->u.sa, localp->len); #endif } pid = vfork(); if (pid == -1) { bb_perror_msg("vfork"); goto again; } if (pid != 0) { /* Parent */ cnum++; if (verbose) connection_status(); if (hccp) hccp->pid = pid; /* clean up changes done by vforked child */ undo_xsetenv(); goto again; } /* Child: prepare env, log, and exec prog */ { /* vfork alert! every xmalloc in this block should be freed! */ char *local_hostname = local_hostname; /* for compiler */ char *local_addr = NULL; char *free_me0 = NULL; char *free_me1 = NULL; char *free_me2 = NULL; if (verbose || !(opts & OPT_E)) { if (!max_per_host) /* remote_addr is not yet known */ free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa); if (opts & OPT_h) { free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa); if (!remote_hostname) { bb_error_msg("can't look up hostname for %s", remote_addr); remote_hostname = remote_addr; } } /* Find out local IP peer connected to. * Errors ignored (I'm not paranoid enough to imagine kernel * which doesn't know local IP). */ if (tcp) getsockname(0, &local.u.sa, &local.len); /* else: for UDP it is done earlier by parent */ local_addr = xmalloc_sockaddr2dotted(&local.u.sa); if (opts & OPT_h) { local_hostname = preset_local_hostname; if (!local_hostname) { free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa); if (!local_hostname) bb_error_msg_and_die("can't look up hostname for %s", local_addr); } /* else: local_hostname is not NULL, but is NOT malloced! */ } } if (verbose) { pid = getpid(); if (max_per_host) { bb_error_msg("concurrency %s %u/%u", remote_addr, cur_per_host, max_per_host); } bb_error_msg((opts & OPT_h) ? "start %u %s-%s (%s-%s)" : "start %u %s-%s", pid, local_addr, remote_addr, local_hostname, remote_hostname); } if (!(opts & OPT_E)) { /* setup ucspi env */ const char *proto = tcp ? "TCP" : "UDP"; #ifdef SO_ORIGINAL_DST /* Extract "original" destination addr:port * from Linux firewall. Useful when you redirect * an outbond connection to local handler, and it needs * to know where it originally tried to connect */ if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) { char *addr = xmalloc_sockaddr2dotted(&local.u.sa); xsetenv_plain("TCPORIGDSTADDR", addr); free(addr); } #endif xsetenv_plain("PROTO", proto); xsetenv_proto(proto, "LOCALADDR", local_addr); xsetenv_proto(proto, "REMOTEADDR", remote_addr); if (opts & OPT_h) { xsetenv_proto(proto, "LOCALHOST", local_hostname); xsetenv_proto(proto, "REMOTEHOST", remote_hostname); } //compat? xsetenv_proto(proto, "REMOTEINFO", ""); /* additional */ if (cur_per_host > 0) /* can not be true for udp */ xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host)); } free(local_addr); free(free_me0); free(free_me1); free(free_me2); } xdup2(0, 1); signal(SIGPIPE, SIG_DFL); /* this one was SIG_IGNed */ /* Non-ignored signals revert to SIG_DFL on exec anyway */ /*signal(SIGCHLD, SIG_DFL);*/ sig_unblock(SIGCHLD); #ifdef SSLSVD strcpy(id, utoa(pid)); ssl_io(0, argv); bb_perror_msg_and_die("can't execute '%s'", argv[0]); #else BB_EXECVP_or_die(argv); #endif }
static void send_r_n(const char *s) { if (verbose) bb_error_msg("send:'%s'", s); printf("%s\r\n", s); }
static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) { struct icmp6_hdr *icmppkt; struct timeval tv, *tp; int dupflag; unsigned long triptime; char buf[INET6_ADDRSTRLEN]; gettimeofday(&tv, NULL); /* discard if too short */ if (sz < (datalen + sizeof(struct icmp6_hdr))) return; icmppkt = (struct icmp6_hdr *) packet; if (icmppkt->icmp6_id != myid) return; /* not our ping */ if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { ++nreceived; tp = (struct timeval *) &icmppkt->icmp6_data8[4]; if ((tv.tv_usec -= tp->tv_usec) < 0) { --tv.tv_sec; tv.tv_usec += 1000000; } tv.tv_sec -= tp->tv_sec; triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); tsum += triptime; if (triptime < tmin) tmin = triptime; if (triptime > tmax) tmax = triptime; if (TST(icmppkt->icmp6_seq % MAX_DUP_CHK)) { ++nrepeats; --nreceived; dupflag = 1; } else { SET(icmppkt->icmp6_seq % MAX_DUP_CHK); dupflag = 0; } if (option_mask32 & OPT_QUIET) return; printf("%d bytes from %s: icmp6_seq=%u", sz, inet_ntop(AF_INET6, &pingaddr.sin6_addr, buf, sizeof(buf)), ntohs(icmppkt->icmp6_seq)); printf(" ttl=%d time=%lu.%lu ms", hoplimit, triptime / 10, triptime % 10); if (dupflag) printf(" (DUP!)"); puts(""); } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) bb_error_msg("warning: got ICMP %d (%s)", icmppkt->icmp6_type, icmp6_type_name(icmppkt->icmp6_type)); }
/* * Write a single sysctl setting */ int sysctl_write_setting(const char *setting, int output) { int retval = 0; const char *name = setting; const char *value; const char *equals; char *tmpname, *outname, *cptr; int fd = -1; if (!name) /* probably dont' want to display this err */ return 0; if (!(equals = strchr(setting, '='))) { bb_error_msg(ERR_NO_EQUALS, setting); return -1; } value = equals + sizeof(char); /* point to the value in name=value */ if (!*name || !*value || name == equals) { bb_error_msg(ERR_MALFORMED_SETTING, setting); return -2; } tmpname = bb_xasprintf("%s%.*s", PROC_PATH, (equals - name), name); outname = bb_xstrdup(tmpname + strlen(PROC_PATH)); while ((cptr = strchr(tmpname, '.')) != NULL) *cptr = '/'; while ((cptr = strchr(outname, '/')) != NULL) *cptr = '.'; if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { switch (errno) { case ENOENT: bb_error_msg(ERR_INVALID_KEY, outname); break; case EACCES: bb_perror_msg(ERR_PERMISSION_DENIED, outname); break; default: bb_error_msg(ERR_UNKNOWN_WRITING, errno, outname); break; } retval = -1; } else { dwrite_str(fd, value); close(fd); if (output) { dwrite_str(STDOUT_FILENO, outname); dwrite_str(STDOUT_FILENO, " = "); } dwrite_str(STDOUT_FILENO, value); dwrite_str(STDOUT_FILENO, "\n"); } /* cleanup */ free(tmpname); free(outname); return retval; } /* end sysctl_write_setting() */
static int writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, const char *fileName, struct stat *statbuf) { struct TarHeader header; if (sizeof(header) != 512) BUG_tar_header_size(); memset(&header, 0, sizeof(struct TarHeader)); strncpy(header.name, header_name, sizeof(header.name)); /* POSIX says to mask mode with 07777. */ PUT_OCTAL(header.mode, statbuf->st_mode & 07777); PUT_OCTAL(header.uid, statbuf->st_uid); PUT_OCTAL(header.gid, statbuf->st_gid); memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */ PUT_OCTAL(header.mtime, statbuf->st_mtime); /* Enter the user and group names */ safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname)); safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname)); if (tbInfo->hlInfo) { /* This is a hard link */ header.typeflag = LNKTYPE; strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname)); #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS /* Write out long linkname if needed */ if (header.linkname[sizeof(header.linkname)-1]) writeLongname(tbInfo->tarFd, GNULONGLINK, tbInfo->hlInfo->name, 0); #endif } else if (S_ISLNK(statbuf->st_mode)) { char *lpath = xmalloc_readlink_or_warn(fileName); if (!lpath) return FALSE; header.typeflag = SYMTYPE; strncpy(header.linkname, lpath, sizeof(header.linkname)); #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS /* Write out long linkname if needed */ if (header.linkname[sizeof(header.linkname)-1]) writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0); #else /* If it is larger than 100 bytes, bail out */ if (header.linkname[sizeof(header.linkname)-1]) { free(lpath); bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); return FALSE; } #endif free(lpath); } else if (S_ISDIR(statbuf->st_mode)) { header.typeflag = DIRTYPE; /* Append '/' only if there is a space for it */ if (!header.name[sizeof(header.name)-1]) header.name[strlen(header.name)] = '/'; } else if (S_ISCHR(statbuf->st_mode)) { header.typeflag = CHRTYPE; PUT_OCTAL(header.devmajor, major(statbuf->st_rdev)); PUT_OCTAL(header.devminor, minor(statbuf->st_rdev)); } else if (S_ISBLK(statbuf->st_mode)) { header.typeflag = BLKTYPE; PUT_OCTAL(header.devmajor, major(statbuf->st_rdev)); PUT_OCTAL(header.devminor, minor(statbuf->st_rdev)); } else if (S_ISFIFO(statbuf->st_mode)) { header.typeflag = FIFOTYPE; } else if (S_ISREG(statbuf->st_mode)) { if (sizeof(statbuf->st_size) > 4 && statbuf->st_size > (off_t)0777777777777LL ) { bb_error_msg_and_die("cannot store file '%s' " "of size %"OFF_FMT"d, aborting", fileName, statbuf->st_size); } header.typeflag = REGTYPE; PUT_OCTAL(header.size, statbuf->st_size); } else { bb_error_msg("%s: unknown file type", fileName); return FALSE; } #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS /* Write out long name if needed */ /* (we, like GNU tar, output long linkname *before* long name) */ if (header.name[sizeof(header.name)-1]) writeLongname(tbInfo->tarFd, GNULONGNAME, header_name, S_ISDIR(statbuf->st_mode)); #endif /* Now write the header out to disk */ chksum_and_xwrite(tbInfo->tarFd, &header); /* Now do the verbose thing (or not) */ if (tbInfo->verboseFlag) { FILE *vbFd = stdout; if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ vbFd = stderr; /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ /* We don't have such excesses here: for us "v" == "vv" */ /* '/' is probably a GNUism */ fprintf(vbFd, "%s%s\n", header_name, S_ISDIR(statbuf->st_mode) ? "/" : ""); } return TRUE; }
int i2cset_main(int argc, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1), opt_m = (1 << 2), opt_r = (1 << 3); const char *const optstr = "fym:r"; int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0; int val, blen = 0, mask = 0, fd, status; unsigned char block[I2C_SMBUS_BLOCK_MAX]; char *opt_m_arg = NULL; unsigned opts; opt_complementary = "-3"; /* from 3 to ? args */ opts = getopt32(argv, optstr, &opt_m_arg); argv += optind; argc -= optind; bus_num = i2c_bus_lookup(argv[0]); bus_addr = i2c_parse_bus_addr(argv[1]); data_addr = i2c_parse_data_addr(argv[2]); if (argv[3]) { if (!argv[4] && argv[3][0] != 'c') { mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */ } else { switch (argv[argc-1][0]) { case 'c': /* Already set */ break; case 'b': mode = I2C_SMBUS_BYTE_DATA; break; case 'w': mode = I2C_SMBUS_WORD_DATA; break; case 's': mode = I2C_SMBUS_BLOCK_DATA; break; case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break; default: bb_error_msg("invalid mode"); bb_show_usage(); } pec = argv[argc-1][1] == 'p'; if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) { if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA) bb_error_msg_and_die( "PEC not supported for I2C " "block writes"); if (opts & opt_m) bb_error_msg_and_die( "mask not supported for block " "writes"); } } } /* Prepare the value(s) to be written according to current mode. */ switch (mode) { case I2C_SMBUS_BYTE_DATA: val = xstrtou_range(argv[3], 0, 0, 0xff); break; case I2C_SMBUS_WORD_DATA: val = xstrtou_range(argv[3], 0, 0, 0xffff); break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: for (blen = 3; blen < (argc - 1); blen++) block[blen] = xstrtou_range(argv[blen], 0, 0, 0xff); val = -1; break; default: val = -1; break; } if (opts & opt_m) { mask = xstrtou_range(opt_m_arg, 0, 0, (mode == I2C_SMBUS_BYTE || mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff); } fd = i2c_dev_open(bus_num); check_write_funcs(fd, mode, pec); i2c_set_slave_addr(fd, bus_addr, opts & opt_f); if (!(opts & opt_y)) confirm_action(bus_addr, mode, data_addr, pec); /* * If we're using mask - read the current value here and adjust the * value to be written. */ if (opts & opt_m) { int tmpval; switch (mode) { case I2C_SMBUS_BYTE: tmpval = i2c_smbus_read_byte(fd); break; case I2C_SMBUS_WORD_DATA: tmpval = i2c_smbus_read_word_data(fd, data_addr); break; default: tmpval = i2c_smbus_read_byte_data(fd, data_addr); } if (tmpval < 0) bb_perror_msg_and_die("can't read old value"); val = (val & mask) | (tmpval & ~mask); if (!(opts & opt_y)) { bb_error_msg("old value 0x%0*x, write mask " "0x%0*x, will write 0x%0*x to register " "0x%02x", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val, data_addr); confirm_or_abort(); } } if (pec) i2c_set_pec(fd, 1); switch (mode) { case I2C_SMBUS_BYTE: status = i2c_smbus_write_byte(fd, data_addr); break; case I2C_SMBUS_WORD_DATA: status = i2c_smbus_write_word_data(fd, data_addr, val); break; case I2C_SMBUS_BLOCK_DATA: status = i2c_smbus_write_block_data(fd, data_addr, blen, block); break; case I2C_SMBUS_I2C_BLOCK_DATA: status = i2c_smbus_write_i2c_block_data(fd, data_addr, blen, block); break; default: /* I2C_SMBUS_BYTE_DATA */ status = i2c_smbus_write_byte_data(fd, data_addr, val); break; } if (status < 0) bb_perror_msg_and_die("write failed"); if (pec) i2c_set_pec(fd, 0); /* Clear PEC. */ /* No readback required - we're done. */ if (!(opts & opt_r)) return 0; switch (mode) { case I2C_SMBUS_BYTE: status = i2c_smbus_read_byte(fd); val = data_addr; break; case I2C_SMBUS_WORD_DATA: status = i2c_smbus_read_word_data(fd, data_addr); break; default: /* I2C_SMBUS_BYTE_DATA */ status = i2c_smbus_read_byte_data(fd, data_addr); } if (status < 0) { puts("Warning - readback failed"); } else if (status != val) { printf("Warning - data mismatch - wrote " "0x%0*x, read back 0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status); } else { printf("Value 0x%0*x written, readback matched\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val); } return 0; }
static int writeFileToTarball(const char *fileName, struct stat *statbuf, void *userData, int depth ATTRIBUTE_UNUSED) { struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; const char *header_name; int inputFileFd = -1; /* * Check to see if we are dealing with a hard link. * If so - * Treat the first occurance of a given dev/inode as a file while * treating any additional occurances as hard links. This is done * by adding the file information to the HardLinkInfo linked list. */ tbInfo->hlInfo = NULL; if (statbuf->st_nlink > 1) { tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); if (tbInfo->hlInfo == NULL) addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName); } /* It is against the rules to archive a socket */ if (S_ISSOCK(statbuf->st_mode)) { bb_error_msg("%s: socket ignored", fileName); return TRUE; } /* It is a bad idea to store the archive we are in the process of creating, * so check the device and inode to be sure that this particular file isn't * the new tarball */ if (tbInfo->statBuf.st_dev == statbuf->st_dev && tbInfo->statBuf.st_ino == statbuf->st_ino) { bb_error_msg("%s: file is the archive; skipping", fileName); return TRUE; } header_name = fileName; while (header_name[0] == '/') { static int alreadyWarned = FALSE; if (alreadyWarned == FALSE) { bb_error_msg("removing leading '/' from member names"); alreadyWarned = TRUE; } header_name++; } #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS if (strlen(fileName) >= NAME_SIZE) { bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); return TRUE; } #endif if (header_name[0] == '\0') return TRUE; if (exclude_file(tbInfo->excludeList, header_name)) return SKIP; /* Is this a regular file? */ if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) { /* open the file we want to archive, and make sure all is well */ inputFileFd = open(fileName, O_RDONLY); if (inputFileFd < 0) { bb_perror_msg("%s: cannot open", fileName); return FALSE; } } /* Add an entry to the tarball */ if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) { return FALSE; } /* If it was a regular file, write out the body */ if (inputFileFd >= 0) { size_t readSize; /* Wwrite the file to the archive. */ /* We record size into header first, */ /* and then write out file. If file shrinks in between, */ /* tar will be corrupted. So we don't allow for that. */ /* NB: GNU tar 1.16 warns and pads with zeroes */ /* or even seeks back and updates header */ bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); ////off_t readSize; ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); ////if (readSize != statbuf->st_size && readSize >= 0) { //// bb_error_msg_and_die("short read from %s, aborting", fileName); ////} /* Check that file did not grow in between? */ /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */ close(inputFileFd); /* Pad the file up to the tar block size */ /* (a few tricks here in the name of code size) */ readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1); memset(bb_common_bufsiz1, 0, readSize); xwrite(tbInfo->tarFd, bb_common_bufsiz1, readSize); } return TRUE; }
/* * Add the symbol defined in the kernel, simulating a pseudo module. * Create a dummy module entry in the list of modules. * This module is used to handle the exported kernel symbols. * * Load from the currently running kernel * OR * from a file containing kernel symbols from a different kernel. * The file can be either a "System.map" file or a copy of "/proc/ksyms". * * Return -1 if any error. */ static int addksyms(const char *file_syms) { FILE *fp; MODULE *mod = modules + n_modules++; SYMBOL *symtab[MAX_MAP_SYM]; struct module_symbol *ksym; unsigned int so_far = 0; int is_mapfile = 0; int n_syms = 0; int size; char line[PATH_MAX]; char *p; mod->name = "-"; mod->defsym.n_syms = 0; mod->defsym.symtab = NULL; mod->undefs.n_syms = 0; mod->undefs.symtab = NULL; /* Fake the _mod_use_count_ symbol provided by insmod */ /* Dummy */ symtab[n_syms++] = addsym("mod_use_count_", mod, SYM_DEFINED, 0); symtab[n_syms++] = addsym("__this_module", mod, SYM_DEFINED, 0); /* * Specification: depmod / kernel syms only * When initialising its symbol table from the kernel * depmod silently discards all symbol from loaded modules. * * This means that depmod may be used at any time to compute * the dependancy table, even if there are modules already * loaded. * * depmod use the kernel system call to obtain the * symbol table, not /proc/ksyms. */ if (file_syms) { if ((fp = fopen(file_syms, "r")) == NULL) { bb_error_msg("Can't read %s", file_syms); return -1; } if (!fgets(line, sizeof(line), fp)) { fclose(fp); bb_error_msg("premature EOF on %s", file_syms); return -1; } p = strtok(line, " \t\n"); if (!p) { fclose(fp); bb_error_msg("Illegal format of %s", file_syms); return -1; } if (!isspace(*line)) /* Adressless symbol? */ p = strtok(NULL, " \t\n"); /* The second word is either the symbol name or a type */ if (p && p[0] && !p[1]) { /* System.map */ is_mapfile = 1; p = strtok(NULL, " \t\n"); } else { /* /proc/ksyms copy */ if (p && strtok(NULL, " \t\n")) p = NULL; } if (p && strncmp(p, "GPLONLY_", 8) == 0) p += 8; if (p) symtab[n_syms++] = addsym(p, mod, SYM_DEFINED, 0); while (fgets(line, sizeof(line), fp)) { if (!is_mapfile && strchr(line, '[')) continue; p = strtok(line, " \t\n"); /* Skip first word */ if (!isspace(*line)) /* Adressless symbol? */ p = strtok(NULL, " \t\n"); if (is_mapfile) { if (!p || !p[0] || p[1]) continue; p = strtok(NULL, " \t\n"); /* Sparc has symbols like '.div' that need to be * exported. They strip the '.' and prefix the * symbol with '__sparc_dot_'. There is no need * for 'sparc' in the name, other systems with * the same problem should use just '__dot_'. * Support both prefixes, ready for other * systems. * */ if (!strncmp(p, "__kstrtab___dot_", 15)) { p += 15; *p = '.'; } else if (!strncmp(p, "__kstrtab___sparc_dot_", 21)) { p += 21; *p = '.'; } else if (!strncmp(p, "__kstrtab_", 10)) p += 10; else if (!strncmp(p, "__export_priv_", 14)) { /* Sparc has some weird exported symbols marked * __export_priv_ instead of the normal __kstrtab_. * Replace the 'v' with '_' and point at the start of * the '__' before the name. I see no good reason * to use __export_priv_, but for compatibility with * old sparc kernels, it is supported. Try to remove * __export_priv_ from sparc and remove this code * four releases after the last kernel that uses * __export_priv_. */ p += 12; *p = '_'; } else continue; } if (strncmp(p, "GPLONLY_", 8) == 0) p += 8; assert(n_syms < MAX_MAP_SYM); symtab[n_syms++] = addsym(p, mod, SYM_DEFINED, 0); } fclose(fp); } else { /* Use the exported symbols from currently running kernel */ if (!new_get_kernel_info(K_SYMBOLS)) return -1; for (ksym = ksyms; so_far < nksyms; ++so_far, ksym++) { if (strncmp((char *)ksym->name, "GPLONLY_", 8) == 0) ksym->name = ((char *)ksym->name) + 8; assert(n_syms < MAX_MAP_SYM); symtab[n_syms++] = addsym((char *)ksym->name, mod, SYM_DEFINED, 0); } } size = n_syms * sizeof(SYMBOL *); mod->defsym.symtab = (SYMBOL **)xmalloc(size); mod->defsym.n_syms = n_syms; memcpy(mod->defsym.symtab, symtab, size); return 0; }
static int writeTarFile(const int tar_fd, const int verboseFlag, const unsigned long dereferenceFlag, const llist_t *include, const llist_t *exclude, const int gzip) { pid_t gzipPid = 0; int errorFlag = FALSE; struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; fchmod(tar_fd, 0644); tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) bb_perror_msg_and_die("cannot stat tar file"); if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) { int gzipDataPipe[2] = { -1, -1 }; int gzipStatusPipe[2] = { -1, -1 }; volatile int vfork_exec_errno = 0; const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) bb_perror_msg_and_die("pipe"); signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ #if defined(__GNUC__) && __GNUC__ /* Avoid vfork clobbering */ (void) &include; (void) &errorFlag; (void) &zip_exec; #endif gzipPid = vfork(); if (gzipPid == 0) { dup2(gzipDataPipe[0], 0); close(gzipDataPipe[1]); dup2(tbInfo.tarFd, 1); close(gzipStatusPipe[0]); fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows success */ BB_EXECLP(zip_exec, zip_exec, "-f", NULL); vfork_exec_errno = errno; close(gzipStatusPipe[1]); exit(-1); } else if (gzipPid > 0) { close(gzipDataPipe[0]); close(gzipStatusPipe[1]); while (1) { char buf; int n = full_read(gzipStatusPipe[0], &buf, 1); if (n == 0 && vfork_exec_errno != 0) { errno = vfork_exec_errno; bb_perror_msg_and_die("cannot exec %s", zip_exec); } else if ((n < 0) && (errno == EAGAIN || errno == EINTR)) continue; /* try it again */ break; } close(gzipStatusPipe[0]); tbInfo.tarFd = gzipDataPipe[1]; } else bb_perror_msg_and_die("vfork gzip"); } tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { if (!recursive_action(include->data, TRUE, dereferenceFlag, FALSE, writeFileToTarball, writeFileToTarball, &tbInfo, 0)) { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ memset(bb_common_bufsiz1, 0, 2*TAR_BLOCK_SIZE); xwrite(tbInfo.tarFd, bb_common_bufsiz1, 2*TAR_BLOCK_SIZE); /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Close so the child process (if any) will exit */ close(tbInfo.tarFd); /* Hang up the tools, close up shop, head home */ if (ENABLE_FEATURE_CLEAN_UP) freeHardLinkInfo(&tbInfo.hlInfoHead); if (errorFlag) bb_error_msg("error exit delayed from previous errors"); if (gzipPid) { int status; if (waitpid(gzipPid, &status, 0) == -1) bb_perror_msg("waitpid"); else if (!WIFEXITED(status) || WEXITSTATUS(status)) /* gzip was killed or has exited with nonzero! */ errorFlag = TRUE; } return errorFlag; }
/* * Do the substitute command. * The current line is set to the last substitution done. */ static void subCommand(const char * cmd, int num1, int num2) { char *cp, *oldStr, *newStr, buf[USERSIZE]; int delim, oldLen, newLen, deltaLen, offset; LINE *lp, *nlp; int globalFlag, printFlag, didSub, needPrint; if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) { bb_error_msg("bad line range for substitute"); return; } globalFlag = FALSE; printFlag = FALSE; didSub = FALSE; needPrint = FALSE; /* * Copy the command so we can modify it. */ strcpy(buf, cmd); cp = buf; if (isblank(*cp) || (*cp == '\0')) { bb_error_msg("bad delimiter for substitute"); return; } delim = *cp++; oldStr = cp; cp = strchr(cp, delim); if (cp == NULL) { bb_error_msg("missing 2nd delimiter for substitute"); return; } *cp++ = '\0'; newStr = cp; cp = strchr(cp, delim); if (cp) *cp++ = '\0'; else cp = (char*)""; while (*cp) switch (*cp++) { case 'g': globalFlag = TRUE; break; case 'p': printFlag = TRUE; break; default: bb_error_msg("unknown option for substitute"); return; } if (*oldStr == '\0') { if (searchString[0] == '\0') { bb_error_msg("no previous search string"); return; } oldStr = searchString; } if (oldStr != searchString) strcpy(searchString, oldStr); lp = findLine(num1); if (lp == NULL) return; oldLen = strlen(oldStr); newLen = strlen(newStr); deltaLen = newLen - oldLen; offset = 0; nlp = NULL; while (num1 <= num2) { offset = findString(lp, oldStr, oldLen, offset); if (offset < 0) { if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } offset = 0; lp = lp->next; num1++; continue; } needPrint = printFlag; didSub = TRUE; dirty = TRUE; /* * If the replacement string is the same size or shorter * than the old string, then the substitution is easy. */ if (deltaLen <= 0) { memcpy(&lp->data[offset], newStr, newLen); if (deltaLen) { memcpy(&lp->data[offset + newLen], &lp->data[offset + oldLen], lp->len - offset - oldLen); lp->len += deltaLen; } offset += newLen; if (globalFlag) continue; if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } lp = lp->next; num1++; continue; } /* * The new string is larger, so allocate a new line * structure and use that. Link it in in place of * the old line structure. */ nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen); if (nlp == NULL) { bb_error_msg("cannot get memory for line"); return; } nlp->len = lp->len + deltaLen; memcpy(nlp->data, lp->data, offset); memcpy(&nlp->data[offset], newStr, newLen); memcpy(&nlp->data[offset + newLen], &lp->data[offset + oldLen], lp->len - offset - oldLen); nlp->next = lp->next; nlp->prev = lp->prev; nlp->prev->next = nlp; nlp->next->prev = nlp; if (curLine == lp) curLine = nlp; free(lp); lp = nlp; offset += newLen; if (globalFlag) continue; if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } lp = lp->next; num1++; } if (!didSub) bb_error_msg("no substitutions found for \"%s\"", oldStr); }
// file libbb/warn_ignoring_args.c line 12 static void bb_warn_ignoring_args(char *arg) { if(!(arg == ((char *)NULL))) bb_error_msg("ignoring all arguments"); }
/* * Read lines from a file at the specified line number. * Returns TRUE if the file was successfully read. */ static int readLines(const char * file, int num) { int fd, cc; int len, lineCount, charCount; char *cp; if ((num < 1) || (num > lastNum + 1)) { bb_error_msg("bad line for read"); return FALSE; } fd = open(file, 0); if (fd < 0) { perror(file); return FALSE; } bufPtr = bufBase; bufUsed = 0; lineCount = 0; charCount = 0; cc = 0; printf("\"%s\", ", file); fflush(stdout); do { cp = memchr(bufPtr, '\n', bufUsed); if (cp) { len = (cp - bufPtr) + 1; if (!insertLine(num, bufPtr, len)) { close(fd); return FALSE; } bufPtr += len; bufUsed -= len; charCount += len; lineCount++; num++; continue; } if (bufPtr != bufBase) { memcpy(bufBase, bufPtr, bufUsed); bufPtr = bufBase + bufUsed; } if (bufUsed >= bufSize) { len = (bufSize * 3) / 2; cp = realloc(bufBase, len); if (cp == NULL) { bb_error_msg("no memory for buffer"); close(fd); return FALSE; } bufBase = cp; bufPtr = bufBase + bufUsed; bufSize = len; } cc = read(fd, bufPtr, bufSize - bufUsed); bufUsed += cc; bufPtr = bufBase; } while (cc > 0); if (cc < 0) { perror(file); close(fd); return FALSE; } if (bufUsed) { if (!insertLine(num, bufPtr, bufUsed)) { close(fd); return -1; } lineCount++; charCount += bufUsed; } close(fd); printf("%d lines%s, %d chars\n", lineCount, (bufUsed ? " (incomplete)" : ""), charCount); return TRUE; }
extern int run_parts(char **args, const unsigned char test_mode) { struct dirent **namelist = 0; struct stat st; char *filename; char *arg0 = args[0]; int entries; int i; int exitstatus = 0; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &i; (void) &exitstatus; #endif /* scandir() isn't POSIX, but it makes things easy. */ entries = scandir(arg0, &namelist, valid_name, alphasort); if (entries == -1) { if (test_mode & 2) { return(2); } bb_perror_msg_and_die("failed to open directory %s", arg0); } for (i = 0; i < entries; i++) { filename = concat_path_file(arg0, namelist[i]->d_name); if (stat(filename, &st) < 0) { bb_perror_msg_and_die("failed to stat component %s", filename); } if (S_ISREG(st.st_mode) && !access(filename, X_OK)) { if (test_mode & 1) { puts(filename); } else { /* exec_errno is common vfork variable */ volatile int exec_errno = 0; int result; int pid; if ((pid = vfork()) < 0) { bb_perror_msg_and_die("failed to fork"); } else if (!pid) { args[0] = filename; execv(filename, args); exec_errno = errno; _exit(1); } waitpid(pid, &result, 0); if(exec_errno) { errno = exec_errno; bb_perror_msg_and_die("failed to exec %s", filename); } if (WIFEXITED(result) && WEXITSTATUS(result)) { bb_perror_msg("%s exited with return code %d", filename, WEXITSTATUS(result)); exitstatus = 1; } else if (WIFSIGNALED(result)) { bb_perror_msg("%s exited because of uncaught signal %d", filename, WTERMSIG(result)); exitstatus = 1; } } } else if (!S_ISDIR(st.st_mode)) { bb_error_msg("component %s is not an executable plain file", filename); exitstatus = 1; } free(namelist[i]); free(filename); } free(namelist); return(exitstatus); }
/* * Print lines in a specified range. * The last line printed becomes the current line. * If expandFlag is TRUE, then the line is printed specially to * show magic characters. */ static int printLines(int num1, int num2, int expandFlag) { const LINE *lp; const char *cp; int ch, count; if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) { bb_error_msg("bad line range for print"); return FALSE; } lp = findLine(num1); if (lp == NULL) return FALSE; while (num1 <= num2) { if (!expandFlag) { write(1, lp->data, lp->len); setCurNum(num1++); lp = lp->next; continue; } /* * Show control characters and characters with the * high bit set specially. */ cp = lp->data; count = lp->len; if ((count > 0) && (cp[count - 1] == '\n')) count--; while (count-- > 0) { ch = *cp++; if (ch & 0x80) { fputs("M-", stdout); ch &= 0x7f; } if (ch < ' ') { fputc('^', stdout); ch += '@'; } if (ch == 0x7f) { fputc('^', stdout); ch = '?'; } fputc(ch, stdout); } fputs("$\n", stdout); setCurNum(num1++); lp = lp->next; } return TRUE; }
static void rcptto(const char *s) { // N.B. we don't die if recipient is rejected, for the other recipients may be accepted if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) bb_error_msg("Bad recipient: <%s>", s); }
void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; #if ENABLE_FEATURE_TAR_SELINUX char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); free(archive_handle->tar__sctx[PAX_NEXT_FILE]); archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { char *slash = strrchr(file_header->name, '/'); if (slash) { *slash = '\0'; bb_make_directory(file_header->name, -1, FILEUTILS_RECUR); *slash = '/'; } } if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ if (!S_ISDIR(file_header->mode)) { /* Is it hardlink? * We encode hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* Ugly special case: * tar cf t.tar hardlink1 hardlink2 hardlink1 * results in this tarball structure: * hardlink1 * hardlink2 -> hardlink1 * hardlink1 -> hardlink1 <== !!! */ if (strcmp(file_header->link_target, file_header->name) == 0) goto ret; } /* Proceed with deleting */ if (_unlink(file_header->name) == -1 && errno != ENOENT ) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat existing_sb; if (lstat(file_header->name, &existing_sb) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("can't stat old file"); } } else if (existing_sb.st_mtime >= file_header->mtime) { if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) && !S_ISDIR(file_header->mode) ) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } data_skip(archive_handle); goto ret; } else if ((_unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); } } /* Handle hard links separately * We encode hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 ) { /* hard link */ res = link(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("can't create %slink " "from %s to %s", "hard", file_header->name, file_header->link_target); } /* Hardlinks have no separate mode/ownership, skip chown/chmod */ goto ret; } /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ char *dst_name; int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; dst_name = file_header->name; #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) /* rpm-style temp file name */ dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); #endif if (_sopen_s(&dst_fd, dst_name, flags, _SH_DENYNO, file_header->mode) != 0) { bb_perror_msg_and_die("can't open file %s", dst_name); } bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); _close(dst_fd); #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { xrename(dst_name, file_header->name); free(dst_name); } #endif break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((res == -1) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't make dir %s", file_header->name); } break; case S_IFLNK: /* Symlink */ //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create %slink " "from %s to %s", "sym", file_header->name, file_header->link_target); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't create node %s", file_header->name); } break; default: bb_error_msg_and_die("unrecognized file type"); } if (!S_ISLNK(file_header->mode)) { if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { uid_t uid = file_header->uid; gid_t gid = file_header->gid; #if ENABLE_FEATURE_TAR_UNAME_GNAME if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { if (file_header->tar__uname) { //TODO: cache last name/id pair? struct passwd *pwd = getpwnam(file_header->tar__uname); if (pwd) uid = pwd->pw_uid; } if (file_header->tar__gname) { struct group *grp = getgrnam(file_header->tar__gname); if (grp) gid = grp->gr_gid; } } #endif /* GNU tar 1.15.1 uses chown, not lchown */ chown(file_header->name, uid, gid); } /* uclibc has no lchmod, glibc is even stranger - * it has lchmod which seems to do nothing! * so we use chmod... */ if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { (void)_chmod(file_header->name, file_header->mode); } if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { struct timeval t[2]; t[1].tv_sec = t[0].tv_sec = (long)file_header->mtime; t[1].tv_usec = t[0].tv_usec = 0; utimes(file_header->name, t); } } ret: ; #if ENABLE_FEATURE_TAR_SELINUX if (sctx) { /* reset the context after creating an entry */ setfscreatecon(NULL); } #endif }
int man_main(int argc UNUSED_PARAM, char **argv) { parser_t *parser; const char *pager; char **man_path_list; char *sec_list; char *cur_path, *cur_sect; int count_mp, cur_mp; int opt, not_found; char *token[2]; opt_complementary = "-1"; /* at least one argument */ opt = getopt32(argv, "+aw"); argv += optind; sec_list = xstrdup("1:2:3:4:5:6:7:8:9"); /* Last valid man_path_list[] is [0x10] */ man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); count_mp = 0; man_path_list[0] = xstrdup(getenv("MANPATH")); if (man_path_list[0]) count_mp++; pager = getenv("MANPAGER"); if (!pager) { pager = getenv("PAGER"); if (!pager) pager = "more"; } /* Parse man.conf */ parser = config_open("/etc/man.conf"); while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) { if (!token[1]) continue; if (strcmp("MANPATH", token[0]) == 0) { man_path_list = xrealloc_vector(man_path_list, 4, count_mp); man_path_list[count_mp] = xstrdup(token[1]); count_mp++; /* man_path_list is NULL terminated */ /*man_path_list[count_mp] = NULL; - xrealloc_vector did it */ } if (strcmp("MANSECT", token[0]) == 0) { free(sec_list); sec_list = xstrdup(token[1]); } } config_close(parser); not_found = 0; do { /* for each argv[] */ int found = 0; cur_mp = 0; if (strchr(*argv, '/')) { found = show_manpage(pager, *argv, /*man:*/ 1, 0); goto check_found; } while ((cur_path = man_path_list[cur_mp++]) != NULL) { /* for each MANPATH */ do { /* for each MANPATH item */ char *next_path = strchrnul(cur_path, ':'); int path_len = next_path - cur_path; cur_sect = sec_list; do { /* for each section */ char *next_sect = strchrnul(cur_sect, ':'); int sect_len = next_sect - cur_sect; char *man_filename; int cat0man1 = 0; /* Search for cat, then man page */ while (cat0man1 < 2) { int found_here; man_filename = xasprintf("%.*s/%s%.*s/%s.%.*s" Z_SUFFIX, path_len, cur_path, "cat\0man" + (cat0man1 * 4), sect_len, cur_sect, *argv, sect_len, cur_sect); found_here = show_manpage(pager, man_filename, cat0man1, 0); found |= found_here; cat0man1 += found_here + 1; free(man_filename); } if (found && !(opt & OPT_a)) goto next_arg; cur_sect = next_sect; while (*cur_sect == ':') cur_sect++; } while (*cur_sect); cur_path = next_path; while (*cur_path == ':') cur_path++; } while (*cur_path); } check_found: if (!found) { bb_error_msg("no manual entry for '%s'", *argv); not_found = 1; } next_arg: argv++; } while (*argv); return not_found; }