int readahead_main(int argc UNUSED_PARAM, char **argv) { int retval = EXIT_SUCCESS; if (!argv[1]) { bb_show_usage(); } while (*++argv) { int fd = open_or_warn(*argv, O_RDONLY); if (fd >= 0) { off_t len; int r; /* fdlength was reported to be unreliable - use seek */ len = xlseek(fd, 0, SEEK_END); xlseek(fd, 0, SEEK_SET); r = readahead(fd, 0, len); close(fd); if (r >= 0) continue; } retval = EXIT_FAILURE; } return retval; }
int fsync_main(int argc UNUSED_PARAM, char **argv) { int status; int opts; opts = getopt32(argv, "d"); /* fdatasync */ argv += optind; if (!*argv) { bb_show_usage(); } status = EXIT_SUCCESS; do { int fd = open_or_warn(*argv, O_NOATIME | O_NOCTTY | O_RDONLY); if (fd == -1) { status = EXIT_FAILURE; continue; } if ((opts ? fdatasync(fd) : fsync(fd))) { //status = EXIT_FAILURE; - do we want this? bb_simple_perror_msg(*argv); } close(fd); } while (*++argv); return status; }
static void reopen_logfile_to_stderr(void) { if (G.log_filename) { int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND); if (logfd >= 0) xmove_fd(logfd, STDERR_FILENO); } }
void FAST_FUNC read_leases(const char *file) { struct dyn_lease lease; int64_t written_at, time_passed; int fd; #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 unsigned i = 0; #endif fd = open_or_warn(file, O_RDONLY); if (fd < 0) return; if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) goto ret; written_at = SWAP_BE64(written_at); time_passed = time(NULL) - written_at; /* Strange written_at, or lease file from old version of udhcpd * which had no "written_at" field? */ if ((uint64_t)time_passed > 12 * 60 * 60) goto ret; while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { //FIXME: what if it matches some static lease? uint32_t y = ntohl(lease.lease_nip); if (y >= server_config.start_ip && y <= server_config.end_ip) { signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; if (expires <= 0) continue; /* NB: add_lease takes "relative time", IOW, * lease duration, not lease deadline. */ if (add_lease(lease.lease_mac, lease.lease_nip, expires, lease.hostname, sizeof(lease.hostname) ) == 0 ) { bb_error_msg("too many leases while loading %s", file); break; } #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 i++; #endif } } log1("Read %d leases", i); ret: close(fd); }
void FAST_FUNC write_leases(void) { int fd; unsigned i; leasetime_t curr; int64_t written_at; fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC); if (fd < 0) return; curr = written_at = time(NULL); written_at = SWAP_BE64(written_at); full_write(fd, &written_at, sizeof(written_at)); for (i = 0; i < server_config.max_leases; i++) { leasetime_t tmp_time; if (g_leases[i].lease_nip == 0) continue; /* Screw with the time in the struct, for easier writing */ tmp_time = g_leases[i].expires; g_leases[i].expires -= curr; if ((signed_leasetime_t) g_leases[i].expires < 0) g_leases[i].expires = 0; g_leases[i].expires = htonl(g_leases[i].expires); /* No error check. If the file gets truncated, * we lose some leases on restart. Oh well. */ full_write(fd, &g_leases[i], sizeof(g_leases[i])); /* Then restore it when done */ g_leases[i].expires = tmp_time; } close(fd); if (server_config.notify_file) { char *argv[3]; argv[0] = server_config.notify_file; argv[1] = server_config.lease_file; argv[2] = NULL; spawn_and_wait(argv); } }
int readahead_main(int argc, char **argv) { int retval = EXIT_SUCCESS; if (argc == 1) bb_show_usage(); while (*++argv) { int fd = open_or_warn(*argv, O_RDONLY); if (fd >= 0) { int r = readahead(fd, 0, fdlength(fd)); close(fd); if (r >= 0) continue; } retval = EXIT_FAILURE; } return retval; }
static int xbsd_get_bootstrap(char *path, void *ptr, int size) { int fdb; fdb = open_or_warn(path, O_RDONLY); if (fdb < 0) { return 0; } if (full_read(fdb, ptr, size) < 0) { bb_simple_perror_msg(path); close(fdb); return 0; } printf(" ... %s\n", path); close(fdb); return 1; }
/* Return: * -1 error, copy not made * 0 copy is made or user answered "no" in interactive mode * (failures to preserve mode/owner/times are not reported in exit code) */ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) { /* This is a recursive function, try to minimize stack usage */ /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; smallint retval = 0; smallint dest_exists = 0; smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { /* This may be a dangling symlink. * Making [sym]links to dangling symlinks works, so... */ if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) goto make_links; bb_perror_msg("can't stat '%s'", source); return -1; } if (lstat(dest, &dest_stat) < 0) { if (errno != ENOENT) { bb_perror_msg("can't stat '%s'", dest); return -1; } } else { if (source_stat.st_dev == dest_stat.st_dev && source_stat.st_ino == dest_stat.st_ino ) { bb_error_msg("'%s' and '%s' are the same file", source, dest); return -1; } dest_exists = 1; } #if ENABLE_SELINUX if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) { security_context_t con; if (lgetfilecon(source, &con) >= 0) { if (setfscreatecon(con) < 0) { bb_perror_msg("can't set setfscreatecon %s", con); freecon(con); return -1; } } else if (errno == ENOTSUP || errno == ENODATA) { setfscreatecon_or_die(NULL); } else { bb_perror_msg("can't lgetfilecon %s", source); return -1; } } #endif if (S_ISDIR(source_stat.st_mode)) { DIR *dp; const char *tp; struct dirent *d; mode_t saved_umask = 0; if (!(flags & FILEUTILS_RECUR)) { bb_error_msg("omitting directory '%s'", source); return -1; } /* Did we ever create source ourself before? */ tp = is_in_ino_dev_hashtable(&source_stat); if (tp) { /* We did! it's a recursion! man the lifeboats... */ bb_error_msg("recursion detected, omitting directory '%s'", source); return -1; } if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); return -1; } /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { /* Create DEST */ mode_t mode; saved_umask = umask(0); mode = source_stat.st_mode; if (!(flags & FILEUTILS_PRESERVE_STATUS)) mode = source_stat.st_mode & ~saved_umask; /* Allow owner to access new dir (at least for now) */ mode |= S_IRWXU; if (mkdir(dest, mode) < 0) { umask(saved_umask); bb_perror_msg("can't create directory '%s'", dest); return -1; } umask(saved_umask); /* need stat info for add_to_ino_dev_hashtable */ if (lstat(dest, &dest_stat) < 0) { bb_perror_msg("can't stat '%s'", dest); return -1; } } /* remember (dev,inode) of each created dir. * NULL: name is not remembered */ add_to_ino_dev_hashtable(&dest_stat, NULL); /* Recursively copy files in SOURCE */ dp = opendir(source); if (dp == NULL) { retval = -1; goto preserve_mode_ugid_time; } while ((d = readdir(dp)) != NULL) { char *new_source, *new_dest; new_source = concat_subpath_file(source, d->d_name); if (new_source == NULL) continue; new_dest = concat_path_file(dest, d->d_name); if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0) retval = -1; free(new_source); free(new_dest); } closedir(dp); if (!dest_exists && chmod(dest, source_stat.st_mode & ~saved_umask) < 0 ) { bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); /* retval = -1; - WRONG! copy *WAS* made */ } goto preserve_mode_ugid_time; } if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { int (*lf)(const char *oldpath, const char *newpath); make_links: /* Hmm... maybe * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? * (but realpath returns NULL on dangling symlinks...) */ lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; if (lf(source, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (lf(source, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } /* _Not_ jumping to preserve_mode_ugid_time: * (sym)links don't have those */ return 0; } if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */ !(flags & FILEUTILS_RECUR) /* "cp [-opts] regular_file thing2" */ || S_ISREG(source_stat.st_mode) /* DEREF uses stat, which never returns S_ISLNK() == true. * So the below is never true: */ /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ ) { int src_fd; int dst_fd; mode_t new_mode; if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) { /* "cp -d symlink dst": create a link */ goto dont_cat; } if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { const char *link_target; link_target = is_in_ino_dev_hashtable(&source_stat); if (link_target) { if (link(link_target, dest) < 0) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; if (link(link_target, dest) < 0) { bb_perror_msg("can't create link '%s'", dest); return -1; } } return 0; } add_to_ino_dev_hashtable(&source_stat, dest); } src_fd = open_or_warn(source, O_RDONLY); if (src_fd < 0) return -1; /* Do not try to open with weird mode fields */ new_mode = source_stat.st_mode; if (!S_ISREG(source_stat.st_mode)) new_mode = 0666; // POSIX way is a security problem versus (sym)link attacks if (!ENABLE_FEATURE_NON_POSIX_CP) { dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); } else { /* safe way: */ dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); } if (dst_fd == -1) { ovr = ask_and_unlink(dest, flags); if (ovr <= 0) { close(src_fd); return ovr; } /* It shouldn't exist. If it exists, do not open (symlink attack?) */ dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); if (dst_fd < 0) { close(src_fd); return -1; } } #if ENABLE_SELINUX if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT)) && is_selinux_enabled() > 0 ) { security_context_t con; if (getfscreatecon(&con) == -1) { bb_perror_msg("getfscreatecon"); return -1; } if (con) { if (setfilecon(dest, con) == -1) { bb_perror_msg("setfilecon:%s,%s", dest, con); freecon(con); return -1; } freecon(con); } } #endif if (bb_copyfd_eof(src_fd, dst_fd) == -1) retval = -1; /* Careful with writing... */ if (close(dst_fd) < 0) { bb_perror_msg("error writing to '%s'", dest); retval = -1; } /* ...but read size is already checked by bb_copyfd_eof */ close(src_fd); /* "cp /dev/something new_file" should not * copy mode of /dev/something */ if (!S_ISREG(source_stat.st_mode)) return retval; goto preserve_mode_ugid_time; } dont_cat: /* Source is a symlink or a special file */ /* We are lazy here, a bit lax with races... */ if (dest_exists) { errno = EEXIST; ovr = ask_and_unlink(dest, flags); if (ovr <= 0) return ovr; } if (S_ISLNK(source_stat.st_mode)) { char *lpath = xmalloc_readlink_or_warn(source); if (lpath) { int r = symlink(lpath, dest); free(lpath); if (r < 0) { bb_perror_msg("can't create symlink '%s'", dest); return -1; } if (flags & FILEUTILS_PRESERVE_STATUS) if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } /* _Not_ jumping to preserve_mode_ugid_time: * symlinks don't have those */ return 0; } if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) ) { if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { bb_perror_msg("can't create '%s'", dest); return -1; } } else { bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode); return -1; } preserve_mode_ugid_time: if (flags & FILEUTILS_PRESERVE_STATUS /* Cannot happen: */ /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */ ) { struct timeval times[2]; times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime; times[1].tv_usec = times[0].tv_usec = 0; /* BTW, utimes sets usec-precision time - just FYI */ if (utimes(dest, times) < 0) bb_perror_msg("can't preserve %s of '%s'", "times", dest); if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { source_stat.st_mode &= ~(S_ISUID | S_ISGID); bb_perror_msg("can't preserve %s of '%s'", "ownership", dest); } #if ENABLE_XATTR /* Preserve extended attributes. We must copy it after chown() * because it resets capabilities. */ if (copy_file_attr(source, dest) == -1) bb_perror_msg("can't preserve %s of '%s'", "extended attributes", dest); #endif if (chmod(dest, source_stat.st_mode) < 0) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } return retval; }
static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf, void *userData, int depth UNUSED_PARAM) { struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; const char *header_name; int inputFileFd = -1; /* Strip leading '/' (must be before memorizing hardlink's name) */ header_name = fileName; while (header_name[0] == '/') { static smallint warned; if (!warned) { bb_error_msg("removing leading '/' from member names"); warned = 1; } header_name++; } if (header_name[0] == '\0') return TRUE; /* It is against the rules to archive a socket */ if (S_ISSOCK(statbuf->st_mode)) { bb_error_msg("%s: socket ignored", fileName); return TRUE; } /* * Check to see if we are dealing with a hard link. * If so - * Treat the first occurance of a given dev/inode as a file while * treating any additional occurances as hard links. This is done * by adding the file information to the HardLinkInfo linked list. */ tbInfo->hlInfo = NULL; if (statbuf->st_nlink > 1) { tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); if (tbInfo->hlInfo == NULL) addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name); } /* It is a bad idea to store the archive we are in the process of creating, * so check the device and inode to be sure that this particular file isn't * the new tarball */ if (tbInfo->statBuf.st_dev == statbuf->st_dev && tbInfo->statBuf.st_ino == statbuf->st_ino ) { bb_error_msg("%s: file is the archive; skipping", fileName); return TRUE; } if (exclude_file(tbInfo->excludeList, header_name)) return SKIP; #if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS if (strlen(header_name) >= NAME_SIZE) { bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); return TRUE; } #endif /* Is this a regular file? */ if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) { /* open the file we want to archive, and make sure all is well */ inputFileFd = open_or_warn(fileName, O_RDONLY); if (inputFileFd < 0) { return FALSE; } } /* Add an entry to the tarball */ if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) { return FALSE; } /* If it was a regular file, write out the body */ if (inputFileFd >= 0) { size_t readSize; /* Write the file to the archive. */ /* We record size into header first, */ /* and then write out file. If file shrinks in between, */ /* tar will be corrupted. So we don't allow for that. */ /* NB: GNU tar 1.16 warns and pads with zeroes */ /* or even seeks back and updates header */ bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); ////off_t readSize; ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); ////if (readSize != statbuf->st_size && readSize >= 0) { //// bb_error_msg_and_die("short read from %s, aborting", fileName); ////} /* Check that file did not grow in between? */ /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */ close(inputFileFd); /* Pad the file up to the tar block size */ /* (a few tricks here in the name of code size) */ readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1); memset(block_buf, 0, readSize); xwrite(tbInfo->tarFd, block_buf, readSize); } return TRUE; }
int microcom_main(int argc UNUSED_PARAM, char **argv) { int sfd; int nfd; struct pollfd pfd[2]; struct termios tio0, tiosfd, tio; char *device_lock_file; enum { OPT_X = 1 << 0, // do not respect Ctrl-X, Ctrl-@ OPT_s = 1 << 1, // baudrate OPT_d = 1 << 2, // wait for device response, ms OPT_t = 1 << 3, // timeout, ms }; speed_t speed = 9600; int delay = -1; int timeout = -1; unsigned opts; // fetch options opt_complementary = "=1:s+:d+:t+"; // exactly one arg, numeric options opts = getopt32(argv, "Xs:d:t:", &speed, &delay, &timeout); // argc -= optind; argv += optind; // try to create lock file in /var/lock device_lock_file = (char *)bb_basename(argv[0]); device_lock_file = xasprintf("/var/lock/LCK..%s", device_lock_file); sfd = open(device_lock_file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644); if (sfd < 0) { // device already locked -> bail out if (errno == EEXIST) bb_perror_msg_and_die("can't create %s", device_lock_file); // can't create lock -> don't care if (ENABLE_FEATURE_CLEAN_UP) free(device_lock_file); device_lock_file = NULL; } else { // %4d to make concurrent mgetty (if any) happy. // Mgetty treats 4-bytes lock files as binary, // not text, PID. Making 5+ char file. Brrr... fdprintf(sfd, "%4d\n", getpid()); close(sfd); } // setup signals bb_signals(0 + (1 << SIGHUP) + (1 << SIGINT) + (1 << SIGTERM) + (1 << SIGPIPE) , signal_handler); // error exit code if we fail to open the device signalled = 1; // open device sfd = open_or_warn(argv[0], O_RDWR | O_NOCTTY | O_NONBLOCK); if (sfd < 0) goto done; fcntl(sfd, F_SETFL, 0); // put device to "raw mode" xget1(sfd, &tio, &tiosfd); // set device speed cfsetspeed(&tio, tty_value_to_baud(speed)); if (xset1(sfd, &tio, argv[0])) goto done; // put stdin to "raw mode" (if stdin is a TTY), // handle one character at a time if (isatty(STDIN_FILENO)) { xget1(STDIN_FILENO, &tio, &tio0); if (xset1(STDIN_FILENO, &tio, "stdin")) goto done; } // main loop: check with poll(), then read/write bytes across pfd[0].fd = sfd; pfd[0].events = POLLIN; pfd[1].fd = STDIN_FILENO; pfd[1].events = POLLIN; signalled = 0; nfd = 2; while (!signalled && safe_poll(pfd, nfd, timeout) > 0) { if (nfd > 1 && pfd[1].revents) { char c; // read from stdin -> write to device if (safe_read(STDIN_FILENO, &c, 1) < 1) { // don't poll stdin anymore if we got EOF/error nfd--; goto skip_write; } // do we need special processing? if (!(opts & OPT_X)) { // ^@ sends Break if (VINTR == c) { tcsendbreak(sfd, 0); goto skip_write; } // ^X exits if (24 == c) break; } write(sfd, &c, 1); if (delay >= 0) safe_poll(pfd, 1, delay); skip_write: ; } if (pfd[0].revents) { #define iobuf bb_common_bufsiz1 ssize_t len; // read from device -> write to stdout len = safe_read(sfd, iobuf, sizeof(iobuf)); if (len > 0) full_write(STDOUT_FILENO, iobuf, len); else { // EOF/error -> bail out signalled = SIGHUP; break; } } } // restore device mode tcsetattr(sfd, TCSAFLUSH, &tiosfd); if (isatty(STDIN_FILENO)) tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); done: if (device_lock_file) unlink(device_lock_file); return signalled; }
void FAST_FUNC read_leases(const char *file) { struct dyn_lease lease; int64_t written_at, time_passed; int fd; #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 unsigned i = 0; #endif fd = open_or_warn(file, O_RDONLY); if (fd < 0) return; if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) goto ret; written_at = SWAP_BE64(written_at); time_passed = time(NULL) - written_at; /* Strange written_at, or lease file from old version of udhcpd * which had no "written_at" field? */ if ((uint64_t)time_passed > 12 * 60 * 60) goto ret; while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { uint32_t y = ntohl(lease.lease_nip); if (y >= server_config.start_ip && y <= server_config.end_ip) { signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; uint32_t static_nip; if (expires <= 0) /* We keep expired leases: add_lease() will add * a lease with 0 seconds remaining. * Fewer IP address changes this way for mass reboot scenario. */ expires = 0; /* Check if there is a different static lease for this IP or MAC */ static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac); if (static_nip) { /* NB: we do not add lease even if static_nip == lease.lease_nip. */ continue; } if (is_nip_reserved(server_config.static_leases, lease.lease_nip)) continue; /* NB: add_lease takes "relative time", IOW, * lease duration, not lease deadline. */ if (add_lease(lease.lease_mac, lease.lease_nip, expires, lease.hostname, sizeof(lease.hostname) ) == 0 ) { bb_error_msg("too many leases while loading %s", file); break; } #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 i++; #endif } } log1("read %d leases", i); ret: close(fd); }
int catv_main(int argc, char **argv) { int retval = EXIT_SUCCESS; int fd; unsigned flags; flags = getopt32(argv, "etv"); #define CATV_OPT_e (1<<0) #define CATV_OPT_t (1<<1) #define CATV_OPT_v (1<<2) flags ^= CATV_OPT_v; argv += optind; /* Read from stdin if there's nothing else to do. */ fd = 0; if (!argv[0]) { argv--; goto jump_in; } do { fd = open_or_warn(*argv, O_RDONLY); if (fd < 0) { retval = EXIT_FAILURE; continue; } jump_in: for (;;) { int i, res; #define read_buf bb_common_bufsiz1 res = read(fd, read_buf, COMMON_BUFSIZE); if (res < 0) retval = EXIT_FAILURE; if (res < 1) break; for (i = 0; i < res; i++) { unsigned char c = read_buf[i]; if (c > 126 && (flags & CATV_OPT_v)) { if (c == 127) { printf("^?"); continue; } printf("M-"); c -= 128; } if (c < 32) { if (c == 10) { if (flags & CATV_OPT_e) bb_putchar('$'); } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) { printf("^%c", c+'@'); continue; } } bb_putchar(c); } } if (ENABLE_FEATURE_CLEAN_UP && fd) close(fd); } while (*++argv); fflush_stdout_and_exit(retval); }