static void cmdedit_init(void) { cmdedit_prmt_len = 0; if ((handlers_sets & SET_WCHG_HANDLERS) == 0) { /* emulate usage handler to set handler and call yours work */ win_changed(-SIGWINCH); handlers_sets |= SET_WCHG_HANDLERS; } if ((handlers_sets & SET_ATEXIT) == 0) { #ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR struct passwd *entry; my_euid = geteuid(); entry = getpwuid(my_euid); if (entry) { user_buf = bb_xstrdup(entry->pw_name); home_pwd_buf = bb_xstrdup(entry->pw_dir); } #endif #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION #ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR my_euid = geteuid(); #endif my_uid = getuid(); my_gid = getgid(); #endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */ handlers_sets |= SET_ATEXIT; atexit(cmdedit_reset_term); /* be sure to do this only once */ } }
static void buffer_line(int linenum) { int i; past_eof = 0; if (linenum < 0 || linenum > num_flines) { clear_line(); printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum + 1, NORMAL); } else if (linenum < (num_flines - height - 2)) { for (i = 0; i < (height - 1); i++) { free(buffer[i]); buffer[i] = bb_xstrdup(flines[linenum + i]); } line_pos = linenum; buffer_print(); } else { for (i = 0; i < (height - 1); i++) { free(buffer[i]); if (linenum + i < num_flines + 2) buffer[i] = bb_xstrdup(flines[linenum + i]); else buffer[i] = bb_xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n"); } line_pos = linenum; /* Set past_eof so buffer_down and buffer_up act differently */ past_eof = 1; buffer_print(); } }
/* Move the buffer up and down in the file in order to scroll */ static void buffer_down(int nlines) { int i; if (!past_eof) { if (line_pos + (height - 3) + nlines < num_flines) { line_pos += nlines; for (i = 0; i < (height - 1); i++) { free(buffer[i]); buffer[i] = bb_xstrdup(flines[line_pos + i]); } } else { /* As the number of lines requested was too large, we just move to the end of the file */ while (line_pos + (height - 3) + 1 < num_flines) { line_pos += 1; for (i = 0; i < (height - 1); i++) { free(buffer[i]); buffer[i] = bb_xstrdup(flines[line_pos + i]); } } } /* We exit if the -E flag has been set */ if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines)) tless_exit(0); } }
static const char * obscure_msg(const char *old, const char *newval, const struct passwd *pwdp) { int maxlen, oldlen, newlen; char *new1, *old1; const char *msg; oldlen = strlen(old); newlen = strlen(newval); #if 0 /* why not check the password when set for the first time? --marekm */ if (old[0] == '\0') /* return (1); */ return NULL; #endif if (newlen < 5) return "too short"; /* * Remaining checks are optional. */ /* Not for us -- Sean *if (!getdef_bool("OBSCURE_CHECKS_ENAB")) * return NULL; */ msg = password_check(old, newval, pwdp); if (msg) return msg; /* The traditional crypt() truncates passwords to 8 chars. It is possible to circumvent the above checks by choosing an easy 8-char password and adding some random characters to it... Example: "password$%^&*123". So check it again, this time truncated to the maximum length. Idea from npasswd. --marekm */ maxlen = 8; if (oldlen <= maxlen && newlen <= maxlen) return NULL; new1 = (char *) bb_xstrdup(newval); old1 = (char *) bb_xstrdup(old); if (newlen > maxlen) new1[maxlen] = '\0'; if (oldlen > maxlen) old1[maxlen] = '\0'; msg = password_check(old1, new1, pwdp); memset(new1, 0, newlen); memset(old1, 0, oldlen); free(new1); free(old1); return msg; }
static void buffer_up(int nlines) { int i; int tilde_line; if (!past_eof) { if (line_pos - nlines >= 0) { line_pos -= nlines; for (i = 0; i < (height - 1); i++) { free(buffer[i]); buffer[i] = bb_xstrdup(flines[line_pos + i]); } } else { /* As the requested number of lines to move was too large, we move one line up at a time until we can't. */ while (line_pos != 0) { line_pos -= 1; for (i = 0; i < (height - 1); i++) { free(buffer[i]); buffer[i] = bb_xstrdup(flines[line_pos + i]); } } } } else { /* Work out where the tildes start */ tilde_line = num_flines - line_pos + 3; line_pos -= nlines; /* Going backwards nlines lines has taken us to a point where nothing is past the EOF, so we revert to normal. */ if (line_pos < num_flines - height + 3) { past_eof = 0; buffer_up(nlines); } else { /* We only move part of the buffer, as the rest is past the EOF */ for (i = 0; i < (height - 1); i++) { free(buffer[i]); if (i < tilde_line - nlines + 1) buffer[i] = bb_xstrdup(flines[line_pos + i]); else { if (line_pos >= num_flines - height + 2) buffer[i] = bb_xstrdup("~\n"); } } } } }
/* * Extract any generic string from the given symbol. * Note: assumes same machine and arch for depmod and module. */ static void extract_generic_string(struct obj_file *f, MODULE *mod) { struct obj_section *sec; char *p, *ep, *s, **latest; sec = obj_find_section(f, ".modstring"); if (sec == NULL) return; p = sec->contents; ep = p + sec->header.sh_size; while (p < ep) { s = p; while (*p != '\0' && p < ep) p++; if (p >= ep) { bb_error_msg("unterminated generic string '%*s'", (int)(p - s), s); break; } if (p++ == s) /* empty string? */ continue; mod->generic_string = xrealloc(mod->generic_string, ++(mod->n_generic_string)*sizeof(*(mod->generic_string))); latest = mod->generic_string + mod->n_generic_string-1; *latest = bb_xstrdup(s); } }
static void data_readlines(void) { int i; char current_line[256]; FILE *fp; fp = (inp_stdin) ? stdin : bb_xfopen(filename, "r"); flines = NULL; for (i = 0; (feof(fp)==0) && (i <= MAXLINES); i++) { strcpy(current_line, ""); fgets(current_line, 256, fp); if (fp != stdin) bb_xferror(fp, filename); flines = xrealloc(flines, (i+1) * sizeof(char *)); flines[i] = bb_xstrdup(current_line); } num_flines = i - 2; /* Reset variables for a new file */ line_pos = 0; past_eof = 0; fclose(fp); if (inp == NULL) inp = (inp_stdin) ? bb_xfopen(CURRENT_TTY, "r") : stdin; if (flags & FLAG_N) add_linenumbers(); }
static unsigned char *extract_filename(char *line, unsigned short patch_level) { char *filename_start_ptr = line + 4; int i; /* Terminate string at end of source filename */ { char *line_ptr; line_ptr = strchr(filename_start_ptr, '\t'); if (!line_ptr) { bb_perror_msg("Malformed line %s", line); return(NULL); } *line_ptr = '\0'; } /* Skip over (patch_level) number of leading directories */ for (i = 0; i < patch_level; i++) { char *dirname_ptr; dirname_ptr = strchr(filename_start_ptr, '/'); if (!dirname_ptr) { break; } filename_start_ptr = dirname_ptr + 1; } return(bb_xstrdup(filename_start_ptr)); }
static llist_t *get_block_backed_filesystems(void) { char *fs, *buf, *filesystems[] = {"/etc/filesystems", "/proc/filesystems", 0}; llist_t *list = 0; int i; FILE *f; for(i = 0; filesystems[i]; i++) { if(!(f = fopen(filesystems[i], "r"))) continue; for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f)); free(buf)) { if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue; while(isspace(*fs)) fs++; if(*fs=='#' || *fs=='*') continue; if(!*fs) continue; llist_add_to_end(&list,bb_xstrdup(fs)); } if (ENABLE_FEATURE_CLEAN_UP) fclose(f); } return list; }
/* * Process the commands arguments */ static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) { /* handle (s)ubstitution command */ if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr); /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ else if (strchr("aic", sed_cmd->cmd)) { if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') bb_error_msg_and_die ("only a beginning address can be specified for edit commands"); while(isspace(*cmdstr)) cmdstr++; sed_cmd->string = bb_xstrdup(cmdstr); parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0); cmdstr += strlen(cmdstr); /* handle file cmds: (r)ead */ } else if(strchr("rw", sed_cmd->cmd)) { if (sed_cmd->end_line || sed_cmd->end_match) bb_error_msg_and_die("Command only uses one address"); cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string); if(sed_cmd->cmd=='w') sed_cmd->file=bb_xfopen(sed_cmd->string,"w"); /* handle branch commands */ } else if (strchr(":bt", sed_cmd->cmd)) { int length; while(isspace(*cmdstr)) cmdstr++; length = strcspn(cmdstr, semicolon_whitespace); if (length) { sed_cmd->string = strndup(cmdstr, length); cmdstr += length; } } /* translation command */ else if (sed_cmd->cmd == 'y') { char *match, *replace; int i=cmdstr[0]; cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1; /* \n already parsed, but \delimiter needs unescaping. */ parse_escapes(match,match,strlen(match),i,i); parse_escapes(replace,replace,strlen(replace),i,i); sed_cmd->string = xcalloc(1, (strlen(match) + 1) * 2); for (i = 0; match[i] && replace[i]; i++) { sed_cmd->string[i * 2] = match[i]; sed_cmd->string[(i * 2) + 1] = replace[i]; } free(match); free(replace); } /* if it wasnt a single-letter command that takes no arguments * then it must be an invalid command. */ else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) { bb_error_msg_and_die("Unsupported command %c", sed_cmd->cmd); } /* give back whatever's left over */ return (cmdstr); }
static void get_previous_history(void) { if(command_ps[0] != 0 || history[cur_history] == 0) { free(history[cur_history]); history[cur_history] = bb_xstrdup(command_ps); } cur_history--; }
/* Append mount options to string */ static void append_mount_options(char **oldopts, char *newopts) { if(*oldopts && **oldopts) { char *temp=bb_xasprintf("%s,%s",*oldopts,newopts); free(*oldopts); *oldopts=temp; } else { if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts); *oldopts = bb_xstrdup(newopts); } }
/* Initialise the buffer */ static void buffer_init(void) { int i; if (buffer == NULL) { /* malloc the number of lines needed for the buffer */ buffer = xrealloc(buffer, height * sizeof(char *)); } else { for (i = 0; i < (height - 1); i++) free(buffer[i]); } /* Fill the buffer until the end of the file or the end of the buffer is reached */ for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) { buffer[i] = bb_xstrdup(flines[i]); } /* If the buffer still isn't full, fill it with blank lines */ for (; i < (height - 1); i++) { buffer[i] = bb_xstrdup(""); } }
static void add_cmd_block(char *cmdstr) { int go=1; char *temp=bb_xstrdup(cmdstr),*temp2=temp; while(go) { int len=strcspn(temp2,"\n"); if(!temp2[len]) go=0; else temp2[len]=0; add_cmd(temp2); temp2+=len+1; } free(temp); }
int mount_main(int argc, char **argv) { char *cmdopts = bb_xstrdup(""), *fstabname, *fstype=0, *storage_path=0; FILE *fstab; int i, opt, all = FALSE, rc = 0; struct mntent mtpair[2], *mtcur = mtpair; int resolved_spec = 0; /* parse long options, like --bind and --move. Note that -o option * and --option are synonymous. Yes, this means --remount,rw works. */ for (i = opt = 0; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == '-') { append_mount_options(&cmdopts,argv[i]+2); } else argv[opt++] = argv[i]; } argc = opt; // Parse remaining options while ((opt = getopt(argc, argv, "o:t:rwavnfi")) > 0) { switch (opt) { case 'o': append_mount_options(&cmdopts, optarg); break; case 't': fstype = optarg; break; case 'r': append_mount_options(&cmdopts, "ro"); break; case 'w': append_mount_options(&cmdopts, "rw"); break; case 'a': all = TRUE; break; case 'n': USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;) break; case 'f': USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;) break; case 'i': case 'v': break; // ignore default: bb_show_usage(); }
void fileaction_dobackup(char *filename, int fileref) { struct stat oldfile; int stat_res; char *newname; if (rpm_getint(RPMTAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) { /* Only need to backup config files */ stat_res = lstat (filename, &oldfile); if (stat_res == 0 && S_ISREG(oldfile.st_mode)) { /* File already exists - really should check MD5's etc to see if different */ newname = bb_xstrdup(filename); newname = strcat(newname, ".rpmorig"); copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS); remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE); free(newname); } } }
/* * Read a sysctl setting * */ int sysctl_read_setting(const char *setting, int output) { int retval = 0; char *tmpname, *outname, *cptr; char inbuf[1025]; const char *name = setting; FILE *fp; if (!setting || !*setting) bb_error_msg(ERR_INVALID_KEY, setting); tmpname = concat_path_file(PROC_PATH, name); outname = bb_xstrdup(tmpname + strlen(PROC_PATH)); while ((cptr = strchr(tmpname, '.')) != NULL) *cptr = '/'; while ((cptr = strchr(outname, '/')) != NULL) *cptr = '.'; if ((fp = fopen(tmpname, "r")) == NULL) { switch (errno) { case ENOENT: bb_error_msg(ERR_INVALID_KEY, outname); break; case EACCES: bb_error_msg(ERR_PERMISSION_DENIED, outname); break; default: bb_error_msg(ERR_UNKNOWN_READING, errno, outname); break; } retval = -1; } else { while (fgets(inbuf, sizeof(inbuf) - 1, fp)) { if (output) { dwrite_str(STDOUT_FILENO, outname); dwrite_str(STDOUT_FILENO, " = "); } dwrite_str(STDOUT_FILENO, inbuf); } fclose(fp); } free(tmpname); free(outname); return retval; } /* end sysctl_read_setting() */
extern char *find_real_root_device_name(const char* name) { DIR *dir; struct dirent *entry; struct stat statBuf, rootStat; char *fileName = NULL; dev_t dev; if (stat("/", &rootStat) != 0) bb_perror_msg("could not stat '/'"); else { /* This check is here in case they pass in /dev name */ if ((rootStat.st_mode & S_IFMT) == S_IFBLK) dev = rootStat.st_rdev; else dev = rootStat.st_dev; dir = opendir("/dev"); if (!dir) bb_perror_msg("could not open '/dev'"); else { while((entry = readdir(dir)) != NULL) { const char *myname = entry->d_name; /* Must skip ".." since that is "/", and so we * would get a false positive on ".." */ if (myname[0] == '.' && myname[1] == '.' && !myname[2]) continue; fileName = concat_path_file("/dev", myname); /* Some char devices have the same dev_t as block * devices, so make sure this is a block device */ if (stat(fileName, &statBuf) == 0 && S_ISBLK(statBuf.st_mode)!=0 && statBuf.st_rdev == dev) break; free(fileName); fileName=NULL; } closedir(dir); } } if(fileName==NULL) fileName = bb_xstrdup("/dev/root"); return fileName; }
static int path_parse(char ***p, int flags) { int npth; const char *tmp; const char *pth; /* if not setenv PATH variable, to search cur dir "." */ if (flags != FIND_EXE_ONLY || (pth = cmdedit_path_lookup) == 0 || /* PATH=<empty> or PATH=:<empty> */ *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) { return 1; } tmp = pth; npth = 0; for (;;) { npth++; /* count words is + 1 count ':' */ tmp = strchr(tmp, ':'); if (tmp) { if (*++tmp == 0) break; /* :<empty> */ } else break; } *p = xmalloc(npth * sizeof(char *)); tmp = pth; (*p)[0] = bb_xstrdup(tmp); npth = 1; /* count words is + 1 count ':' */ for (;;) { tmp = strchr(tmp, ':'); if (tmp) { (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ if (*++tmp == 0) break; /* :<empty> */ } else break; (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ } return npth; }
static const char * password_check(const char *old, const char *newval, const struct passwd *pwdp) { const char *msg; char *newmono, *wrapped; int lenwrap; if (strcmp(newval, old) == 0) return "no change"; if (simple(newval)) return "too simple"; msg = NULL; newmono = str_lower(bb_xstrdup(newval)); lenwrap = strlen(old); wrapped = (char *) xmalloc(lenwrap * 2 + 1); str_lower(strcpy(wrapped, old)); if (palindrome(newmono)) msg = "a palindrome"; else if (strcmp(wrapped, newmono) == 0) msg = "case changes only"; else if (similiar(wrapped, newmono)) msg = "too similiar"; else if ( strstr(newval, pwdp->pw_name) ) msg = "username in password"; else { safe_strncpy(wrapped + lenwrap, wrapped, lenwrap + 1); if (strstr(wrapped, newmono)) msg = "rotated"; } memset(newmono, 0, strlen(newmono)); memset(wrapped, 0, lenwrap * 2); free(newmono); free(wrapped); return msg; }
/* * This function appends an option to a list */ static struct mod_opt_t *append_option( struct mod_opt_t *opt_list, char *opt ) { struct mod_opt_t *ol = opt_list; if( ol ) { while( ol-> m_next ) { ol = ol-> m_next; } ol-> m_next = xmalloc( sizeof( struct mod_opt_t ) ); ol = ol-> m_next; } else { ol = opt_list = xmalloc( sizeof( struct mod_opt_t ) ); } ol-> m_opt_val = bb_xstrdup( opt ); ol-> m_next = NULL; return opt_list; }
static void examine_file(void) { int newline_offset; clear_line(); printf("Examine: "); fgets(filename, 256, inp); /* As fgets adds a newline to the end of an input string, we need to remove it */ newline_offset = strlen(filename) - 1; filename[newline_offset] = '\0'; files[num_files] = bb_xstrdup(filename); current_file = num_files + 1; num_files++; inp_stdin = 0; reinitialise(); }
char *bb_simplify_path(const char *path) { char *s, *start, *p; if (path[0] == '/') start = bb_xstrdup(path); else { s = xgetcwd(NULL); start = concat_path_file(s, path); free(s); } p = s = start; do { if (*p == '/') { if (*s == '/') { /* skip duplicate (or initial) slash */ continue; } else if (*s == '.') { if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */ continue; } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) { ++s; if (p > start) { while (*--p != '/'); /* omit previous dir */ } continue; } } } *++p = *s; } while (*++s); if ((p == start) || (*p != '/')) { /* not a trailing slash */ ++p; /* so keep last character */ } *p = 0; return start; }
static char *process_regex_on_line(char *line, regex_t *pattern, int action) { /* This function takes the regex and applies it to the line. Each part of the line that matches has the HIGHLIGHT and NORMAL escape sequences placed around it by insert_highlights if action = 1, or has the escape sequences removed if action = 0, and then the line is returned. */ int match_status; char *line2 = (char *) xmalloc((sizeof(char) * (strlen(line) + 1)) + 64); char *growline = ""; regmatch_t match_structs; line2 = bb_xstrdup(line); match_found = 0; match_status = regexec(pattern, line2, 1, &match_structs, 0); while (match_status == 0) { if (match_found == 0) match_found = 1; if (action) { growline = bb_xasprintf("%s%.*s%s%.*s%s", growline, match_structs.rm_so, line2, HIGHLIGHT, match_structs.rm_eo - match_structs.rm_so, line2 + match_structs.rm_so, NORMAL); } else { growline = bb_xasprintf("%s%.*s%.*s", growline, match_structs.rm_so - 4, line2, match_structs.rm_eo - match_structs.rm_so, line2 + match_structs.rm_so); } line2 += match_structs.rm_eo; match_status = regexec(pattern, line2, 1, &match_structs, REG_NOTBOL); } growline = bb_xasprintf("%s%s", growline, line2); return (match_found ? growline : line); free(growline); free(line2); }
extern char get_header_tar(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; union { unsigned char raw[512]; struct { char name[100]; /* 0-99 */ char mode[8]; /* 100-107 */ char uid[8]; /* 108-115 */ char gid[8]; /* 116-123 */ char size[12]; /* 124-135 */ char mtime[12]; /* 136-147 */ char chksum[8]; /* 148-155 */ char typeflag; /* 156-156 */ char linkname[100]; /* 157-256 */ char magic[6]; /* 257-262 */ char version[2]; /* 263-264 */ char uname[32]; /* 265-296 */ char gname[32]; /* 297-328 */ char devmajor[8]; /* 329-336 */ char devminor[8]; /* 337-344 */ char prefix[155]; /* 345-499 */ char padding[12]; /* 500-512 */ } formated; } tar; long sum = 0; long i; char *tmp; /* Align header */ data_align(archive_handle, 512); if (archive_xread(archive_handle, tar.raw, 512) != 512) { /* Assume end of file */ return(EXIT_FAILURE); } archive_handle->offset += 512; /* If there is no filename its an empty header */ if (tar.formated.name[0] == 0) { return(EXIT_SUCCESS); } /* Check header has valid magic, "ustar" is for the proper tar * 0's are for the old tar format */ if (strncmp(tar.formated.magic, "ustar", 5) != 0) { #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) #endif bb_error_msg_and_die("Invalid tar magic"); } /* Do checksum on headers */ for (i = 0; i < 148 ; i++) { sum += tar.raw[i]; } sum += ' ' * 8; for (i = 156; i < 512 ; i++) { sum += tar.raw[i]; } if (sum != strtol(tar.formated.chksum, NULL, 8)) { bb_error_msg("Invalid tar header checksum"); return(EXIT_FAILURE); } #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS if (longname) { file_header->name = longname; longname = NULL; } else if (linkname) { file_header->name = linkname; linkname = NULL; } else #endif if (tar.formated.prefix[0] == 0) { file_header->name = strdup(tar.formated.name); } else { file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name); } tmp = last_char_is(archive_handle->file_header->name, '/'); if (tmp) { *tmp = '\0'; } file_header->mode = strtol(tar.formated.mode, NULL, 8); file_header->uid = strtol(tar.formated.uid, NULL, 8); file_header->gid = strtol(tar.formated.gid, NULL, 8); file_header->size = strtol(tar.formated.size, NULL, 8); file_header->mtime = strtol(tar.formated.mtime, NULL, 8); file_header->link_name = (tar.formated.linkname[0] != '\0') ? bb_xstrdup(tar.formated.linkname) : NULL; file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + strtol(tar.formated.devminor, NULL, 8)); if (tar.formated.typeflag == '1') { bb_error_msg("WARNING: Converting hard link to symlink"); file_header->mode |= S_IFLNK; } #if defined CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY || defined CONFIG_FEATURE_TAR_GNU_EXTENSIONS /* Fix mode, used by the old format */ switch (tar.formated.typeflag) { # ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY case 0: case '0': file_header->mode |= S_IFREG; break; case '1': // bb_error_msg("Internal hard link not supported"); break; case '2': file_header->mode |= S_IFLNK; break; case '3': file_header->mode |= S_IFCHR; break; case '4': file_header->mode |= S_IFBLK; break; case '5': file_header->mode |= S_IFDIR; break; case '6': file_header->mode |= S_IFIFO; break; # endif # ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS case 'L': { longname = xmalloc(file_header->size + 1); archive_xread_all(archive_handle, longname, file_header->size); longname[file_header->size] = '\0'; archive_handle->offset += file_header->size; return(get_header_tar(archive_handle)); } case 'K': { linkname = xmalloc(file_header->size + 1); archive_xread_all(archive_handle, linkname, file_header->size); linkname[file_header->size] = '\0'; archive_handle->offset += file_header->size; file_header->name = linkname; return(get_header_tar(archive_handle)); } case 'D': case 'M': case 'N': case 'S': case 'V': bb_error_msg("Ignoring GNU extension type %c", tar.formated.typeflag); # endif } #endif if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { archive_handle->action_header(archive_handle->file_header); archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; archive_handle->action_data(archive_handle); archive_handle->passed = llist_add_to(archive_handle->passed, archive_handle->file_header->name); } else { data_skip(archive_handle); } archive_handle->offset += file_header->size; return(EXIT_SUCCESS); }
/* numeric: & 0x8000: default instead of *, * & 0x4000: host instead of net, * & 0x0fff: don't resolve */ int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, int numeric, unsigned int netmask) { struct hostent *ent; struct netent *np; struct addr *pn; unsigned long ad, host_ad; int host = 0; /* Grmpf. -FvK */ if (s_in->sin_family != AF_INET) { #ifdef DEBUG bb_error_msg("rresolve: unsupport address family %d !", s_in->sin_family); #endif errno = EAFNOSUPPORT; return (-1); } ad = (unsigned long) s_in->sin_addr.s_addr; #ifdef DEBUG bb_error_msg("rresolve: %08lx, mask %08x, num %08x", ad, netmask, numeric); #endif if (ad == INADDR_ANY) { if ((numeric & 0x0FFF) == 0) { if (numeric & 0x8000) safe_strncpy(name, bb_INET_default, len); else safe_strncpy(name, "*", len); return (0); } } if (numeric & 0x0FFF) { safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); return (0); } if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) host = 1; #if 0 INET_nn = NULL; #endif pn = INET_nn; while (pn != NULL) { if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { safe_strncpy(name, pn->name, len); #ifdef DEBUG bb_error_msg("rresolve: found %s %08lx in cache", (host ? "host" : "net"), ad); #endif return (0); } pn = pn->next; } host_ad = ntohl(ad); np = NULL; ent = NULL; if (host) { #ifdef DEBUG bb_error_msg("gethostbyaddr (%08lx)", ad); #endif ent = gethostbyaddr((char *) &ad, 4, AF_INET); if (ent != NULL) { safe_strncpy(name, ent->h_name, len); } } else { #ifdef DEBUG bb_error_msg("getnetbyaddr (%08lx)", host_ad); #endif np = getnetbyaddr(host_ad, AF_INET); if (np != NULL) { safe_strncpy(name, np->n_name, len); } } if ((ent == NULL) && (np == NULL)) { safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); } pn = (struct addr *) xmalloc(sizeof(struct addr)); pn->addr = *s_in; pn->next = INET_nn; pn->host = host; pn->name = bb_xstrdup(name); INET_nn = pn; return (0); }
extern char get_header_tar(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; union { /* ustar header, Posix 1003.1 */ unsigned char raw[512]; struct { char name[100]; /* 0-99 */ char mode[8]; /* 100-107 */ char uid[8]; /* 108-115 */ char gid[8]; /* 116-123 */ char size[12]; /* 124-135 */ char mtime[12]; /* 136-147 */ char chksum[8]; /* 148-155 */ char typeflag; /* 156-156 */ char linkname[100]; /* 157-256 */ char magic[6]; /* 257-262 */ char version[2]; /* 263-264 */ char uname[32]; /* 265-296 */ char gname[32]; /* 297-328 */ char devmajor[8]; /* 329-336 */ char devminor[8]; /* 337-344 */ char prefix[155]; /* 345-499 */ char padding[12]; /* 500-512 */ } formated; } tar; long sum = 0; long i; /* Align header */ data_align(archive_handle, 512); if (bb_full_read(archive_handle->src_fd, tar.raw, 512) != 512) { /* Assume end of file */ return(EXIT_FAILURE); } archive_handle->offset += 512; /* If there is no filename its an empty header */ if (tar.formated.name[0] == 0) { return(EXIT_SUCCESS); } /* Check header has valid magic, "ustar" is for the proper tar * 0's are for the old tar format */ if (strncmp(tar.formated.magic, "ustar", 5) != 0) { #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) #endif bb_error_msg_and_die("Invalid tar magic"); } /* Do checksum on headers */ for (i = 0; i < 148 ; i++) { sum += tar.raw[i]; } sum += ' ' * 8; for (i = 156; i < 512 ; i++) { sum += tar.raw[i]; } if (sum != strtol(tar.formated.chksum, NULL, 8)) { bb_error_msg("Invalid tar header checksum"); return(EXIT_FAILURE); } #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS if (longname) { file_header->name = longname; longname = NULL; } else if (linkname) { file_header->name = linkname; linkname = NULL; } else #endif if (tar.formated.prefix[0] == 0) { file_header->name = strdup(tar.formated.name); } else { file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name); } file_header->uid = strtol(tar.formated.uid, NULL, 8); file_header->gid = strtol(tar.formated.gid, NULL, 8); file_header->size = strtol(tar.formated.size, NULL, 8); file_header->mtime = strtol(tar.formated.mtime, NULL, 8); file_header->link_name = (tar.formated.linkname[0] != '\0') ? bb_xstrdup(tar.formated.linkname) : NULL; file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + strtol(tar.formated.devminor, NULL, 8)); /* Set bits 0-11 of the files mode */ file_header->mode = 07777 & strtol(tar.formated.mode, NULL, 8); /* Set bits 12-15 of the files mode */ switch (tar.formated.typeflag) { /* busybox identifies hard links as being regular files with 0 size and a link name */ case '1': file_header->mode |= S_IFREG; break; case 'x': case 'g': bb_error_msg_and_die("pax is not tar"); break; case '7': /* Reserved for high performance files, treat as normal file */ case 0: case '0': #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY if (last_char_is(file_header->name, '/')) { file_header->mode |= S_IFDIR; } else #endif file_header->mode |= S_IFREG; break; case '2': file_header->mode |= S_IFLNK; break; case '3': file_header->mode |= S_IFCHR; break; case '4': file_header->mode |= S_IFBLK; break; case '5': file_header->mode |= S_IFDIR; break; case '6': file_header->mode |= S_IFIFO; break; #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS case 'L': { longname = xmalloc(file_header->size + 1); archive_xread_all(archive_handle, longname, file_header->size); longname[file_header->size] = '\0'; archive_handle->offset += file_header->size; return(get_header_tar(archive_handle)); } case 'K': { linkname = xmalloc(file_header->size + 1); archive_xread_all(archive_handle, linkname, file_header->size); linkname[file_header->size] = '\0'; archive_handle->offset += file_header->size; file_header->name = linkname; return(get_header_tar(archive_handle)); } case 'D': /* GNU dump dir */ case 'M': /* Continuation of multi volume archive*/ case 'N': /* Old GNU for names > 100 characters */ case 'S': /* Sparse file */ case 'V': /* Volume header */ bb_error_msg("Ignoring GNU extension type %c", tar.formated.typeflag); #endif default: bb_error_msg("Unknown typeflag: 0x%x", tar.formated.typeflag); } { /* Strip trailing '/' in directories */ /* Must be done after mode is set as '/' is used to check if its a directory */ char *tmp = last_char_is(file_header->name, '/'); if (tmp) { *tmp = '\0'; } } if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { archive_handle->action_header(archive_handle->file_header); archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; archive_handle->action_data(archive_handle); archive_handle->passed = llist_add_to(archive_handle->passed, file_header->name); } else { data_skip(archive_handle); } archive_handle->offset += file_header->size; free(file_header->link_name); return(EXIT_SUCCESS); }
static void rewrite(FS * fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; register PR *pr, **nextpr = NULL; register FU *fu; register char *p1, *p2, *p3; char savech, *fmtp; const char *byte_count_str; int nconv, prec = 0; for (fu = fs->nextfu; fu; fu = fu->nextfu) { /* * break each format unit into print units; each * conversion character gets its own. */ for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { /* NOSTRICT */ /* DBU:[[email protected]] calloc so that forward ptrs start out NULL*/ pr = (PR *) xcalloc(1,sizeof(PR)); if (!fu->nextpr) fu->nextpr = pr; /* ignore nextpr -- its unused inside the loop and is * uninitialized 1st time thru. */ /* bb_dump_skip preceding text and up to the next % sign */ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); /* only text in the string */ if (!*p1) { pr->fmt = fmtp; pr->flags = F_TEXT; break; } /* * get precision for %s -- if have a byte count, don't * need it. */ if (fu->bcnt) { sokay = USEBCNT; /* bb_dump_skip to conversion character */ for (++p1; strchr(index_str, *p1); ++p1); } else { /* bb_dump_skip any special chars, field width */ while (strchr(index_str + 1, *++p1)); if (*p1 == '.' && isdigit(*++p1)) { sokay = USEPREC; prec = atoi(p1); while (isdigit(*++p1)); } else sokay = NOTOKAY; } p2 = p1 + 1; /* set end pointer */ /* * figure out the byte count for each conversion; * rewrite the format as necessary, set up blank- * pbb_dump_adding for end of data. */ if (*p1 == 'c') { pr->flags = F_CHAR; DO_BYTE_COUNT_1: byte_count_str = "\001"; DO_BYTE_COUNT: if (fu->bcnt) { do { if (fu->bcnt == *byte_count_str) { break; } } while (*++byte_count_str); } /* Unlike the original, output the remainder of the format string. */ if (!*byte_count_str) { bb_error_msg_and_die("bad byte count for conversion character %s.", p1); } pr->bcnt = *byte_count_str; } else if (*p1 == 'l') { ++p2; ++p1; DO_INT_CONV: { const char *e; if (!(e = strchr(lcc, *p1))) { goto DO_BAD_CONV_CHAR; } pr->flags = F_INT; if (e > lcc + 1) { pr->flags = F_UINT; } byte_count_str = "\004\002\001"; goto DO_BYTE_COUNT; } /* NOTREACHED */ } else if (strchr(lcc, *p1)) { goto DO_INT_CONV; } else if (strchr("eEfgG", *p1)) { pr->flags = F_DBL; byte_count_str = "\010\004"; goto DO_BYTE_COUNT; } else if (*p1 == 's') { pr->flags = F_STR; if (sokay == USEBCNT) { pr->bcnt = fu->bcnt; } else if (sokay == USEPREC) { pr->bcnt = prec; } else { /* NOTOKAY */ bb_error_msg_and_die("%%s requires a precision or a byte count."); } } else if (*p1 == '_') { ++p2; switch (p1[1]) { case 'A': endfu = fu; fu->flags |= F_IGNORE; /* FALLTHROUGH */ case 'a': pr->flags = F_ADDRESS; ++p2; if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) { goto DO_BAD_CONV_CHAR; } *p1 = p1[2]; break; case 'c': pr->flags = F_C; /* *p1 = 'c'; set in conv_c */ goto DO_BYTE_COUNT_1; case 'p': pr->flags = F_P; *p1 = 'c'; goto DO_BYTE_COUNT_1; case 'u': pr->flags = F_U; /* *p1 = 'c'; set in conv_u */ goto DO_BYTE_COUNT_1; default: goto DO_BAD_CONV_CHAR; } } else { DO_BAD_CONV_CHAR: bb_error_msg_and_die("bad conversion character %%%s.\n", p1); } /* * copy to PR format string, set conversion character * pointer, update original. */ savech = *p2; p1[1] = '\0'; pr->fmt = bb_xstrdup(fmtp); *p2 = savech; pr->cchar = pr->fmt + (p1 - fmtp); /* DBU:[[email protected]] w/o this, trailing fmt text, space is lost. * Skip subsequent text and up to the next % sign and tack the * additional text onto fmt: eg. if fmt is "%x is a HEX number", * we lose the " is a HEX number" part of fmt. */ for (p3 = p2; *p3 && *p3 != '%'; p3++); if (p3 > p2) { savech = *p3; *p3 = '\0'; if (!(pr->fmt = realloc(pr->fmt, strlen(pr->fmt)+(p3-p2)+1))) bb_perror_msg_and_die("hexdump"); strcat(pr->fmt, p2); *p3 = savech; p2 = p3; } fmtp = p2; /* only one conversion character if byte count */ if (!(pr->flags & F_ADDRESS) && fu->bcnt && nconv++) { bb_error_msg_and_die("byte count with multiple conversion characters.\n"); } } /* * if format unit byte count not specified, figure it out * so can adjust rep count later. */ if (!fu->bcnt) for (pr = fu->nextpr; pr; pr = pr->nextpr) fu->bcnt += pr->bcnt; } /* * if the format string interprets any data at all, and it's * not the same as the bb_dump_blocksize, and its last format unit * interprets any data at all, and has no iteration count, * repeat it as necessary. * * if, rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ for (fu = fs->nextfu;; fu = fu->nextfu) { if (!fu->nextfu && fs->bcnt < bb_dump_blocksize && !(fu->flags & F_SETREP) && fu->bcnt) fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt; if (fu->reps > 1) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) p2 = isspace(*p1) ? p1 : NULL; if (p2) pr->nospace = p2; } if (!fu->nextfu) break; } }
void data_extract_all(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; int dst_fd; int res; if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { char *name = bb_xstrdup(file_header->name); bb_make_directory (dirname(name), -1, FILEUTILS_RECUR); free(name); } /* Check if the file already exists */ if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { /* Remove the existing entry if it exists */ if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) { bb_perror_msg_and_die("Couldnt remove old file"); } } else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) { /* Remove the existing entry if its older than the extracted entry */ struct stat statbuf; if (lstat(file_header->name, &statbuf) == -1) { if (errno != ENOENT) { bb_perror_msg_and_die("Couldnt stat old file"); } } else if (statbuf.st_mtime <= file_header->mtime) { if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_error_msg("%s not created: newer or same age file exists", file_header->name); } data_skip(archive_handle); return; } else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name); } } /* Handle hard links separately * We identified hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) { /* hard link */ res = link(file_header->link_name, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Couldnt create hard link"); } } else { /* Create the filesystem entry */ switch(file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL); bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); break; } case S_IFDIR: res = mkdir(file_header->name, file_header->mode); if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("extract_archive: %s", file_header->name); } break; case S_IFLNK: /* Symlink */ res = symlink(file_header->link_name, file_header->name); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); } break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(file_header->name, file_header->mode, file_header->device); if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { bb_perror_msg("Cannot create node %s", file_header->name); } break; default: bb_error_msg_and_die("Unrecognised file type"); } } if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_OWN)) { lchown(file_header->name, file_header->uid, file_header->gid); } if (!(archive_handle->flags & ARCHIVE_NOPRESERVE_PERM) && (file_header->mode & S_IFMT) != S_IFLNK) { chmod(file_header->name, file_header->mode); } if (archive_handle->flags & ARCHIVE_PRESERVE_DATE && !S_ISLNK(file_header->mode)) { struct utimbuf t; t.actime = t.modtime = file_header->mtime; utime(file_header->name, &t); } }
extern char get_header_ar(archive_handle_t *archive_handle) { file_header_t *typed = archive_handle->file_header; union { char raw[60]; struct { char name[16]; char date[12]; char uid[6]; char gid[6]; char mode[8]; char size[10]; char magic[2]; } formated; } ar; #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES static char *ar_long_names; static unsigned int ar_long_name_size; #endif /* dont use bb_xread as we want to handle the error ourself */ if (read(archive_handle->src_fd, ar.raw, 60) != 60) { /* End Of File */ return(EXIT_FAILURE); } /* Some ar entries have a trailing '\n' after the previous data entry */ if (ar.raw[0] == '\n') { /* fix up the header, we started reading 1 byte too early */ memmove(ar.raw, &ar.raw[1], 59); ar.raw[59] = bb_xread_char(archive_handle->src_fd); archive_handle->offset++; } archive_handle->offset += 60; /* align the headers based on the header magic */ if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { bb_error_msg_and_die("Invalid ar header"); } typed->mode = strtol(ar.formated.mode, NULL, 8); typed->mtime = atoi(ar.formated.date); typed->uid = atoi(ar.formated.uid); typed->gid = atoi(ar.formated.gid); typed->size = atoi(ar.formated.size); /* long filenames have '/' as the first character */ if (ar.formated.name[0] == '/') { #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES if (ar.formated.name[1] == '/') { /* If the second char is a '/' then this entries data section * stores long filename for multiple entries, they are stored * in static variable long_names for use in future entries */ ar_long_name_size = typed->size; ar_long_names = xmalloc(ar_long_name_size); bb_xread_all(archive_handle->src_fd, ar_long_names, ar_long_name_size); archive_handle->offset += ar_long_name_size; /* This ar entries data section only contained filenames for other records * they are stored in the static ar_long_names for future reference */ return (get_header_ar(archive_handle)); /* Return next header */ } else if (ar.formated.name[1] == ' ') { /* This is the index of symbols in the file for compilers */ data_skip(archive_handle); archive_handle->offset += typed->size; return (get_header_ar(archive_handle)); /* Return next header */ } else { /* The number after the '/' indicates the offset in the ar data section (saved in variable long_name) that conatains the real filename */ const unsigned int long_offset = atoi(&ar.formated.name[1]); if (long_offset >= ar_long_name_size) { bb_error_msg_and_die("Cant resolve long filename"); } typed->name = bb_xstrdup(ar_long_names + long_offset); } #else bb_error_msg_and_die("long filenames not supported"); #endif } else { /* short filenames */ typed->name = bb_xstrndup(ar.formated.name, 16); } typed->name[strcspn(typed->name, " /")] = '\0'; if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { archive_handle->action_header(typed); if (archive_handle->sub_archive) { while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS); } else { archive_handle->action_data(archive_handle); } } else { data_skip(archive_handle); } archive_handle->offset += typed->size; /* Set the file pointer to the correct spot, we may have been reading a compressed file */ lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET); return(EXIT_SUCCESS); }