static int smtp_checkp(const char *fmt, const char *param, int code) { char *answer; char *msg = send_mail_command(fmt, param); // read stdin // if the string has a form NNN- -- read next string. E.g. EHLO response // parse first bytes to a number // if code = -1 then just return this number // if code != -1 then checks whether the number equals the code // if not equal -> die saying msg while ((answer = xmalloc_fgetline(stdin)) != NULL) { if (verbose) bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer); if (strlen(answer) <= 3 || '-' != answer[3]) break; free(answer); } if (answer) { int n = atoi(answer); if (timeout) alarm(0); free(answer); if (-1 == code || n == code) { free(msg); return n; } } bb_error_msg_and_die("%s failed", msg); }
static bool ignored_problems_file_contains(ignored_problems_t *set, const char *problem_id, const char *uuid, const char *duphash, FILE **out_fp, const char *mode) { bool found = false; FILE *fp = fopen(set->ign_set_file_path, mode); if (!fp) { pwarn_msg("Can't open ignored problems '%s' in mode '%s'", set->ign_set_file_path, mode); goto ret_contains_end; } unsigned line_num = 0; while (!found) { char *line = xmalloc_fgetline(fp); if (!line) break; ++line_num; found = ignored_problems_eq(set, problem_id, uuid, duphash, line, line_num); free(line); } ret_contains_end: if (out_fp) *out_fp = fp; else if (fp) fclose(fp); return found; }
int cryptpw_main(int argc UNUSED_PARAM, char **argv) { /* Supports: cryptpw -m sha256 PASS 'rounds=999999999$SALT' */ char salt[MAX_PW_SALT_LEN + sizeof("rounds=999999999$")]; char *salt_ptr; char *password; const char *opt_m, *opt_S; int fd; #if ENABLE_LONG_OPTS static const char mkpasswd_longopts[] ALIGN1 = "stdin\0" No_argument "s" "password-fd\0" Required_argument "P" "salt\0" Required_argument "S" "method\0" Required_argument "m" ; applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2"; getopt32(argv, "sP:+S:m:a:", &fd, &opt_S, &opt_m, &opt_m); argv += optind; /* have no idea how to handle -s... */ if (argv[0] && !opt_S) opt_S = argv[1]; salt_ptr = crypt_make_pw_salt(salt, opt_m); if (opt_S) /* put user's data after the "$N$" prefix */ safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); xmove_fd(fd, STDIN_FILENO); password = argv[0]; if (!password) { /* Only mkpasswd, and only from tty, prompts. * Otherwise it is a plain read. */ password = (ENABLE_MKPASSWD && isatty(STDIN_FILENO) && applet_name[0] == 'm') ? bb_ask_stdin("Password: ") : xmalloc_fgetline(stdin) ; /* may still be NULL on EOF/error */ } if (password) puts(pw_encrypt(password, salt, 1)); return EXIT_SUCCESS; }
static void bb_dump_addfile(dumper_t *dumper, char *name) { char *p; FILE *fp; char *buf; fp = xfopen_for_read(name); while ((buf = xmalloc_fgetline(fp)) != NULL) { p = skip_whitespace(buf); if (*p && (*p != '#')) { bb_dump_add(dumper, p); } free(buf); } fclose(fp); }
int cryptpw_main(int argc UNUSED_PARAM, char **argv) { char salt[MAX_PW_SALT_LEN]; char *salt_ptr; const char *opt_m, *opt_S; int fd; #if ENABLE_LONG_OPTS static const char mkpasswd_longopts[] ALIGN1 = "stdin\0" No_argument "s" "password-fd\0" Required_argument "P" "salt\0" Required_argument "S" "method\0" Required_argument "m" ; applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; opt_m = "d"; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2:P+"; getopt32(argv, "sP:S:m:a:", &fd, &opt_S, &opt_m, &opt_m); argv += optind; /* have no idea how to handle -s... */ if (argv[0] && !opt_S) opt_S = argv[1]; salt_ptr = crypt_make_pw_salt(salt, opt_m); if (opt_S) safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); xmove_fd(fd, STDIN_FILENO); puts(pw_encrypt( argv[0] ? argv[0] : ( /* Only mkpasswd, and only from tty, prompts. * Otherwise it is a plain read. */ (isatty(STDIN_FILENO) && applet_name[0] == 'm') ? bb_ask_stdin("Password: ") : xmalloc_fgetline(stdin) ), salt, 1)); return EXIT_SUCCESS; }
static void pop3_checkr(const char *fmt, const char *param, char **ret) { const char *msg = command(fmt, param); char *answer = xmalloc_fgetline(stdin); if (answer && '+' == answer[0]) { if (timeout) alarm(0); if (ret) { // skip "+OK " memmove(answer, answer + 4, strlen(answer) - 4); *ret = answer; } else free(answer); return; } bb_error_msg_and_die("%s failed: %s", msg, answer); }
static llist_t *append_file_list_to_list(llist_t *list) { FILE *src_stream; char *line; llist_t *newlist = NULL; while (list) { src_stream = xfopen_for_read(llist_pop(&list)); while ((line = xmalloc_fgetline(src_stream)) != NULL) { /* kill trailing '/' unless the string is just "/" */ char *cp = last_char_is(line, '/'); if (cp > line) *cp = '\0'; llist_add_to(&newlist, line); } fclose(src_stream); } return newlist; }
static void add_user_to_group(char **args, const char *path, FILE *(*fopen_func)(const char *fileName, const char *mode)) { char *line; int len = strlen(args[1]); llist_t *plist = NULL; FILE *group_file; group_file = fopen_func(path, "r"); if (!group_file) return; while ((line = xmalloc_fgetline(group_file)) != NULL) { /* Find the group */ if (!strncmp(line, args[1], len) && line[len] == ':' ) { /* Add the new user */ line = xasprintf("%s%s%s", line, last_char_is(line, ':') ? "" : ",", args[0]); } llist_add_to_end(&plist, line); } if (ENABLE_FEATURE_CLEAN_UP) { fclose(group_file); group_file = fopen_func(path, "w"); while ((line = llist_pop(&plist))) { if (group_file) fprintf(group_file, "%s\n", line); free(line); } if (group_file) fclose(group_file); } else { group_file = fopen_func(path, "w"); if (group_file) while ((line = llist_pop(&plist))) fprintf(group_file, "%s\n", line); } }
void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename) { FILE *fp = fopen_or_warn_stdin(filename); unsigned N = ns->start; char *line; while ((line = xmalloc_fgetline(fp)) != NULL) { if (ns->all || (ns->nonempty && line[0]) ) { printf("%*u%s%s\n", ns->width, N, ns->sep, line); N += ns->inc; } else if (ns->empty_str) fputs(ns->empty_str, stdout); free(line); } ns->start = N; fclose(fp); }
GList *load_words_from_file(const char* filename) { GList *words_list = NULL; GList *file_list = NULL; file_list = g_list_prepend(file_list, concat_path_file(CONF_DIR, filename)); file_list = g_list_prepend(file_list, get_user_config_file_path(filename, /*don't append suffix*/NULL)); GList *file_list_cur = file_list; while(file_list_cur) { char *cur_file = (char *)file_list_cur->data; FILE *fp = fopen(cur_file, "r"); if (fp) { /* every line is one word */ char *line; while ((line = xmalloc_fgetline(fp)) != NULL) { //FIXME: works only if the '#' is first char won't work for " #abcd# if (line[0] != '#') // if it's not comment words_list = g_list_append(words_list, line); else free(line); } fclose(fp); } else { log_warning("Can't open %s", cur_file); } file_list_cur = g_list_next(file_list_cur); } list_free_with_free(file_list); return words_list; }
static int smtp_checkp(const char *fmt, const char *param, int code) { char *answer; const char *msg = command(fmt, param); // read stdin // if the string has a form \d\d\d- -- read next string. E.g. EHLO response // parse first bytes to a number // if code = -1 then just return this number // if code != -1 then checks whether the number equals the code // if not equal -> die saying msg while ((answer = xmalloc_fgetline(stdin)) != NULL) if (strlen(answer) <= 3 || '-' != answer[3]) break; if (answer) { int n = atoi(answer); if (timeout) alarm(0); free(answer); if (-1 == code || n == code) return n; } bb_error_msg_and_die("%s failed", msg); }
int cryptpw_main(int argc UNUSED_PARAM, char **argv) { char salt[sizeof("$N$XXXXXXXX")]; char *opt_a; if (!getopt32(argv, "a:", &opt_a) || opt_a[0] != 'd') { salt[0] = '$'; salt[1] = '1'; salt[2] = '$'; crypt_make_salt(salt + 3, 4, 0); /* md5 */ #if TESTING strcpy(salt + 3, "ajg./bcf"); #endif } else { crypt_make_salt(salt, 1, 0); /* des */ #if TESTING strcpy(salt, "a."); #endif } puts(pw_encrypt(argv[optind] ? argv[optind] : xmalloc_fgetline(stdin), salt, 1)); return 0; }
int patch_main(int argc UNUSED_PARAM, char **argv) { int opts; int reverse, state = 0; char *oldname = NULL, *newname = NULL; char *opt_p, *opt_i; long oldlen = oldlen; /* for compiler */ long newlen = newlen; /* for compiler */ INIT_TT(); opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); argv += optind; reverse = opts & FLAG_REVERSE; TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! TT.filein = TT.fileout = -1; if (opts & FLAG_INPUT) { xmove_fd(xopen_stdin(opt_i), STDIN_FILENO); } else { if (argv[0] && argv[1]) { xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); } } if (argv[0]) { oldname = xstrdup(argv[0]); newname = xstrdup(argv[0]); } // Loop through the lines in the patch for(;;) { char *patchline; patchline = xmalloc_fgetline(stdin); if (!patchline) break; // Other versions of patch accept damaged patches, // so we need to also. if (!*patchline) { free(patchline); patchline = xstrdup(" "); } // Are we assembling a hunk? if (state >= 2) { if (*patchline==' ' || *patchline=='+' || *patchline=='-') { dlist_add(&TT.current_hunk, patchline); if (*patchline != '+') oldlen--; if (*patchline != '-') newlen--; // Context line? if (*patchline==' ' && state==2) TT.context++; else state=3; // If we've consumed all expected hunk lines, apply the hunk. if (!oldlen && !newlen) state = apply_one_hunk(); continue; } fail_hunk(); state = 0; continue; } // Open a new file? if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { char *s, **name = reverse ? &newname : &oldname; int i; if (*patchline == '+') { name = reverse ? &oldname : &newname; state = 1; } finish_oldfile(); if (!argv[0]) { free(*name); // Trim date from end of filename (if any). We don't care. for (s = patchline+4; *s && *s!='\t'; s++) if (*s=='\\' && s[1]) s++; i = atoi(s); if (i>1900 && i<=1970) *name = xstrdup("/dev/null"); else { *s = 0; *name = xstrdup(patchline+4); } } // We defer actually opening the file because svn produces broken // patches that don't signal they want to create a new file the // way the patch man page says, so you have to read the first hunk // and _guess_. // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ // but a missing ,value means the value is 1. } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { int i; char *s = patchline+4; // Read oldline[,oldlen] +newline[,newlen] TT.oldlen = oldlen = TT.newlen = newlen = 1; TT.oldline = strtol(s, &s, 10); if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); TT.newline = strtol(s+2, &s, 10); if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); if (oldlen < 1 && newlen < 1) bb_error_msg_and_die("Really? %s", patchline); TT.context = 0; state = 2; // If this is the first hunk, open the file. if (TT.filein == -1) { int oldsum, newsum, empty = 0; char *name; oldsum = TT.oldline + oldlen; newsum = TT.newline + newlen; name = reverse ? oldname : newname; // We're deleting oldname if new file is /dev/null (before -p) // or if new hunk is empty (zero context) after patching if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { name = reverse ? newname : oldname; empty++; } // handle -p path truncation. for (i=0, s = name; *s;) { if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; if (*s++ != '/') continue; while (*s == '/') s++; i++; name = s; } if (empty) { // File is empty after the patches have been applied state = 0; if (option_mask32 & FLAG_RMEMPTY) { // If flag -E or --remove-empty-files is set printf("removing %s\n", name); xunlink(name); } else { printf("patching file %s\n", name); xclose(xopen(name, O_WRONLY | O_TRUNC)); } // If we've got a file to open, do so. } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { struct stat statbuf; // If the old file was null, we're creating a new one. if (!strcmp(oldname, "/dev/null") || !oldsum) { printf("creating %s\n", name); s = strrchr(name, '/'); if (s) { *s = 0; bb_make_directory(name, -1, FILEUTILS_RECUR); *s = '/'; } TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); } else { printf("patching file %s\n", name); TT.filein = xopen(name, O_RDONLY); } TT.tempname = xasprintf("%sXXXXXX", name); TT.fileout = xmkstemp(TT.tempname); // Set permissions of output file fstat(TT.filein, &statbuf); fchmod(TT.fileout, statbuf.st_mode); TT.linenum = 0; TT.hunknum = 0; } } TT.hunknum++; continue; } // If we didn't continue above, discard this line. free(patchline); } finish_oldfile(); if (ENABLE_FEATURE_CLEAN_UP) { free(oldname); free(newname); } return TT.exitval; }
int sendmail_main(int argc UNUSED_PARAM, char **argv) { char *opt_connect = opt_connect; char *opt_from = NULL; char *s; llist_t *list = NULL; char *host = sane_address(safe_gethostname()); unsigned nheaders = 0; int code; enum { HDR_OTHER = 0, HDR_TOCC, HDR_BCC, } last_hdr = 0; int check_hdr; int has_to = 0; enum { //--- standard options OPT_t = 1 << 0, // read message for recipients, append them to those on cmdline OPT_f = 1 << 1, // sender address OPT_o = 1 << 2, // various options. -oi IMPLIED! others are IGNORED! OPT_i = 1 << 3, // IMPLIED! //--- BB specific options OPT_w = 1 << 4, // network timeout OPT_H = 1 << 5, // use external connection helper OPT_S = 1 << 6, // specify connection string OPT_a = 1 << 7, // authentication tokens OPT_v = 1 << 8, // verbosity }; // init global variables INIT_G(); // save initial stdin since body is piped! xdup2(STDIN_FILENO, 3); G.fp0 = xfdopen_for_read(3); // parse options // -v is a counter, -H and -S are mutually exclusive, -a is a list opt_complementary = "vv:w+:H--S:S--H:a::"; // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, // it is still under development. opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list, &verbose); //argc -= optind; argv += optind; // process -a[upm]<token> options if ((opts & OPT_a) && !list) bb_show_usage(); while (list) { char *a = (char *) llist_pop(&list); if ('u' == a[0]) G.user = xstrdup(a+1); if ('p' == a[0]) G.pass = xstrdup(a+1); // N.B. we support only AUTH LOGIN so far //if ('m' == a[0]) // G.method = xstrdup(a+1); } // N.B. list == NULL here //bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv); // connect to server // connection helper ordered? -> if (opts & OPT_H) { const char *args[] = { "sh", "-c", opt_connect, NULL }; // plug it in launch_helper(args); // Now: // our stdout will go to helper's stdin, // helper's stdout will be available on our stdin. // Wait for initial server message. // If helper (such as openssl) invokes STARTTLS, the initial 220 // is swallowed by helper (and not repeated after TLS is initiated). // We will send NOOP cmd to server and check the response. // We should get 220+250 on plain connection, 250 on STARTTLSed session. // // The problem here is some servers delay initial 220 message, // and consider client to be a spammer if it starts sending cmds // before 220 reached it. The code below is unsafe in this regard: // in non-STARTTLSed case, we potentially send NOOP before 220 // is sent by server. // Ideas? (--delay SECS opt? --assume-starttls-helper opt?) code = smtp_check("NOOP", -1); if (code == 220) // we got 220 - this is not STARTTLSed connection, // eat 250 response to our NOOP smtp_check(NULL, 250); else if (code != 250) bb_error_msg_and_die("SMTP init failed"); } else { // vanilla connection int fd; // host[:port] not explicitly specified? -> use $SMTPHOST // no $SMTPHOST? -> use localhost if (!(opts & OPT_S)) { opt_connect = getenv("SMTPHOST"); if (!opt_connect) opt_connect = (char *)"127.0.0.1"; } // do connect fd = create_and_connect_stream_or_die(opt_connect, 25); // and make ourselves a simple IO filter xmove_fd(fd, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); // Wait for initial server 220 message smtp_check(NULL, 220); } // we should start with modern EHLO if (250 != smtp_checkp("EHLO %s", host, -1)) smtp_checkp("HELO %s", host, 250); // perform authentication if (opts & OPT_a) { smtp_check("AUTH LOGIN", 334); // we must read credentials unless they are given via -a[up] options if (!G.user || !G.pass) get_cred_or_die(4); encode_base64(NULL, G.user, NULL); smtp_check("", 334); encode_base64(NULL, G.pass, NULL); smtp_check("", 235); } // set sender // N.B. we have here a very loosely defined algorythm // since sendmail historically offers no means to specify secrets on cmdline. // 1) server can require no authentication -> // we must just provide a (possibly fake) reply address. // 2) server can require AUTH -> // we must provide valid username and password along with a (possibly fake) reply address. // For the sake of security username and password are to be read either from console or from a secured file. // Since reading from console may defeat usability, the solution is either to read from a predefined // file descriptor (e.g. 4), or again from a secured file. // got no sender address? use auth name, then UID username as a last resort if (!opt_from) { opt_from = xasprintf("%s@%s", G.user ? G.user : xuid2uname(getuid()), xgethostbyname(host)->h_name); } free(host); smtp_checkp("MAIL FROM:<%s>", opt_from, 250); // process message // read recipients from message and add them to those given on cmdline. // this means we scan stdin for To:, Cc:, Bcc: lines until an empty line // and then use the rest of stdin as message body code = 0; // set "analyze headers" mode while ((s = xmalloc_fgetline(G.fp0)) != NULL) { dump: // put message lines doubling leading dots if (code) { // escape leading dots // N.B. this feature is implied even if no -i (-oi) switch given // N.B. we need to escape the leading dot regardless of // whether it is single or not character on the line if ('.' == s[0] /*&& '\0' == s[1] */) bb_putchar('.'); // dump read line send_r_n(s); free(s); continue; } // analyze headers // To: or Cc: headers add recipients check_hdr = (0 == strncasecmp("To:", s, 3)); has_to |= check_hdr; if (opts & OPT_t) { if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { rcptto_list(s+3); last_hdr = HDR_TOCC; goto addheader; } // Bcc: header adds blind copy (hidden) recipient if (0 == strncasecmp("Bcc:", s, 4)) { rcptto_list(s+4); free(s); last_hdr = HDR_BCC; continue; // N.B. Bcc: vanishes from headers! } } check_hdr = (list && isspace(s[0])); if (strchr(s, ':') || check_hdr) { // other headers go verbatim // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. // Continuation is denoted by prefixing additional lines with whitespace(s). // Thanks (stefan.seyfried at googlemail.com) for pointing this out. if (check_hdr && last_hdr != HDR_OTHER) { rcptto_list(s+1); if (last_hdr == HDR_BCC) continue; // N.B. Bcc: vanishes from headers! } else { last_hdr = HDR_OTHER; } addheader: // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) goto bail; llist_add_to_end(&list, s); } else { // a line without ":" (an empty line too, by definition) doesn't look like a valid header // so stop "analyze headers" mode reenter: // put recipients specified on cmdline check_hdr = 1; while (*argv) { char *t = sane_address(*argv); rcptto(t); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) // goto bail; if (!has_to) { const char *hdr; if (check_hdr && argv[1]) hdr = "To: %s,"; else if (check_hdr) hdr = "To: %s"; else if (argv[1]) hdr = "To: %s," + 3; else hdr = "To: %s" + 3; llist_add_to_end(&list, xasprintf(hdr, t)); check_hdr = 0; } argv++; } // enter "put message" mode // N.B. DATA fails iff no recipients were accepted (or even provided) // in this case just bail out gracefully if (354 != smtp_check("DATA", -1)) goto bail; // dump the headers while (list) { send_r_n((char *) llist_pop(&list)); } // stop analyzing headers code++; // N.B. !s means: we read nothing, and nothing to be read in the future. // just dump empty line and break the loop if (!s) { send_r_n(""); break; } // go dump message body // N.B. "s" already contains the first non-header line, so pretend we read it from input goto dump; } } // odd case: we didn't stop "analyze headers" mode -> message body is empty. Reenter the loop // N.B. after reenter code will be > 0 if (!code) goto reenter; // finalize the message smtp_check(".", 250); bail: // ... and say goodbye smtp_check("QUIT", 221); // cleanup if (ENABLE_FEATURE_CLEAN_UP) fclose(G.fp0); return EXIT_SUCCESS; }
int uniq_main(int argc UNUSED_PARAM, char **argv) { FILE *in, *out; const char *s0, *e0, *s1, *e1, *input_filename; unsigned long dups; unsigned skip_fields, skip_chars, max_chars; unsigned opt; unsigned i; enum { OPT_c = 0x1, OPT_d = 0x2, OPT_u = 0x4, OPT_f = 0x8, OPT_s = 0x10, OPT_w = 0x20, }; skip_fields = skip_chars = 0; max_chars = INT_MAX; opt_complementary = "f+:s+:w+"; opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars); argv += optind; input_filename = *argv; in = xgetoptfile_uniq_s(argv, 0); if (*argv) { ++argv; } out = xgetoptfile_uniq_s(argv, 2); if (*argv && argv[1]) { bb_show_usage(); } s1 = e1 = NULL; /* prime the pump */ do { s0 = s1; e0 = e1; dups = 0; /* gnu uniq ignores newlines */ while ((s1 = xmalloc_fgetline(in)) != NULL) { e1 = s1; for (i = skip_fields; i; i--) { e1 = skip_whitespace(e1); e1 = skip_non_whitespace(e1); } for (i = skip_chars; *e1 && i; i--) { ++e1; } if (!s0 || strncmp(e0, e1, max_chars)) { break; } ++dups; /* note: testing for overflow seems excessive. */ } if (s0) { if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */ fprintf(out, "\0%ld " + (opt & 1), dups + 1); /* 1 == OPT_c */ fprintf(out, "%s\n", s0); } free((void *)s0); } } while (s1); die_if_ferror(in, input_filename); fflush_stdout_and_exit(EXIT_SUCCESS); }
int cryptpw_main(int argc UNUSED_PARAM, char **argv) { /* $N$ + sha_salt_16_bytes + NUL */ char salt[3 + 16 + 1]; char *salt_ptr; const char *opt_m, *opt_S; int len; int fd; #if ENABLE_LONG_OPTS static const char mkpasswd_longopts[] ALIGN1 = "stdin\0" No_argument "s" "password-fd\0" Required_argument "P" "salt\0" Required_argument "S" "method\0" Required_argument "m" ; applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; opt_m = "d"; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2:P+"; getopt32(argv, "sP:S:m:a:", &fd, &opt_S, &opt_m, &opt_m); argv += optind; /* have no idea how to handle -s... */ if (argv[0] && !opt_S) opt_S = argv[1]; len = 2/2; salt_ptr = salt; if (opt_m[0] != 'd') { /* not des */ len = 8/2; /* so far assuming md5 */ *salt_ptr++ = '$'; *salt_ptr++ = '1'; *salt_ptr++ = '$'; #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA if (opt_m[0] == 's') { /* sha */ salt[1] = '5' + (strcmp(opt_m, "sha512") == 0); len = 16/2; } #endif } if (opt_S) safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3); else crypt_make_salt(salt_ptr, len, 0); xmove_fd(fd, STDIN_FILENO); puts(pw_encrypt( argv[0] ? argv[0] : ( /* Only mkpasswd, and only from tty, prompts. * Otherwise it is a plain read. */ (isatty(STDIN_FILENO) && applet_name[0] == 'm') ? bb_ask_stdin("Password: ") : xmalloc_fgetline(stdin) ), salt, 1)); return EXIT_SUCCESS; }
int chpasswd_main(int argc UNUSED_PARAM, char **argv) { char *name; const char *algo = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; int opt; if (getuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); opt = getopt32long(argv, "^" "emc:" "\0" "m--ec:e--mc:c--em", chpasswd_longopts, &algo ); while ((name = xmalloc_fgetline(stdin)) != NULL) { char *free_me; char *pass; int rc; pass = strchr(name, ':'); if (!pass) bb_error_msg_and_die("missing new password"); *pass++ = '\0'; xuname2uid(name); /* dies if there is no such user */ free_me = NULL; if (!(opt & OPT_ENC)) { char salt[MAX_PW_SALT_LEN]; if (opt & OPT_MD5) { /* Force MD5 if the -m flag is set */ algo = "md5"; } crypt_make_pw_salt(salt, algo); free_me = pass = pw_encrypt(pass, salt, 0); } /* This is rather complex: if user is not found in /etc/shadow, * we try to find & change his passwd in /etc/passwd */ #if ENABLE_FEATURE_SHADOWPASSWDS rc = update_passwd(bb_path_shadow_file, name, pass, NULL); if (rc > 0) /* password in /etc/shadow was updated */ pass = (char*)"x"; if (rc >= 0) /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ #endif rc = update_passwd(bb_path_passwd_file, name, pass, NULL); /* LOGMODE_BOTH logs to syslog also */ logmode = LOGMODE_BOTH; if (rc < 0) bb_error_msg_and_die("an error occurred updating password for %s", name); if (rc) bb_error_msg("password for '%s' changed", name); logmode = LOGMODE_STDIO; free(name); free(free_me); } return EXIT_SUCCESS; }
int sed_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; llist_t *opt_e, *opt_f; char *opt_i; #if ENABLE_LONG_OPTS static const char sed_longopts[] ALIGN1 = /* name has_arg short */ "in-place\0" Optional_argument "i" "regexp-extended\0" No_argument "r" "quiet\0" No_argument "n" "silent\0" No_argument "n" "expression\0" Required_argument "e" "file\0" Required_argument "f"; #endif INIT_G(); /* destroy command strings on exit */ if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); /* Lie to autoconf when it starts asking stupid questions. */ if (argv[1] && strcmp(argv[1], "--version") == 0) { puts("This is not GNU sed version 4.0"); return 0; } /* do normal option parsing */ opt_e = opt_f = NULL; opt_i = NULL; /* -i must be first, to match OPT_in_place definition */ /* -E is a synonym of -r: * GNU sed 4.2.1 mentions it in neither --help * nor manpage, but does recognize it. */ opt = getopt32long(argv, "^" "i::rEne:*f:*" "\0" "nn"/*count -n*/, sed_longopts, &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ //argc -= optind; argv += optind; if (opt & OPT_in_place) { // -i die_func = cleanup_outname; } if (opt & (2|4)) G.regex_type |= REG_EXTENDED; // -r or -E //if (opt & 8) // G.be_quiet++; // -n (implemented with a counter instead) while (opt_e) { // -e add_cmd_block(llist_pop(&opt_e)); } while (opt_f) { // -f char *line; FILE *cmdfile; cmdfile = xfopen_stdin(llist_pop(&opt_f)); while ((line = xmalloc_fgetline(cmdfile)) != NULL) { add_cmd(line); free(line); } fclose_if_not_stdin(cmdfile); } /* if we didn't get a pattern from -e or -f, use argv[0] */ if (!(opt & 0x30)) { if (!*argv) bb_show_usage(); add_cmd_block(*argv++); } /* Flush any unfinished commands. */ add_cmd(""); /* By default, we write to stdout */ G.nonstdout = stdout; /* argv[0..(argc-1)] should be names of file to process. If no * files were specified or '-' was specified, take input from stdin. * Otherwise, we process all the files specified. */ G.input_file_list = argv; if (!argv[0]) { if (opt & OPT_in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i"); argv[0] = (char*)bb_msg_standard_input; /* G.last_input_file = 0; - already is */ } else { goto start; for (; *argv; argv++) { struct stat statbuf; int nonstdoutfd; sed_cmd_t *sed_cmd; G.last_input_file++; start: if (!(opt & OPT_in_place)) { if (LONE_DASH(*argv)) { *argv = (char*)bb_msg_standard_input; process_files(); } continue; } /* -i: process each FILE separately: */ if (stat(*argv, &statbuf) != 0) { bb_simple_perror_msg(*argv); G.exitcode = EXIT_FAILURE; G.current_input_file++; continue; } G.outname = xasprintf("%sXXXXXX", *argv); nonstdoutfd = xmkstemp(G.outname); G.nonstdout = xfdopen_for_write(nonstdoutfd); /* Set permissions/owner of output file */ /* chmod'ing AFTER chown would preserve suid/sgid bits, * but GNU sed 4.2.1 does not preserve them either */ fchmod(nonstdoutfd, statbuf.st_mode); fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); process_files(); fclose(G.nonstdout); G.nonstdout = stdout; if (opt_i) { char *backupname = xasprintf("%s%s", *argv, opt_i); xrename(*argv, backupname); free(backupname); } /* else unlink(*argv); - rename below does this */ xrename(G.outname, *argv); //TODO: rollback backup on error? free(G.outname); G.outname = NULL; /* Fix disabled range matches and mangled ",+N" ranges */ for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { sed_cmd->beg_line = sed_cmd->beg_line_orig; sed_cmd->end_line = sed_cmd->end_line_orig; } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: * if (G.current_input_file[G.current_input_file] == NULL) * return G.exitcode; * but it's not needed since process_files() works correctly * in this case too. */ } process_files(); return G.exitcode; }
int hexdump_main(int argc, char **argv) { dumper_t *dumper = alloc_dumper(); const char *p; int ch; #if ENABLE_FEATURE_HEXDUMP_REVERSE FILE *fp; smallint rdump = 0; #endif if (ENABLE_HD && !applet_name[2]) { /* we are "hd" */ ch = 'C'; goto hd_applet; } /* We cannot use getopt32: in hexdump options are cumulative. * E.g. "hexdump -C -C file" should dump each line twice */ while ((ch = getopt(argc, argv, hexdump_opts)) > 0) { p = strchr(hexdump_opts, ch); if (!p) bb_show_usage(); if ((p - hexdump_opts) < 5) { bb_dump_add(dumper, add_first); bb_dump_add(dumper, add_strings[(int)(p - hexdump_opts)]); } /* Save a little bit of space below by omitting the 'else's. */ if (ch == 'C') { hd_applet: bb_dump_add(dumper, "\"%08.8_Ax\n\""); bb_dump_add(dumper, "\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); bb_dump_add(dumper, "\" |\" 16/1 \"%_p\" \"|\\n\""); } if (ch == 'e') { bb_dump_add(dumper, optarg); } /* else */ if (ch == 'f') { bb_dump_addfile(dumper, optarg); } /* else */ if (ch == 'n') { dumper->dump_length = xatoi_positive(optarg); } /* else */ if (ch == 's') { /* compat: -s accepts hex numbers too */ dumper->dump_skip = xstrtoull_range_sfx( optarg, /*base:*/ 0, /*lo:*/ 0, /*hi:*/ OFF_T_MAX, bkm_suffixes ); } /* else */ if (ch == 'v') { dumper->dump_vflag = ALL; } #if ENABLE_FEATURE_HEXDUMP_REVERSE if (ch == 'R') { rdump = 1; } #endif } if (!dumper->fshead) { bb_dump_add(dumper, add_first); bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); } argv += optind; #if !ENABLE_FEATURE_HEXDUMP_REVERSE return bb_dump_dump(dumper, argv); #else if (!rdump) { return bb_dump_dump(dumper, argv); } /* -R: reverse of 'hexdump -Cv' */ fp = stdin; if (!*argv) { argv--; goto jump_in; } do { char *buf; fp = xfopen_for_read(*argv); jump_in: while ((buf = xmalloc_fgetline(fp)) != NULL) { p = buf; while (1) { /* skip address or previous byte */ while (isxdigit(*p)) p++; while (*p == ' ') p++; /* '|' char will break the line */ if (!isxdigit(*p) || sscanf(p, "%x ", &ch) != 1) break; putchar(ch); } free(buf); } fclose(fp); } while (*++argv); fflush_stdout_and_exit(EXIT_SUCCESS); #endif }
int patch_main(int argc UNUSED_PARAM, char **argv) { struct stat saved_stat; char *patch_line; FILE *patch_file; int patch_level; int ret = 0; char plus = '+'; unsigned opt; enum { OPT_R = (1 << 2), OPT_N = (1 << 3), /*OPT_f = (1 << 4), ignored */ /*OPT_E = (1 << 5), ignored, this is the default */ /*OPT_g = (1 << 6), ignored */ OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS, }; xfunc_error_retval = 2; { const char *p = "-1"; const char *i = "-"; /* compat */ #if ENABLE_LONG_OPTS static const char patch_longopts[] ALIGN1 = "strip\0" Required_argument "p" "input\0" Required_argument "i" "reverse\0" No_argument "R" "forward\0" No_argument "N" /* "Assume user knows what [s]he is doing, do not ask any questions": */ "force\0" No_argument "f" /*ignored*/ # if ENABLE_DESKTOP "remove-empty-files\0" No_argument "E" /*ignored*/ /* "Controls actions when a file is under RCS or SCCS control, * and does not exist or is read-only and matches the default version, * or when a file is under ClearCase control and does not exist..." * IOW: rather obscure option. * But Gentoo's portage does use -g0 */ "get\0" Required_argument "g" /*ignored*/ # endif "dry-run\0" No_argument "\xfd" # if ENABLE_DESKTOP "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ # endif ; applet_long_options = patch_longopts; #endif /* -f,-E,-g are ignored */ opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); if (opt & OPT_R) plus = '-'; patch_level = xatoi(p); /* can be negative! */ patch_file = xfopen_stdin(i); } patch_line = xmalloc_fgetline(patch_file); while (patch_line) { FILE *src_stream; FILE *dst_stream; //char *old_filename; char *new_filename; char *backup_filename = NULL; unsigned src_cur_line = 1; unsigned dst_cur_line = 0; unsigned dst_beg_line; unsigned bad_hunk_count = 0; unsigned hunk_count = 0; smallint copy_trailing_lines_flag = 0; /* Skip everything upto the "---" marker * No need to parse the lines "Only in <dir>", and "diff <args>" */ do { /* Extract the filename ugsed before the patch was generated */ new_filename = extract_filename(patch_line, patch_level, "--- "); // was old_filename above patch_line = xmalloc_fgetline(patch_file); if (!patch_line) goto quit; } while (!new_filename); free(new_filename); // "source" filename is irrelevant new_filename = extract_filename(patch_line, patch_level, "+++ "); if (!new_filename) { bb_error_msg_and_die("invalid patch"); } /* Get access rights from the file to be patched */ if (stat(new_filename, &saved_stat) != 0) { char *slash = strrchr(new_filename, '/'); if (slash) { /* Create leading directories */ *slash = '\0'; bb_make_directory(new_filename, -1, FILEUTILS_RECUR); *slash = '/'; } src_stream = NULL; saved_stat.st_mode = 0644; } else if (!(opt & OPT_dry_run)) { backup_filename = xasprintf("%s.orig", new_filename); xrename(new_filename, backup_filename); src_stream = xfopen_for_read(backup_filename); } else src_stream = xfopen_for_read(new_filename); if (opt & OPT_dry_run) { dst_stream = xfopen_for_write("/dev/null"); } else { dst_stream = xfopen_for_write(new_filename); fchmod(fileno(dst_stream), saved_stat.st_mode); } printf("patching file %s\n", new_filename); /* Handle all hunks for this file */ patch_line = xmalloc_fgets(patch_file); while (patch_line) { unsigned count; unsigned src_beg_line; unsigned hunk_offset_start; unsigned src_last_line = 1; unsigned dst_last_line = 1; if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) ) { /* No more hunks for this file */ break; } if (plus != '+') { /* reverse patch */ unsigned tmp = src_last_line; src_last_line = dst_last_line; dst_last_line = tmp; tmp = src_beg_line; src_beg_line = dst_beg_line; dst_beg_line = tmp; } hunk_count++; if (src_beg_line && dst_beg_line) { /* Copy unmodified lines upto start of hunk */ /* src_beg_line will be 0 if it's a new file */ count = src_beg_line - src_cur_line; if (copy_lines(src_stream, dst_stream, count)) { bb_error_msg_and_die("bad src file"); } src_cur_line += count; dst_cur_line += count; copy_trailing_lines_flag = 1; } src_last_line += hunk_offset_start = src_cur_line; dst_last_line += dst_cur_line; while (1) { free(patch_line); patch_line = xmalloc_fgets(patch_file); if (patch_line == NULL) break; /* EOF */ if (!*patch_line) { /* whitespace-damaged patch with "" lines */ free(patch_line); patch_line = xstrdup(" "); } if ((*patch_line != '-') && (*patch_line != '+') && (*patch_line != ' ') ) { break; /* End of hunk */ } if (*patch_line != plus) { /* '-' or ' ' */ char *src_line = NULL; if (src_cur_line == src_last_line) break; if (src_stream) { src_line = xmalloc_fgets(src_stream); if (src_line) { int diff = strcmp(src_line, patch_line + 1); src_cur_line++; free(src_line); if (diff) src_line = NULL; } } /* Do not patch an already patched hunk with -N */ if (src_line == 0 && (opt & OPT_N)) { continue; } if (!src_line) { bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); bad_hunk_count++; break; } if (*patch_line != ' ') { /* '-' */ continue; } } if (dst_cur_line == dst_last_line) break; fputs(patch_line + 1, dst_stream); dst_cur_line++; } /* end of while loop handling one hunk */ } /* end of while loop handling one file */ /* Cleanup last patched file */ if (copy_trailing_lines_flag) { copy_lines(src_stream, dst_stream, (unsigned)(-1)); } if (src_stream) { fclose(src_stream); } fclose(dst_stream); if (bad_hunk_count) { ret = 1; bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); } else { /* It worked, we can remove the backup */ if (backup_filename) { unlink(backup_filename); } if (!(opt & OPT_dry_run) && ((dst_cur_line == 0) || (dst_beg_line == 0)) ) { /* The new patched file is empty, remove it */ xunlink(new_filename); // /* old_filename and new_filename may be the same file */ // unlink(old_filename); } } free(backup_filename); //free(old_filename); free(new_filename); } /* end of "while there are patch lines" */ quit: /* 0 = SUCCESS * 1 = Some hunks failed * 2 = More serious problems (exited earlier) */ return ret; }
int main(int argc,char **argv) { FILE *fp_macro = 0; FILE *fp_config = 0; FILE *fp_source = 0; FILE *fp_table = 0; char *line; char *line1; char *cp ; char *url = (char*)malloc(256*sizeof(char)); //char macros[4000][256]; char **macros = (char **)malloc(4000*256*sizeof(char)); //char sameoption = 0; macros[0] = xasprintf("null"); int i = 0; fp_source = fopen(UCI_SOURCE,"r"); if(!fp_source) { printf("file %s open failed!\n",UCI_SOURCE); return (-1); } fp_macro = fopen(UCI_MACRO,"w"); if(!fp_macro) { printf("file %s open failed\n",UCI_MACRO); return (-1); } fp_config = fopen(UCI_CONFIG,"w"); if(!fp_config) { printf("file %s open failed\n",UCI_CONFIG); return (-1); } fp_table = fopen(FUNC_TABLE,"r"); if(!fp_table) { printf("file %s open failed\n",FUNC_TABLE); return (-1); } fprintf(fp_macro,"#ifndef __TR_UCICONFIG_H__\n"); fprintf(fp_macro,"#define __TR_UCICONFIG_H__\n"); fprintf(fp_macro,"\n"); fprintf(fp_macro,"#define MS \"trconf\"\n"); fprintf(fp_macro,"#define TRCONF MS\".\"\n"); fprintf(fp_macro,"\n"); while(1) { line = xmalloc_fgetline(fp_source);//get a line content of the tr_uciconfig file if(line) { char *option = (char *)malloc(256*sizeof(char)); char *section = (char *)malloc(256*sizeof(char)); char *tmp = (char *)malloc(256*sizeof(char)); //char *tmp1 = (char *)malloc(256*sizeof(char)); i++; /*get the section and the option*/ strcpy(tmp,line); /* cp = strchr(tmp,''); *cp = '\0'; cp = strchr(tmp,' '); tmp = ++cp; */ cp = strchr(tmp,' '); cp = ++cp; section = xasprintf("%s",cp); //section = xasprintf("%s",tmp); cp = strchr(line,'_'); cp = ++cp; option = xasprintf("%s",cp);//we can refer to the option get the url of this option in the tr69_handler_table.h //option_argv[i] = option; printf("the content of the section is [%s]\n",section); printf("content of the option [%d]:[%s]\n",i,option); strcpy(option_argv[i],option); /*get the url of this option */ while(1) { line1 = xmalloc_fgetline(fp_table); if(line1) { if(strstr(line1,section)) { printf("get the dest section %s and the line content is %s\n",section,line1); cp = strchr(line1,'{'); cp = cp + 2; tmp = cp; cp = strchr(tmp,'"'); *cp ='\0'; url = xasprintf("%s",tmp); cp = strrchr(url,'.'); *cp = '\0'; tmp = xasprintf("%s",url); while(cp=strchr(tmp,'.'))/*xxx.xx.xxxx*/ { *cp = '_'; } url = xasprintf("%s",tmp); /* sameoption = option_check(option); if((!strcmp(url,macros[i-1])) && (sameoption)) { printf("the url and the option are same!\n"); continue; } else */ //macros[i] = xasprintf("%s",url);/*xxx_xx_xxxx*/ break;//every time there is only one option can be deal with. } } else break; } /*write the tr_uciconfig.h*/ //fprintf(fp_macro,"%s\tTRCONF \"%s.%s\"\n",line,section,option); fprintf(fp_macro,"%s\t\t\tTRCONF \"%s.%s\"\n",line,url,option); /*write the trconf*/ //if(strcmp(section,macros[i-1]))//if the current section is not same as the macros[i-1],then create the section name if(strcmp(url,macros[i-1])) { fprintf(fp_config,"config tr181 \'%s\'\n",url); fprintf(fp_config,"\toption %s \'\'\n",option); } else { fprintf(fp_config,"\toption %s \'\'\n",option); } //strcpy(macros[i],section); //macros[i] = xasprintf("%s",section); macros[i] = xasprintf("%s",url);/*xxx_xx_xxxx*/ } else { break; } } fprintf(fp_macro,"#endif"); //exit: fclose(fp_source); fclose(fp_macro); fclose(fp_config); fclose(fp_table); return (0); }
int sed_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; llist_t *opt_e, *opt_f; char *opt_i; #if ENABLE_LONG_OPTS static const char sed_longopts[] ALIGN1 = /* name has_arg short */ "in-place\0" Optional_argument "i" "regexp-extended\0" No_argument "r" "quiet\0" No_argument "n" "silent\0" No_argument "n" "expression\0" Required_argument "e" "file\0" Required_argument "f"; #endif int status = EXIT_SUCCESS; INIT_G(); /* destroy command strings on exit */ if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); /* Lie to autoconf when it starts asking stupid questions. */ if (argv[1] && strcmp(argv[1], "--version") == 0) { puts("This is not GNU sed version 4.0"); return 0; } /* do normal option parsing */ opt_e = opt_f = NULL; opt_i = NULL; opt_complementary = "e::f::" /* can occur multiple times */ "nn"; /* count -n */ IF_LONG_OPTS(applet_long_options = sed_longopts); /* -i must be first, to match OPT_in_place definition */ opt = getopt32(argv, "i::rne:f:", &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ //argc -= optind; argv += optind; if (opt & OPT_in_place) { // -i atexit(cleanup_outname); } if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r //if (opt & 0x4) G.be_quiet++; // -n while (opt_e) { // -e add_cmd_block(llist_pop(&opt_e)); } while (opt_f) { // -f char *line; FILE *cmdfile; cmdfile = xfopen_for_read(llist_pop(&opt_f)); while ((line = xmalloc_fgetline(cmdfile)) != NULL) { add_cmd(line); free(line); } fclose(cmdfile); } /* if we didn't get a pattern from -e or -f, use argv[0] */ if (!(opt & 0x18)) { if (!*argv) bb_show_usage(); add_cmd_block(*argv++); } /* Flush any unfinished commands. */ add_cmd(""); /* By default, we write to stdout */ G.nonstdout = stdout; /* argv[0..(argc-1)] should be names of file to process. If no * files were specified or '-' was specified, take input from stdin. * Otherwise, we process all the files specified. */ if (argv[0] == NULL) { if (opt & OPT_in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i"); add_input_file(stdin); } else { int i; for (i = 0; argv[i]; i++) { struct stat statbuf; int nonstdoutfd; FILE *file; sed_cmd_t *sed_cmd; if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { add_input_file(stdin); process_files(); continue; } file = fopen_or_warn(argv[i], "r"); if (!file) { status = EXIT_FAILURE; continue; } add_input_file(file); if (!(opt & OPT_in_place)) { continue; } /* -i: process each FILE separately: */ G.outname = xasprintf("%sXXXXXX", argv[i]); nonstdoutfd = xmkstemp(G.outname); G.nonstdout = xfdopen_for_write(nonstdoutfd); /* Set permissions/owner of output file */ fstat(fileno(file), &statbuf); /* chmod'ing AFTER chown would preserve suid/sgid bits, * but GNU sed 4.2.1 does not preserve them either */ fchmod(nonstdoutfd, statbuf.st_mode); fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); process_files(); fclose(G.nonstdout); G.nonstdout = stdout; if (opt_i) { char *backupname = xasprintf("%s%s", argv[i], opt_i); xrename(argv[i], backupname); free(backupname); } /* else unlink(argv[i]); - rename below does this */ xrename(G.outname, argv[i]); //TODO: rollback backup on error? free(G.outname); G.outname = NULL; /* Re-enable disabled range matches */ for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { sed_cmd->beg_line = sed_cmd->beg_line_orig; } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: * if (G.current_input_file >= G.input_file_count) * return status; * but it's not needed since process_files() works correctly * in this case too. */ } process_files(); return status; }
static GList* load_bzrep_conf_file(const char *path) { FILE *fp = stdin; if (strcmp(path, "-") != 0) { fp = fopen(path, "r"); if (!fp) return NULL; } GList *sections = NULL; char *line; while ((line = xmalloc_fgetline(fp)) != NULL) { /* Skip comments */ char first = *skip_whitespace(line); if (first == '#') goto free_line; /* Handle trailing backslash continuation */ check_continuation: ; unsigned len = strlen(line); if (len && line[len-1] == '\\') { line[len-1] = '\0'; char *next_line = xmalloc_fgetline(fp); if (next_line) { line = append_to_malloced_string(line, next_line); free(next_line); goto check_continuation; } } /* We are reusing line buffer to form temporary * "key\0values\0..." in its beginning */ bool summary_line = false; char *value = NULL; char *src; char *dst; for (src = dst = line; *src; src++) { char c = *src; /* did we reach the value list? */ if (!value && c == ':' && src[1] == ':') { *dst++ = '\0'; /* terminate key */ src += 2; value = dst; /* remember where value starts */ summary_line = (strcmp(line, "%summary") == 0); if (summary_line) { value = src; break; } continue; } /* skip whitespace in value list */ if (value && isspace(c)) continue; *dst++ = c; /* store next key or value char */ } GList *item_list = NULL; if (summary_line) { /* %summary is special */ item_list = g_list_append(NULL, xstrdup(skip_whitespace(value))); } else { *dst = '\0'; /* terminate value (or key) */ if (value) item_list = split_string_on_char(value, ','); } section_t *sec = xzalloc(sizeof(*sec)); sec->name = xstrdup(line); sec->items = item_list; sections = g_list_prepend(sections, sec); free_line: free(line); } if (fp != stdin) fclose(fp); return g_list_reverse(sections); }
void ignored_problems_remove_row(ignored_problems_t *set, const char *problem_id, const char *uuid, const char *duphash) { VERB1 log("Going to remove problem '%s' from ignored problems", problem_id); FILE *orig_fp; if (!ignored_problems_file_contains(set, problem_id, uuid, duphash, &orig_fp, "r")) { if (orig_fp) { log_notice("Won't remove problem '%s' from ignored problems:" " it is already removed", problem_id); /* Close orig_fp here becuase it looks like much simpler than * exetendig the set of goto labels at the end of this function */ fclose(orig_fp); } else { /* This is not a fatal problem. We are permissive because we don't want * to scare users by strange error messages. */ log_notice("Can't remove problem '%s' from ignored problems:" " can't open the list", problem_id); } return; } /* orig_fp must be valid here because if ignored_problems_file_contains() * returned TRUE the function ensures that orig_fp is set to a valid FILE*. * * But the function moved the file position indicator. */ rewind(orig_fp); char *new_tempfile_name = xasprintf("%s.XXXXXX", set->ign_set_file_path); int new_tempfile_fd = mkstemp(new_tempfile_name); if (new_tempfile_fd < 0) { perror_msg(_("Can't create temporary file '%s'"), set->ign_set_file_path); goto ret_close_files; } unsigned line_num = 0; char *line; while ((line = xmalloc_fgetline(orig_fp)) != NULL) { ++line_num; if (!ignored_problems_eq(set, problem_id, uuid, duphash, line, line_num)) { ssize_t len = strlen(line); line[len] = '\n'; if (full_write(new_tempfile_fd, line, len + 1) < 0) { /* Probably out of space */ line[len] = '\0'; perror_msg(_("Can't write to '%s'." " Problem '%s' will not be removed from the ignored" " problems '%s'"), new_tempfile_name, problem_id, set->ign_set_file_path); free(line); goto ret_unlink_new; } } free(line); } if (rename(new_tempfile_name, set->ign_set_file_path) < 0) { /* Something nefarious happened */ perror_msg(_("Can't rename '%s' to '%s'. Failed to remove problem '%s'"), set->ign_set_file_path, new_tempfile_name, problem_id); ret_unlink_new: unlink(new_tempfile_name); } ret_close_files: fclose(orig_fp); if (new_tempfile_fd >= 0) close(new_tempfile_fd); free(new_tempfile_name); }
/* Called after "Backtrace:" line was read. * Example (yes, stray newline before 'B' is real): [ 86985.879]<space> Backtrace: [ 86985.880] 0: /usr/bin/Xorg (xorg_backtrace+0x2f) [0x462d8f] [ 86985.880] 1: /usr/bin/Xorg (0x400000+0x67b56) [0x467b56] [ 86985.880] 2: /lib64/libpthread.so.0 (0x30a5800000+0xf4f0) [0x30a580f4f0] [ 86985.880] 3: /usr/lib64/xorg/modules/extensions/librecord.so (0x7ff6c225e000+0x26c3) [0x7ff6c22606c3] [ 86985.880] 4: /usr/bin/Xorg (_CallCallbacks+0x3c) [0x43820c] [ 86985.880] 5: /usr/bin/Xorg (WriteToClient+0x1f5) [0x466315] [ 86985.880] 6: /usr/lib64/xorg/modules/extensions/libdri2.so (ProcDRI2WaitMSCReply+0x4f) [0x7ff6c1e4feef] [ 86985.880] 7: /usr/lib64/xorg/modules/extensions/libdri2.so (DRI2WaitMSCComplete+0x52) [0x7ff6c1e4e6d2] [ 86985.880] 8: /usr/lib64/xorg/modules/drivers/intel_drv.so (0x7ff6c1bfb000+0x25ae4) [0x7ff6c1c20ae4] [ 86985.880] 9: /usr/lib64/libdrm.so.2 (drmHandleEvent+0xa3) [0x376b407513] [ 86985.880] 10: /usr/bin/Xorg (WakeupHandler+0x6b) [0x4379db] [ 86985.880] 11: /usr/bin/Xorg (WaitForSomething+0x1a9) [0x460289] [ 86985.880] 12: /usr/bin/Xorg (0x400000+0x3379a) [0x43379a] [ 86985.880] 13: /usr/bin/Xorg (0x400000+0x22dc5) [0x422dc5] [ 86985.880] 14: /lib64/libc.so.6 (__libc_start_main+0xed) [0x30a542169d] [ 86985.880] 15: /usr/bin/Xorg (0x400000+0x230b1) [0x4230b1] [ 86985.880] Segmentation fault at address 0x7ff6bf09e010 */ static void process_xorg_bt(void) { char *reason = NULL; char *exe = NULL; GList *list = NULL; unsigned cnt = 0; char *line; while ((line = xmalloc_fgetline(stdin)) != NULL) { char *p = skip_pfx(line); /* xorg-server-1.12.0/os/osinit.c: * if (sip->si_code == SI_USER) { * ErrorF("Recieved signal %d sent by process %ld, uid %ld\n", * ^^^^^^^^ yes, typo here! Can't grep for this word! :( * signo, (long) sip->si_pid, (long) sip->si_uid); * } else { * switch (signo) { * case SIGSEGV: * case SIGBUS: * case SIGILL: * case SIGFPE: * ErrorF("%s at address %p\n", strsignal(signo), sip->si_addr); */ if (*p < '0' || *p > '9') { if (strstr(p, " at address ") || strstr(p, " sent by process ")) { overlapping_strcpy(line, p); reason = line; line = NULL; } /* TODO: Other cases when we have useful reason string? */ break; } errno = 0; char *end; IGNORE_RESULT(strtoul(p, &end, 10)); if (errno || end == p || *end != ':') break; /* This looks like bt line */ /* Guess Xorg server's executable name from it */ if (!exe) { char *filename = skip_whitespace(end + 1); char *filename_end = skip_non_whitespace(filename); char sv = *filename_end; *filename_end = '\0'; /* Does it look like "[/usr]/[s]bin/Xfoo"? */ if (strstr(filename, "bin/X")) exe = xstrdup(filename); *filename_end = sv; } /* Save it to list */ overlapping_strcpy(line, p); list = g_list_prepend(list, line); line = NULL; if (++cnt > 255) /* prevent ridiculously large bts */ break; } free(line); if (list) { list = g_list_reverse(list); char *bt = list2lines(list); /* frees list */ if (g_opts & OPT_o) printf("%s%s%s\n", bt, reason ? reason : "", reason ? "\n" : ""); if (g_opts & (OPT_d|OPT_D)) if (g_bt_count <= MAX_DUMPED_DD_COUNT) save_bt_to_dump_dir(bt, exe, reason ? reason : "Xorg server crashed"); free(bt); } free(reason); free(exe); }
int uniq_main(int argc UNUSED_PARAM, char **argv) { const char *input_filename; unsigned skip_fields, skip_chars, max_chars; unsigned opt; char *cur_line; const char *cur_compare; enum { OPT_c = 0x1, OPT_d = 0x2, /* print only dups */ OPT_u = 0x4, /* print only uniq */ OPT_f = 0x8, OPT_s = 0x10, OPT_w = 0x20, OPT_i = 0x40, }; skip_fields = skip_chars = 0; max_chars = INT_MAX; opt = getopt32(argv, "cduf:+s:+w:+i", &skip_fields, &skip_chars, &max_chars); argv += optind; input_filename = argv[0]; if (input_filename) { const char *output; if (input_filename[0] != '-' || input_filename[1]) { close(STDIN_FILENO); /* == 0 */ xopen(input_filename, O_RDONLY); /* fd will be 0 */ } output = argv[1]; if (output) { if (argv[2]) bb_show_usage(); if (output[0] != '-' || output[1]) { // Won't work with "uniq - FILE" and closed stdin: //close(STDOUT_FILENO); //xopen(output, O_WRONLY | O_CREAT | O_TRUNC); xmove_fd(xopen(output, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } } } cur_compare = cur_line = NULL; /* prime the pump */ do { unsigned i; unsigned long dups; char *old_line; const char *old_compare; old_line = cur_line; old_compare = cur_compare; dups = 0; /* gnu uniq ignores newlines */ while ((cur_line = xmalloc_fgetline(stdin)) != NULL) { cur_compare = cur_line; for (i = skip_fields; i; i--) { cur_compare = skip_whitespace(cur_compare); cur_compare = skip_non_whitespace(cur_compare); } for (i = skip_chars; *cur_compare && i; i--) { ++cur_compare; } if (!old_line) break; if ((opt & OPT_i) ? strncasecmp(old_compare, cur_compare, max_chars) : strncmp(old_compare, cur_compare, max_chars) ) { break; } free(cur_line); ++dups; /* testing for overflow seems excessive */ } if (old_line) { if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_u) */ if (opt & OPT_c) { /* %7lu matches GNU coreutils 6.9 */ printf("%7lu ", dups + 1); } puts(old_line); } free(old_line); } } while (cur_line); die_if_ferror(stdin, input_filename); fflush_stdout_and_exit(EXIT_SUCCESS); }
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; }
int main(int argc, char **argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [-vsoxm] [-d DIR]/[-D] [FILE]\n" "\n" "Extract Xorg crash from FILE (or standard input)" ); /* Keep OPT_z enums and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL( 's', NULL, NULL, _("Log to syslog")), OPT_BOOL( 'o', NULL, NULL, _("Print found crash data on standard output")), OPT_STRING('d', NULL, &debug_dumps_dir, "DIR", _("Create problem directory in DIR for every crash found")), OPT_BOOL( 'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")), OPT_BOOL( 'x', NULL, NULL, _("Make the problem directory world readable")), OPT_BOOL( 'm', NULL, NULL, _("Print search string(s) to stdout and exit")), OPT_END() }; unsigned opts = g_opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); msg_prefix = g_progname; if ((opts & OPT_s) || getenv("ABRT_SYSLOG")) { logmode = LOGMODE_JOURNAL; } if (opts & OPT_m) { puts("Backtrace"); return 0; } if (opts & OPT_D) { if (opts & OPT_d) show_usage_and_die(program_usage_string, program_options); load_abrt_conf(); debug_dumps_dir = g_settings_dump_location; g_settings_dump_location = NULL; free_abrt_conf_data(); } argv += optind; if (argv[0]) xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO); char *line; while ((line = xmalloc_fgetline(stdin)) != NULL) { char *p = skip_pfx(line); if (strcmp(p, "Backtrace:") == 0) { free(line); g_bt_count++; process_xorg_bt(); continue; } free(line); } /* If we are run by a log watcher, this delays log rescan * (because log watcher waits to us to terminate) * and possibly prevents dreaded "abrt storm". */ if (opts & (OPT_d|OPT_D)) { if (g_bt_count > MAX_DUMPED_DD_COUNT) sleep(g_bt_count - MAX_DUMPED_DD_COUNT); } return 0; }
/* Returns false if open failed, else returns true. * TODO: better error detection? */ bool load_conf_file(const char *path, map_string_t *settings, bool skipKeysWithoutValue) { FILE *fp = stdin; if (strcmp(path, "-") != 0) { fp = fopen(path, "r"); if (!fp) return false; } char *line; while ((line = xmalloc_fgetline(fp)) != NULL) { bool in_quote = false; /* We are reusing line buffer to form temporary * "key\0value\0..." in its beginning */ char *value = NULL; char *src; char *dst; for (src = dst = line; *src; src++) { char c = *src; if (c == '"') { in_quote = !in_quote; /* skip the opening quote */ if (in_quote) continue; } if (!in_quote) { /* skip white-space unless it's inside value */ if (isspace(c) && !(value && dst != value)) { continue; } if (c == '#' && dst == line) { break; } if (c == '=') { *dst++ = '\0'; /* terminate key */ value = dst; /* remember where value starts */ continue; } } *dst++ = c; /* store next key or value char */ } /* Skip broken or empty lines. */ if (!value) goto free_line; /* Strip trailing spaces and closing quote from value */ while (dst > value && (isspace(dst[-1]) || dst[-1] == '"')) { dst--; if (*dst == '"') break; } *dst = '\0'; /* terminate value */ if (skipKeysWithoutValue && value[0] == '\0') goto free_line; /* Skip lines with unclosed quotes. */ if (in_quote) goto free_line; replace_map_string_item(settings, xstrdup(line), xstrdup(value)); free_line: free(line); } if (fp != stdin) fclose(fp); return true; }
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; }