static void die_if_nologin(void) { FILE *fp; int c; int empty = 1; fp = fopen_for_read("/etc/nologin"); if (!fp) /* assuming it does not exist */ return; while ((c = getc(fp)) != EOF) { if (c == '\n') bb_putchar('\r'); bb_putchar(c); empty = 0; } if (empty) puts("\r\nSystem closed for routine maintenance\r"); fclose(fp); fflush_all(); /* Users say that they do need this prior to exit: */ tcdrain(STDOUT_FILENO); exit(EXIT_FAILURE); }
static pid_list *scan_pid_maps(const char *fname, pid_t pid, inode_list *ilist, pid_list *plist) { FILE *file; char line[MAX_LINE + 1]; int major, minor; ino_t inode; long long uint64_inode; dev_t dev; file = fopen_for_read(fname); if (!file) return plist; while (fgets(line, MAX_LINE, file)) { if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) continue; inode = uint64_inode; if (major == 0 && minor == 0 && inode == 0) continue; dev = makedev(major, minor); if (search_dev_inode(ilist, dev, inode)) plist = add_pid(plist, pid); } fclose(file); return plist; }
/* Save C-state usage and duration. Also update maxcstate. */ static void read_cstate_counts(ullong *usage, ullong *duration) { DIR *dir; struct dirent *d; dir = opendir("/proc/acpi/processor"); if (!dir) return; while ((d = readdir(dir)) != NULL) { FILE *fp; char buf[192]; int level; int len; len = strlen(d->d_name); /* "CPUnn" */ if (len < 3 || len > BIG_SYSNAME_LEN) continue; sprintf(buf, "%s/%s/power", "/proc/acpi/processor", d->d_name); fp = fopen_for_read(buf); if (!fp) continue; // Example file contents: // active state: C0 // max_cstate: C8 // maximum allowed latency: 2000000000 usec // states: // C1: type[C1] promotion[--] demotion[--] latency[001] usage[00006173] duration[00000000000000000000] // C2: type[C2] promotion[--] demotion[--] latency[001] usage[00085191] duration[00000000000083024907] // C3: type[C3] promotion[--] demotion[--] latency[017] usage[01017622] duration[00000000017921327182] level = 0; while (fgets(buf, sizeof(buf), fp)) { char *p = strstr(buf, "age["); if (!p) continue; p += 4; usage[level] += bb_strtoull(p, NULL, 10) + 1; p = strstr(buf, "ation["); if (!p) continue; p += 6; duration[level] += bb_strtoull(p, NULL, 10); if (level >= MAX_CSTATE_COUNT-1) break; level++; if (level > G.maxcstate) /* update maxcstate */ G.maxcstate = level; } fclose(fp); } closedir(dir); }
static void do_pidfile(void) { FILE *f; unsigned pid; f = fopen_for_read(pidfile); if (f) { if (fscanf(f, "%u", &pid) == 1) check(pid); fclose(f); } else if (errno != ENOENT) bb_perror_msg_and_die("open pidfile %s", pidfile); }
static void process_cron_update_file(void) { FILE *fi; char buf[256]; fi = fopen_for_read(CRONUPDATE); if (fi != NULL) { unlink(CRONUPDATE); while (fgets(buf, sizeof(buf), fi) != NULL) { /* use first word only */ skip_non_whitespace(buf)[0] = '\0'; load_crontab(buf); } fclose(fi); } }
static int is_hpet_irq(const char *name) { char *p; # if BLOATY_HPET_IRQ_NUM_DETECTION long hpet_chan; /* Learn the range of existing hpet timers. This is done once */ if (!G.scanned_timer_list) { FILE *fp; char buf[80]; G.scanned_timer_list = true; fp = fopen_for_read("/proc/timer_list"); if (!fp) return 0; while (fgets(buf, sizeof(buf), fp)) { p = strstr(buf, "Clock Event Device: hpet"); if (!p) continue; p += sizeof("Clock Event Device: hpet")-1; if (!isdigit(*p)) continue; hpet_chan = xatoi_positive(p); if (hpet_chan < G.percpu_hpet_start) G.percpu_hpet_start = hpet_chan; if (hpet_chan > G.percpu_hpet_end) G.percpu_hpet_end = hpet_chan; } fclose(fp); } # endif //TODO: optimize p = strstr(name, "hpet"); if (!p) return 0; p += 4; if (!isdigit(*p)) return 0; # if BLOATY_HPET_IRQ_NUM_DETECTION hpet_chan = xatoi_positive(p); if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end) return 0; # endif return 1; }
/* * Check to see if we're dealing with the swap device. */ static int is_swap_device(const char *file) { FILE *f; char buf[1024], *cp; dev_t file_dev; struct stat st_buf; int ret = 0; file_dev = 0; #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ if ((stat(file, &st_buf) == 0) && S_ISBLK(st_buf.st_mode)) file_dev = st_buf.st_rdev; #endif /* __GNU__ */ if (!(f = fopen_for_read("/proc/swaps"))) return 0; /* Skip the first line */ fgets(buf, sizeof(buf), f); while (!feof(f)) { if (!fgets(buf, sizeof(buf), f)) break; if ((cp = strchr(buf, ' ')) != NULL) *cp = 0; if ((cp = strchr(buf, '\t')) != NULL) *cp = 0; if (strcmp(buf, file) == 0) { ret++; break; } #ifndef __GNU__ if (file_dev && (stat(buf, &st_buf) == 0) && S_ISBLK(st_buf.st_mode) && file_dev == st_buf.st_rdev) { ret++; break; } #endif /* __GNU__ */ } fclose(f); return ret; }
static unsigned get_hz(void) { static unsigned hz_internal; FILE *fp; if (hz_internal) return hz_internal; fp = fopen_for_read("/proc/net/psched"); if (fp) { unsigned nom, denom; if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) if (nom == 1000000) hz_internal = denom; fclose(fp); } if (!hz_internal) hz_internal = sysconf(_SC_CLK_TCK); return hz_internal; }
static void scan_proc_net(const char *path, unsigned port) { char line[MAX_LINE + 1]; long long uint64_inode; unsigned tmp_port; FILE *f; struct stat st; int fd; /* find socket dev */ st.st_dev = 0; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd >= 0) { fstat(fd, &st); close(fd); } f = fopen_for_read(path); if (!f) return; while (fgets(line, MAX_LINE, f)) { char addr[68]; if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " "%*x:%*x %*x %*d %*d %llu", addr, &tmp_port, &uint64_inode) == 3 ) { int len = strlen(addr); if (len == 8 && (option_mask32 & OPT_IP6)) continue; if (len > 8 && (option_mask32 & OPT_IP4)) continue; if (tmp_port == port) { st.st_ino = uint64_inode; add_inode(&st); } } } fclose(f); }
static inode_list *scan_proc_net(const char *proto, unsigned port, inode_list *ilist) { char path[20], line[MAX_LINE + 1]; ino_t tmp_inode; dev_t tmp_dev; long long uint64_inode; unsigned tmp_port; FILE *f; tmp_dev = find_socket_dev(); sprintf(path, "/proc/net/%s", proto); f = fopen_for_read(path); if (!f) return ilist; while (fgets(line, MAX_LINE, f)) { char addr[68]; if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " "%*x:%*x %*x %*d %*d %llu", addr, &tmp_port, &uint64_inode) == 3 ) { int len = strlen(addr); if (len == 8 && (option_mask32 & OPT_IP6)) continue; if (len > 8 && (option_mask32 & OPT_IP4)) continue; if (tmp_port == port) { tmp_inode = uint64_inode; ilist = add_inode(ilist, tmp_dev, tmp_inode); } } } fclose(f); return ilist; }
static void scan_pid_maps(const char *fname, pid_t pid) { FILE *file; char line[MAX_LINE + 1]; int major, minor; long long uint64_inode; struct stat st; file = fopen_for_read(fname); if (!file) return; while (fgets(line, MAX_LINE, file)) { if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) continue; st.st_ino = uint64_inode; if (major == 0 && minor == 0 && st.st_ino == 0) continue; st.st_dev = makedev(major, minor); if (search_dev_inode(&st)) add_pid(pid); } fclose(file); }
static NOINLINE int process_timer_stats(void) { char buf[128]; char line[15 + 3 + 128]; int n; FILE *fp; buf[0] = '\0'; n = 0; fp = NULL; if (!G.cant_enable_timer_stats) fp = fopen_for_read("/proc/timer_stats"); if (fp) { // Example file contents: // Timer Stats Version: v0.2 // Sample period: 1.329 s // 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) // 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) // 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) // 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) // ... // 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) // 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) // 331 total events, 249.059 events/sec while (fgets(buf, sizeof(buf), fp)) { const char *count, *process, *func; char *p; int idx; unsigned cnt; count = skip_whitespace(buf); p = strchr(count, ','); if (!p) continue; *p++ = '\0'; cnt = bb_strtou(count, NULL, 10); if (strcmp(skip_non_whitespace(count), " total events") == 0) { #if ENABLE_FEATURE_POWERTOP_PROCIRQ n = cnt / G.total_cpus; if (n > 0 && n < G.interrupt_0) { sprintf(line, " <interrupt> : %s", "extra timer interrupt"); save_line(line, G.interrupt_0 - n); } #endif break; } if (strchr(count, 'D')) continue; /* deferred */ p = skip_whitespace(p); /* points to pid now */ process = NULL; get_func_name: p = strchr(p, ' '); if (!p) continue; *p++ = '\0'; p = skip_whitespace(p); if (process == NULL) { process = p; goto get_func_name; } func = p; //if (strcmp(process, "swapper") == 0 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 //) { // process = "[kernel scheduler]"; // func = "Load balancing tick"; //} if (strncmp(func, "tick_nohz_", 10) == 0) continue; if (strncmp(func, "tick_setup_sched_timer", 20) == 0) continue; //if (strcmp(process, "powertop") == 0) // continue; idx = index_in_strings("insmod\0modprobe\0swapper\0", process); if (idx != -1) { process = idx < 2 ? "[kernel module]" : "<kernel core>"; } strchrnul(p, '\n')[0] = '\0'; // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn) // ^ ^ ^ // count process func //if (strchr(process, '[')) sprintf(line, "%15.15s : %s", process, func); //else // sprintf(line, "%s", process); save_line(line, cnt); } fclose(fp); } return n; }
int add_remove_shell_main(int argc UNUSED_PARAM, char **argv) { FILE *orig_fp; char *orig_fn; char *new_fn; struct stat sb; sb.st_mode = 0666; argv++; orig_fn = xmalloc_follow_symlinks(SHELLS_FILE); if (!orig_fn) return EXIT_FAILURE; orig_fp = fopen_for_read(orig_fn); if (orig_fp) xfstat(fileno(orig_fp), &sb, orig_fn); new_fn = xasprintf("%s.tmp", orig_fn); /* * O_TRUNC or O_EXCL? At the first glance, O_EXCL looks better, * since it prevents races. But: (1) it requires a retry loop, * (2) if /etc/shells.tmp is *stale*, then retry loop * with O_EXCL will never succeed - it should have a timeout, * after which it should revert to O_TRUNC. * For now, I settle for O_TRUNC instead. */ xmove_fd(xopen3(new_fn, O_WRONLY | O_CREAT | O_TRUNC, sb.st_mode), STDOUT_FILENO); /* TODO? xfchown(STDOUT_FILENO, sb.st_uid, sb.st_gid); */ if (orig_fp) { /* Copy old file, possibly skipping removed shell names */ char *line; while ((line = xmalloc_fgetline(orig_fp)) != NULL) { char **cpp = argv; while (*cpp) { if (*cpp != dont_add && strcmp(*cpp, line) == 0) { /* Old file has this shell name */ if (REMOVE_SHELL) { /* we are remove-shell */ /* delete this name by not copying it */ goto next_line; } /* we are add-shell */ /* mark this name as "do not add" */ *cpp = dont_add; } cpp++; } /* copy shell name from old to new file */ puts(line); next_line: free(line); } if (ENABLE_FEATURE_CLEAN_UP) fclose(orig_fp); } if (ADD_SHELL) { char **cpp = argv; while (*cpp) { if (*cpp != dont_add) puts(*cpp); cpp++; } } /* Ensure we wrote out everything */ if (fclose(stdout) != 0) { xunlink(new_fn); bb_perror_msg_and_die("%s: write error", new_fn); } /* Small hole: if rename fails, /etc/shells.tmp is not removed */ xrename(new_fn, orig_fn); if (ENABLE_FEATURE_CLEAN_UP) { free(orig_fn); free(new_fn); } return EXIT_SUCCESS; }
#ifndef GETXXKEY_R_FUNC #error GETXXKEY_R_FUNC is not defined! #endif int GETXXKEY_R_FUNC(GETXXKEY_R_KEYTYPE key, GETXXKEY_R_ENTTYPE *__restrict resultbuf, char *__restrict buffer, size_t buflen, GETXXKEY_R_ENTTYPE **__restrict result) { FILE *stream; int rv; *result = NULL; stream = fopen_for_read(GETXXKEY_R_PATHNAME); if (!stream) return errno; while (1) { rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream); if (!rv) { if (GETXXKEY_R_TEST(resultbuf)) { /* found key? */ *result = resultbuf; break; } } else { if (rv == ENOENT) { /* EOF encountered */ rv = 0; } break; }
static void process_files(void) { char *pattern_space, *next_line; int linenum = 0; char last_puts_char = '\n'; char last_gets_char, next_gets_char; sed_cmd_t *sed_cmd; int substituted; /* Prime the pump */ next_line = get_next_line(&next_gets_char, &last_puts_char); /* Go through every line in each file */ again: substituted = 0; /* Advance to next line. Stop if out of lines. */ pattern_space = next_line; if (!pattern_space) return; last_gets_char = next_gets_char; /* Read one line in advance so we can act on the last line, * the '$' address */ next_line = get_next_line(&next_gets_char, &last_puts_char); linenum++; /* For every line, go through all the commands */ restart: for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { int old_matched, matched; old_matched = sed_cmd->in_match; /* Determine if this command matches this line: */ dbg("match1:%d", sed_cmd->in_match); dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line && !sed_cmd->beg_match && !sed_cmd->end_match)); dbg("match3:%d", (sed_cmd->beg_line > 0 && (sed_cmd->end_line || sed_cmd->end_match ? (sed_cmd->beg_line <= linenum) : (sed_cmd->beg_line == linenum) ) )); dbg("match4:%d", (beg_match(sed_cmd, pattern_space))); dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); /* Are we continuing a previous multi-line match? */ sed_cmd->in_match = sed_cmd->in_match /* Or is no range necessary? */ || (!sed_cmd->beg_line && !sed_cmd->end_line && !sed_cmd->beg_match && !sed_cmd->end_match) /* Or did we match the start of a numerical range? */ || (sed_cmd->beg_line > 0 && (sed_cmd->end_line || sed_cmd->end_match /* note: even if end is numeric and is < linenum too, * GNU sed matches! We match too, therefore we don't * check here that linenum <= end. * Example: * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p' * first three input lines are deleted; * 4th line is matched and printed * by "2,3" (!) and by "4" ranges */ ? (sed_cmd->beg_line <= linenum) /* N,end */ : (sed_cmd->beg_line == linenum) /* N */ ) ) /* Or does this line match our begin address regex? */ || (beg_match(sed_cmd, pattern_space)) /* Or did we match last line of input? */ || (sed_cmd->beg_line == -1 && next_line == NULL); /* Snapshot the value */ matched = sed_cmd->in_match; dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); /* Is this line the end of the current match? */ if (matched) { if (sed_cmd->end_line <= -2) { /* address2 is +N, i.e. N lines from beg_line */ sed_cmd->end_line = linenum + (-sed_cmd->end_line - 2); } /* once matched, "n,xxx" range is dead, disabling it */ if (sed_cmd->beg_line > 0) { sed_cmd->beg_line = -2; } dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1 ? !next_line : (sed_cmd->end_line <= linenum) : !sed_cmd->end_match); dbg("end2:%d", sed_cmd->end_match && old_matched && !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0)); sed_cmd->in_match = !( /* has the ending line come, or is this a single address command? */ (sed_cmd->end_line ? sed_cmd->end_line == -1 ? !next_line : (sed_cmd->end_line <= linenum) : !sed_cmd->end_match ) /* or does this line matches our last address regex */ || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0) ) ); } /* Skip blocks of commands we didn't match */ if (sed_cmd->cmd == '{') { if (sed_cmd->invert ? matched : !matched) { unsigned nest_cnt = 0; while (1) { if (sed_cmd->cmd == '{') nest_cnt++; if (sed_cmd->cmd == '}') { nest_cnt--; if (nest_cnt == 0) break; } sed_cmd = sed_cmd->next; if (!sed_cmd) bb_error_msg_and_die("unterminated {"); } } continue; } /* Okay, so did this line match? */ if (sed_cmd->invert ? matched : !matched) continue; /* no */ /* Update last used regex in case a blank substitute BRE is found */ if (sed_cmd->beg_match) { G.previous_regex_ptr = sed_cmd->beg_match; } /* actual sedding */ dbg("pattern_space:'%s' next_line:'%s' cmd:%c", pattern_space, next_line, sed_cmd->cmd); switch (sed_cmd->cmd) { /* Print line number */ case '=': fprintf(G.nonstdout, "%d\n", linenum); break; /* Write the current pattern space up to the first newline */ case 'P': { char *tmp = strchr(pattern_space, '\n'); if (tmp) { *tmp = '\0'; /* TODO: explain why '\n' below */ sed_puts(pattern_space, '\n'); *tmp = '\n'; break; } /* Fall Through */ } /* Write the current pattern space to output */ case 'p': /* NB: we print this _before_ the last line * (of current file) is printed. Even if * that line is nonterminated, we print * '\n' here (gnu sed does the same) */ sed_puts(pattern_space, '\n'); break; /* Delete up through first newline */ case 'D': { char *tmp = strchr(pattern_space, '\n'); if (tmp) { overlapping_strcpy(pattern_space, tmp + 1); goto restart; } } /* discard this line. */ case 'd': goto discard_line; /* Substitute with regex */ case 's': if (!do_subst_command(sed_cmd, &pattern_space)) break; dbg("do_subst_command succeeded:'%s'", pattern_space); substituted |= 1; /* handle p option */ if (sed_cmd->sub_p) sed_puts(pattern_space, last_gets_char); /* handle w option */ if (sed_cmd->sw_file) puts_maybe_newline( pattern_space, sed_cmd->sw_file, &sed_cmd->sw_last_char, last_gets_char); break; /* Append line to linked list to be printed later */ case 'a': append(xstrdup(sed_cmd->string)); break; /* Insert text before this line */ case 'i': sed_puts(sed_cmd->string, '\n'); break; /* Cut and paste text (replace) */ case 'c': /* Only triggers on last line of a matching range. */ if (!sed_cmd->in_match) sed_puts(sed_cmd->string, '\n'); goto discard_line; /* Read file, append contents to output */ case 'r': { FILE *rfile; rfile = fopen_for_read(sed_cmd->string); if (rfile) { char *line; while ((line = xmalloc_fgetline(rfile)) != NULL) append(line); fclose(rfile); } break; } /* Write pattern space to file. */ case 'w': puts_maybe_newline( pattern_space, sed_cmd->sw_file, &sed_cmd->sw_last_char, last_gets_char); break; /* Read next line from input */ case 'n': if (!G.be_quiet) sed_puts(pattern_space, last_gets_char); if (next_line == NULL) { /* If no next line, jump to end of script and exit. */ goto discard_line; } free(pattern_space); pattern_space = next_line; last_gets_char = next_gets_char; next_line = get_next_line(&next_gets_char, &last_puts_char); substituted = 0; linenum++; break; /* Quit. End of script, end of input. */ case 'q': /* Exit the outer while loop */ free(next_line); next_line = NULL; goto discard_commands; /* Append the next line to the current line */ case 'N': { int len; /* If no next line, jump to end of script and exit. */ /* http://www.gnu.org/software/sed/manual/sed.html: * "Most versions of sed exit without printing anything * when the N command is issued on the last line of * a file. GNU sed prints pattern space before exiting * unless of course the -n command switch has been * specified. This choice is by design." */ if (next_line == NULL) { //goto discard_line; goto discard_commands; /* GNU behavior */ } /* Append next_line, read new next_line. */ len = strlen(pattern_space); pattern_space = xrealloc(pattern_space, len + strlen(next_line) + 2); pattern_space[len] = '\n'; strcpy(pattern_space + len+1, next_line); last_gets_char = next_gets_char; next_line = get_next_line(&next_gets_char, &last_puts_char); linenum++; break; } /* Test/branch if substitution occurred */ case 't': if (!substituted) break; substituted = 0; /* Fall through */ /* Test/branch if substitution didn't occur */ case 'T': if (substituted) break; /* Fall through */ /* Branch to label */ case 'b': if (!sed_cmd->string) goto discard_commands; else sed_cmd = branch_to(sed_cmd->string); break; /* Transliterate characters */ case 'y': { int i, j; for (i = 0; pattern_space[i]; i++) { for (j = 0; sed_cmd->string[j]; j += 2) { if (pattern_space[i] == sed_cmd->string[j]) { pattern_space[i] = sed_cmd->string[j + 1]; break; } } } break; } case 'g': /* Replace pattern space with hold space */ free(pattern_space); pattern_space = xstrdup(G.hold_space ? G.hold_space : ""); break; case 'G': /* Append newline and hold space to pattern space */ { int pattern_space_size = 2; int hold_space_size = 0; if (pattern_space) pattern_space_size += strlen(pattern_space); if (G.hold_space) hold_space_size = strlen(G.hold_space); pattern_space = xrealloc(pattern_space, pattern_space_size + hold_space_size); if (pattern_space_size == 2) pattern_space[0] = 0; strcat(pattern_space, "\n"); if (G.hold_space) strcat(pattern_space, G.hold_space); last_gets_char = '\n'; break; } case 'h': /* Replace hold space with pattern space */ free(G.hold_space); G.hold_space = xstrdup(pattern_space); break; case 'H': /* Append newline and pattern space to hold space */ { int hold_space_size = 2; int pattern_space_size = 0; if (G.hold_space) hold_space_size += strlen(G.hold_space); if (pattern_space) pattern_space_size = strlen(pattern_space); G.hold_space = xrealloc(G.hold_space, hold_space_size + pattern_space_size); if (hold_space_size == 2) *G.hold_space = 0; strcat(G.hold_space, "\n"); if (pattern_space) strcat(G.hold_space, pattern_space); break; } case 'x': /* Exchange hold and pattern space */ { char *tmp = pattern_space; pattern_space = G.hold_space ? G.hold_space : xzalloc(1); last_gets_char = '\n'; G.hold_space = tmp; break; } } /* switch */ } /* for each cmd */ /* * Exit point from sedding... */ discard_commands: /* we will print the line unless we were told to be quiet ('-n') or if the line was suppressed (ala 'd'elete) */ if (!G.be_quiet) sed_puts(pattern_space, last_gets_char); /* Delete and such jump here. */ discard_line: flush_append(&last_puts_char /*,last_gets_char*/); free(pattern_space); goto again; }
int more_main(int argc UNUSED_PARAM, char **argv) { int c = c; /* for compiler */ int lines; int input = 0; int spaces = 0; int please_display_more_prompt; struct stat st; FILE *file; FILE *cin; int len; unsigned terminal_width; unsigned terminal_height; INIT_G(); argv++; /* Another popular pager, most, detects when stdout * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); cin = fopen_for_read(CURRENT_TTY); if (!cin) return bb_cat(argv); if (ENABLE_FEATURE_USE_TERMIOS) { cin_fileno = fileno(cin); getTermSettings(cin_fileno, &initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~(ICANON | ECHO); new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; setTermSettings(cin_fileno, &new_settings); bb_signals(0 + (1 << SIGINT) + (1 << SIGQUIT) + (1 << SIGTERM) , gotsig); } do { file = stdin; if (*argv) { file = fopen_or_warn(*argv, "r"); if (!file) continue; } st.st_size = 0; fstat(fileno(file), &st); please_display_more_prompt = 0; /* never returns w, h <= 1 */ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); terminal_height -= 1; len = 0; lines = 0; while (spaces || (c = getc(file)) != EOF) { int wrap; if (spaces) spaces--; loop_top: if (input != 'r' && please_display_more_prompt) { len = printf("--More-- "); if (st.st_size != 0) { uoff_t d = (uoff_t)st.st_size / 100; if (d == 0) d = 1; len += printf("(%u%% of %"OFF_FMT"u bytes)", (int) ((uoff_t)ftello(file) / d), st.st_size); } fflush_all(); /* * We've just displayed the "--More--" prompt, so now we need * to get input from the user. */ for (;;) { input = getc(cin); input = tolower(input); if (!ENABLE_FEATURE_USE_TERMIOS) printf("\033[A"); /* cursor up */ /* Erase the last message */ printf("\r%*s\r", len, ""); /* Due to various multibyte escape * sequences, it's not ok to accept * any input as a command to scroll * the screen. We only allow known * commands, else we show help msg. */ if (input == ' ' || input == '\n' || input == 'q' || input == 'r') break; len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); } len = 0; lines = 0; please_display_more_prompt = 0; if (input == 'q') goto end; /* The user may have resized the terminal. * Re-read the dimensions. */ if (ENABLE_FEATURE_USE_TERMIOS) { get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height); terminal_height -= 1; } } /* Crudely convert tabs into spaces, which are * a bajillion times easier to deal with. */ if (c == '\t') { spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE; c = ' '; } /* * There are two input streams to worry about here: * * c : the character we are reading from the file being "mored" * input: a character received from the keyboard * * If we hit a newline in the _file_ stream, we want to test and * see if any characters have been hit in the _input_ stream. This * allows the user to quit while in the middle of a file. */ wrap = (++len > terminal_width); if (c == '\n' || wrap) { /* Then outputting this character * will move us to a new line. */ if (++lines >= terminal_height || input == '\n') please_display_more_prompt = 1; len = 0; } if (c != '\n' && wrap) { /* Then outputting this will also put a character on * the beginning of that new line. Thus we first want to * display the prompt (if any), so we skip the putchar() * and go back to the top of the loop, without reading * a new character. */ putchar('\n'); goto loop_top; } /* My small mind cannot fathom backspaces and UTF-8 */ putchar(c); die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */ } fclose(file); fflush_all(); } while (*argv && *++argv); end: setTermSettings(cin_fileno, &initial_settings); return 0; }
static smallint scan_proc_net_or_maps(const char *path, unsigned port) { FILE *f; char line[MAX_LINE + 1], addr[68]; int major, minor, r; long long uint64_inode; unsigned tmp_port; smallint retval; struct stat statbuf; const char *fmt; void *f*g, *sag; f = fopen_for_read(path); if (!f) return 0; if (G.recursion_depth == PROC_NET) { int fd; /* find socket dev */ statbuf.st_dev = 0; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd >= 0) { fstat(fd, &statbuf); close(fd); } fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x " "%*x:%*x %*x:%*x %*x %*d %*d %llu"; f*g = addr; sag = &tmp_port; } else { fmt = "%*s %*s %*s %x:%x %llu"; f*g = &major; sag = &minor; } retval = 0; while (fgets(line, MAX_LINE, f)) { r = sscanf(line, fmt, f*g, sag, &uint64_inode); if (r != 3) continue; statbuf.st_ino = uint64_inode; if (G.recursion_depth == PROC_NET) { r = strlen(addr); if (r == 8 && (option_mask32 & OPT_IP6)) continue; if (r > 8 && (option_mask32 & OPT_IP4)) continue; if (tmp_port == port) add_inode(&statbuf); } else { if (major != 0 && minor != 0 && statbuf.st_ino != 0) { statbuf.st_dev = makedev(major, minor); retval = search_dev_inode(&statbuf); if (retval) break; } } } fclose(f); return retval; }
void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) { FILE *fp; int c; char buf[256+1]; const char *outbuf; time_t t; struct utsname uts; time(&t); uname(&uts); puts("\r"); /* start a new line */ fp = fopen_for_read(issue_file); if (!fp) return; while ((c = fgetc(fp)) != EOF) { outbuf = buf; buf[0] = c; buf[1] = '\0'; if (c == '\n') { buf[1] = '\r'; buf[2] = '\0'; } if (c == '\\' || c == '%') { c = fgetc(fp); switch (c) { case 's': outbuf = uts.sysname; break; case 'n': case 'h': outbuf = uts.nodename; break; case 'r': outbuf = uts.release; break; case 'v': outbuf = uts.version; break; case 'm': outbuf = uts.machine; break; /* The field domainname of struct utsname is Linux specific. */ #if defined(__linux__) case 'D': case 'o': outbuf = uts.domainname; break; #endif case 'd': strftime(buf, sizeof(buf), fmtstr_d, localtime(&t)); break; case 't': strftime(buf, sizeof(buf), fmtstr_t, localtime(&t)); break; case 'l': outbuf = tty; break; default: buf[0] = c; } } fputs(outbuf, stdout); } fclose(fp); fflush(stdout); }
void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) { FILE *fp; int c; char buf[256+1]; const char *outbuf; time_t t; struct utsname uts; time(&t); uname(&uts); puts("\r"); /* start a new line */ fp = fopen_for_read(issue_file); if (!fp) return; while ((c = fgetc(fp)) != EOF) { outbuf = buf; buf[0] = c; buf[1] = '\0'; if (c == '\n') { buf[1] = '\r'; buf[2] = '\0'; } if (c == '\\' || c == '%') { c = fgetc(fp); switch (c) { //From getty manpage (* - supported by us) //======================================== //4 or 4{interface} // Insert the IPv4 address of the network interface (example: \4{eth0}). // If the interface argument is not specified, then select the first // fully configured (UP, non-LOOPBACK, RUNNING) interface. //6 or 6{interface} -- The same as \4 but for IPv6. //b -- Insert the baudrate of the current line. //*d -- Insert the current date. //*t -- Insert the current time. //e or e{name} // Translate the human-readable name to an escape sequence and insert it // (for example: \e{red}Alert text.\e{reset}). If the name argument // is not specified, then insert \033. The currently supported names are: // black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright, // lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred, // magenta, red, reset, reverse, and yellow. Unknown names are ignored. //*s // Insert the system name (the name of the operating system - `uname -s`) //*S or S{VARIABLE} // Insert the VARIABLE data from /etc/os-release. // If the VARIABLE argument is not specified, use PRETTY_NAME. // If PRETTY_NAME is not in /etc/os-release, \S is the same as \s. //*l -- Insert the name of the current tty line. //*m -- Insert the architecture identifier of the machine: `uname -m`. //*n -- Insert the nodename of the machine: `uname -n`. //*o -- Insert the NIS domainname of the machine. Same as `hostname -d'. //*O -- Insert the DNS domainname of the machine. //*r -- Insert the release number of the OS: `uname -r`. //u -- Insert the number of current users logged in. //U -- Insert the string "1 user" or "N users" (current users logged in). //*v -- Insert the version of the OS, e.g. the build-date etc: `uname -v`. //We also implement: //*D -- same as \O "DNS domainname" //*h -- same as \n "nodename" case 'S': /* minimal implementation, not reading /etc/os-release */ /*FALLTHROUGH*/ case 's': outbuf = uts.sysname; break; case 'n': case 'h': outbuf = uts.nodename; break; case 'r': outbuf = uts.release; break; case 'v': outbuf = uts.version; break; case 'm': outbuf = uts.machine; break; /* The field domainname of struct utsname is Linux specific. */ #if defined(__linux__) case 'D': case 'o': case 'O': outbuf = uts.domainname; break; #endif case 'd': strftime(buf, sizeof(buf), fmtstr_d, localtime(&t)); break; case 't': strftime_HHMMSS(buf, sizeof(buf), &t); break; case 'l': outbuf = tty; break; default: buf[0] = c; } } fputs(outbuf, stdout); } fclose(fp); fflush_all(); }