/* len should probably be size_t */ static void tail_xbb_full_write(const char *buf, size_t len) { /* If we get a write error, there is really no sense in continuing. */ if (bb_full_write(STDOUT_FILENO, buf, len) < 0) { bb_perror_nomsg_and_die(); } }
static size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size2) { int status; size_t xread, wrote, total, size = size2; if (src_fd < 0) { return -1; } if (size == 0) { /* If size is 0 copy until EOF */ size = ULONG_MAX; } { RESERVE_CONFIG_BUFFER(buffer,BUFSIZ); total = 0; wrote = 0; status = -1; while (total < size) { xread = BUFSIZ; if (size < (total + BUFSIZ)) xread = size - total; xread = bb_full_read(src_fd, buffer, xread); if (xread > 0) { if (dst_fd < 0) { /* A -1 dst_fd means we need to fake it... */ wrote = xread; } else { wrote = bb_full_write(dst_fd, buffer, xread); } if (wrote < xread) { bb_perror_msg(bb_msg_write_error); break; } total += wrote; } else if (xread < 0) { bb_perror_msg(bb_msg_read_error); break; } else if (xread == 0) { /* All done. */ status = 0; break; } } RELEASE_CONFIG_BUFFER(buffer); } if (status == 0 || total) return total; /* Some sortof error occured */ return -1; }
/* If size is 0 copy until EOF */ static ssize_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size) { ssize_t read_total = 0; RESERVE_CONFIG_BUFFER(buffer,BUFSIZ); while ((size == 0) || (read_total < size)) { size_t read_try; ssize_t read_actual; if ((size == 0) || (size - read_total > BUFSIZ)) { read_try = BUFSIZ; } else { read_try = size - read_total; } read_actual = safe_read(src_fd, buffer, read_try); if (read_actual > 0) { if ((dst_fd >= 0) && (bb_full_write(dst_fd, buffer, (size_t) read_actual) != read_actual)) { bb_perror_msg(bb_msg_write_error); /* match Read error below */ break; } } else if (read_actual == 0) { if (size) { bb_error_msg("Unable to read all data"); read_total = -1; } break; } else { /* read_actual < 0 */ bb_perror_msg("Read error"); read_total = -1; break; } read_total += read_actual; } RELEASE_CONFIG_BUFFER(buffer); return(read_total); }
size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size) { size_t read_total = 0; while ((size == 0) || (read_total < size)) { size_t read_try; ssize_t read_actual; if ((size == 0) || (size - read_total > BUFSIZ)) { read_try = BUFSIZ; } else { read_try = size - read_total; } read_actual = safe_read(src_fd, buffer, read_try); if (read_actual > 0) { if ((dst_fd >= 0) && (bb_full_write(dst_fd, buffer, (size_t) read_actual) != read_actual)) { printf("bb_msg_write_error"); /* match Read error below */ break; } } else if (read_actual == 0) { if (size) { printf("Unable to read all data"); } break; } else { /* read_actual < 0 */ printf("Read error"); break; } read_total += read_actual; } return (read_total); }
int nc_main(int argc, char **argv) { int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x; #ifdef CONFIG_NC_GAPING_SECURITY_HOLE char *pr00gie = NULL; #endif struct sockaddr_in address; struct hostent *hostinfo; fd_set readfds, testfds; while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) { switch (opt) { case 'l': do_listen++; break; case 'p': lport = bb_lookup_port(optarg, "tcp", 0); break; case 'i': delay = atoi(optarg); break; #ifdef CONFIG_NC_GAPING_SECURITY_HOLE case 'e': pr00gie = optarg; break; #endif case 'w': wsecs = atoi(optarg); break; default: bb_show_usage(); } } if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) bb_show_usage(); sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); x = 1; if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) bb_perror_msg_and_die("reuseaddr"); address.sin_family = AF_INET; if (wsecs) { signal(SIGALRM, timeout); alarm(wsecs); } if (lport != 0) { memset(&address.sin_addr, 0, sizeof(address.sin_addr)); address.sin_port = lport; bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); } if (do_listen) { socklen_t addrlen = sizeof(address); bb_xlisten(sfd, 1); if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) bb_perror_msg_and_die("accept"); close(sfd); sfd = tmpfd; } else { hostinfo = xgethostbyname(argv[optind]); address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) bb_perror_msg_and_die("connect"); } if (wsecs) { alarm(0); signal(SIGALRM, SIG_DFL); } #ifdef CONFIG_NC_GAPING_SECURITY_HOLE /* -e given? */ if (pr00gie) { dup2(sfd, 0); close(sfd); dup2(0, 1); dup2(0, 2); execl(pr00gie, pr00gie, NULL); /* Don't print stuff or it will go over the wire.... */ _exit(-1); } #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */ FD_ZERO(&readfds); FD_SET(sfd, &readfds); FD_SET(STDIN_FILENO, &readfds); while (1) { int fd; int ofd; int nread; testfds = readfds; if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) bb_perror_msg_and_die("select"); for (fd = 0; fd < FD_SETSIZE; fd++) { if (FD_ISSET(fd, &testfds)) { if ((nread = safe_read(fd, bb_common_bufsiz1, sizeof(bb_common_bufsiz1))) < 0) { bb_perror_msg_and_die(bb_msg_read_error); } if (fd == sfd) { if (nread == 0) exit(0); ofd = STDOUT_FILENO; } else { if (nread <= 0) { shutdown(sfd, 1 /* send */ ); close(STDIN_FILENO); FD_CLR(STDIN_FILENO, &readfds); } ofd = sfd; } if (bb_full_write(ofd, bb_common_bufsiz1, nread) < 0) bb_perror_msg_and_die(bb_msg_write_error); if (delay > 0) { sleep(delay); } } } } }
static inline int tftp(const int cmd, const struct hostent *host, const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize) { const int cmd_get = cmd & tftp_cmd_get; const int cmd_put = cmd & tftp_cmd_put; const int bb_tftp_num_retries = 5; struct sockaddr_in sa; struct sockaddr_in from; struct timeval tv; socklen_t fromlen; fd_set rfds; char *cp; unsigned short tmp; int socketfd; int len; int opcode = 0; int finished = 0; int timeout = bb_tftp_num_retries; unsigned short block_nr = 1; #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE int want_option_ack = 0; #endif /* Can't use RESERVE_CONFIG_BUFFER here since the allocation * size varies meaning BUFFERS_GO_ON_STACK would fail */ char *buf=xmalloc(tftp_bufsize + 4); tftp_bufsize += 4; if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { bb_perror_msg("socket"); return EXIT_FAILURE; } len = sizeof(sa); memset(&sa, 0, len); bind(socketfd, (struct sockaddr *)&sa, len); sa.sin_family = host->h_addrtype; sa.sin_port = port; memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, sizeof(sa.sin_addr)); /* build opcode */ if (cmd_get) { opcode = TFTP_RRQ; } if (cmd_put) { opcode = TFTP_WRQ; } while (1) { cp = buf; /* first create the opcode part */ *((unsigned short *) cp) = htons(opcode); cp += 2; /* add filename and mode */ if ((cmd_get && (opcode == TFTP_RRQ)) || (cmd_put && (opcode == TFTP_WRQ))) { int too_long = 0; /* see if the filename fits into buf */ /* and fill in packet */ len = strlen(remotefile) + 1; if ((cp + len) >= &buf[tftp_bufsize - 1]) { too_long = 1; } else { safe_strncpy(cp, remotefile, len); cp += len; } if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) { bb_error_msg("too long remote-filename"); break; } /* add "mode" part of the package */ memcpy(cp, "octet", 6); cp += 6; #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE len = tftp_bufsize - 4; /* data block size */ if (len != TFTP_BLOCKSIZE_DEFAULT) { if ((&buf[tftp_bufsize - 1] - cp) < 15) { bb_error_msg("too long remote-filename"); break; } /* add "blksize" + number of blocks */ memcpy(cp, "blksize", 8); cp += 8; cp += snprintf(cp, 6, "%d", len) + 1; want_option_ack = 1; } #endif } /* add ack and data */ if ((cmd_get && (opcode == TFTP_ACK)) || (cmd_put && (opcode == TFTP_DATA))) { *((unsigned short *) cp) = htons(block_nr); cp += 2; block_nr++; if (cmd_put && (opcode == TFTP_DATA)) { len = bb_full_read(localfd, cp, tftp_bufsize - 4); if (len < 0) { bb_perror_msg("read"); break; } if (len != (tftp_bufsize - 4)) { finished++; } cp += len; } } /* send packet */ timeout = bb_tftp_num_retries; /* re-initialize */ do { len = cp - buf; #ifdef CONFIG_FEATURE_TFTP_DEBUG fprintf(stderr, "sending %u bytes\n", len); for (cp = buf; cp < &buf[len]; cp++) fprintf(stderr, "%02x ", (unsigned char)*cp); fprintf(stderr, "\n"); #endif if (sendto(socketfd, buf, len, 0, (struct sockaddr *) &sa, sizeof(sa)) < 0) { bb_perror_msg("send"); len = -1; break; } if (finished && (opcode == TFTP_ACK)) { break; } /* receive packet */ memset(&from, 0, sizeof(from)); fromlen = sizeof(from); tv.tv_sec = TFTP_TIMEOUT; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(socketfd, &rfds); switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { case 1: len = recvfrom(socketfd, buf, tftp_bufsize, 0, (struct sockaddr *) &from, &fromlen); if (len < 0) { bb_perror_msg("recvfrom"); break; } timeout = 0; if (sa.sin_port == port) { sa.sin_port = from.sin_port; } if (sa.sin_port == from.sin_port) { break; } /* fall-through for bad packets! */ /* discard the packet - treat as timeout */ timeout = bb_tftp_num_retries; case 0: bb_error_msg("timeout"); timeout--; if (timeout == 0) { len = -1; bb_error_msg("last timeout"); } break; default: bb_perror_msg("select"); len = -1; } } while (timeout && (len >= 0)); if ((finished) || (len < 0)) { break; } /* process received packet */ opcode = ntohs(*((unsigned short *) buf)); tmp = ntohs(*((unsigned short *) &buf[2])); #ifdef CONFIG_FEATURE_TFTP_DEBUG fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp); #endif if (opcode == TFTP_ERROR) { const char *msg = NULL; if (buf[4] != '\0') { msg = &buf[4]; buf[tftp_bufsize - 1] = '\0'; } else if (tmp < (sizeof(tftp_bb_error_msg) / sizeof(char *))) { msg = tftp_bb_error_msg[tmp]; } if (msg) { bb_error_msg("server says: %s", msg); } break; } #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE if (want_option_ack) { want_option_ack = 0; if (opcode == TFTP_OACK) { /* server seems to support options */ char *res; res = tftp_option_get(&buf[2], len-2, "blksize"); if (res) { int blksize = atoi(res); if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { if (cmd_put) { opcode = TFTP_DATA; } else { opcode = TFTP_ACK; } #ifdef CONFIG_FEATURE_TFTP_DEBUG fprintf(stderr, "using blksize %u\n", blksize); #endif tftp_bufsize = blksize + 4; block_nr = 0; continue; } } /* FIXME: * we should send ERROR 8 */ bb_error_msg("bad server option"); break; } bb_error_msg("warning: blksize not supported by server" " - reverting to 512"); tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; } #endif if (cmd_get && (opcode == TFTP_DATA)) { if (tmp == block_nr) { len = bb_full_write(localfd, &buf[4], len - 4); if (len < 0) { bb_perror_msg("write"); break; } if (len != (tftp_bufsize - 4)) { finished++; } opcode = TFTP_ACK; continue; } /* in case the last ack disappeared into the ether */ if ( tmp == (block_nr - 1) ) { --block_nr; opcode = TFTP_ACK; continue; } else if (tmp + 1 == block_nr) { /* Server lost our TFTP_ACK. Resend it */ block_nr = tmp; opcode = TFTP_ACK; continue; } } if (cmd_put && (opcode == TFTP_ACK)) { if (tmp == (unsigned short)(block_nr - 1)) { if (finished) { break; } opcode = TFTP_DATA; continue; } } } #ifdef CONFIG_FEATURE_CLEAN_UP close(socketfd); free(buf); #endif return finished ? EXIT_SUCCESS : EXIT_FAILURE; }
/* Write out a tar header for the specified file/directory/whatever */ static inline int writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, const char *real_name, struct stat *statbuf) { long chksum = 0; struct TarHeader header; const unsigned char *cp = (const unsigned char *) &header; ssize_t size = sizeof(struct TarHeader); memset(&header, 0, size); strncpy(header.name, header_name, sizeof(header.name)); putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); strncpy(header.magic, TAR_MAGIC TAR_VERSION, TAR_MAGIC_LEN + TAR_VERSION_LEN); /* Enter the user and group names (default to root if it fails) */ if (my_getpwuid(header.uname, statbuf->st_uid) == NULL) strcpy(header.uname, "root"); if (my_getgrgid(header.gname, statbuf->st_gid) == NULL) strcpy(header.gname, "root"); if (tbInfo->hlInfo) { /* This is a hard link */ header.typeflag = LNKTYPE; strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname)); } else if (S_ISLNK(statbuf->st_mode)) { char *lpath = xreadlink(real_name); if (!lpath) /* Already printed err msg inside xreadlink() */ return (FALSE); header.typeflag = SYMTYPE; strncpy(header.linkname, lpath, sizeof(header.linkname)); free(lpath); } else if (S_ISDIR(statbuf->st_mode)) { header.typeflag = DIRTYPE; strncat(header.name, "/", sizeof(header.name)); } else if (S_ISCHR(statbuf->st_mode)) { header.typeflag = CHRTYPE; putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); } else if (S_ISBLK(statbuf->st_mode)) { header.typeflag = BLKTYPE; putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); } else if (S_ISFIFO(statbuf->st_mode)) { header.typeflag = FIFOTYPE; } else if (S_ISREG(statbuf->st_mode)) { header.typeflag = REGTYPE; putOctal(header.size, sizeof(header.size), statbuf->st_size); } else { bb_error_msg("%s: Unknown file type", real_name); return (FALSE); } /* Calculate and store the checksum (i.e., the sum of all of the bytes of * the header). The checksum field must be filled with blanks for the * calculation. The checksum field is formatted differently from the * other fields: it has [6] digits, a null, then a space -- rather than * digits, followed by a null like the other fields... */ memset(header.chksum, ' ', sizeof(header.chksum)); cp = (const unsigned char *) &header; while (size-- > 0) chksum += *cp++; putOctal(header.chksum, 7, chksum); /* Now write the header out to disk */ if ((size = bb_full_write(tbInfo->tarFd, (char *) &header, sizeof(struct TarHeader))) < 0) { bb_error_msg(bb_msg_io_error, real_name); return (FALSE); } /* Pad the header up to the tar block size */ for (; size < TAR_BLOCK_SIZE; size++) { write(tbInfo->tarFd, "\0", 1); } /* Now do the verbose thing (or not) */ if (tbInfo->verboseFlag) { FILE *vbFd = stdout; if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ vbFd = stderr; fprintf(vbFd, "%s\n", header.name); } return (TRUE); }
int dd_main(int argc, char **argv) { size_t out_full = 0; size_t out_part = 0; size_t in_full = 0; size_t in_part = 0; size_t count = -1; size_t bs = 512; ssize_t n; off_t seek = 0; off_t skip = 0; int sync_flag = FALSE; int noerror = FALSE; int trunc_flag = TRUE; int oflag; int ifd; int ofd; int i; const char *infile = NULL; const char *outfile = NULL; char *buf; for (i = 1; i < argc; i++) { if (strncmp("bs=", argv[i], 3) == 0) bs = bb_xparse_number(argv[i]+3, dd_suffixes); else if (strncmp("count=", argv[i], 6) == 0) count = bb_xparse_number(argv[i]+6, dd_suffixes); else if (strncmp("seek=", argv[i], 5) == 0) seek = bb_xparse_number(argv[i]+5, dd_suffixes); else if (strncmp("skip=", argv[i], 5) == 0) skip = bb_xparse_number(argv[i]+5, dd_suffixes); else if (strncmp("if=", argv[i], 3) == 0) infile = argv[i]+3; else if (strncmp("of=", argv[i], 3) == 0) outfile = argv[i]+3; else if (strncmp("conv=", argv[i], 5) == 0) { buf = argv[i]+5; while (1) { if (strncmp("notrunc", buf, 7) == 0) { trunc_flag = FALSE; buf += 7; } else if (strncmp("sync", buf, 4) == 0) { sync_flag = TRUE; buf += 4; } else if (strncmp("noerror", buf, 7) == 0) { noerror = TRUE; buf += 7; } else { bb_error_msg_and_die("invalid conversion `%s'", argv[i]+5); } if (buf[0] == '\0') break; if (buf[0] == ',') buf++; } } else bb_show_usage(); } buf = xmalloc(bs); if (infile != NULL) { ifd = bb_xopen(infile, O_RDONLY|0x20000000); } else { ifd = STDIN_FILENO; infile = bb_msg_standard_input; } if (outfile != NULL) { oflag = O_WRONLY | O_CREAT; if (!seek && trunc_flag) { oflag |= O_TRUNC; } if ((ofd = open(outfile, oflag|0x20000000, 0666)) < 0) { bb_perror_msg_and_die("%s", outfile); } if (seek && trunc_flag) { if (ftruncate(ofd, seek * bs) < 0) { struct stat st; if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) || S_ISDIR (st.st_mode)) { bb_perror_msg_and_die("%s", outfile); } } } } else { ofd = STDOUT_FILENO; outfile = bb_msg_standard_output; } if (skip) { if (lseek(ifd, skip * bs, SEEK_CUR) < 0) { bb_perror_msg_and_die("%s", infile); } } if (seek) { if (lseek(ofd, seek * bs, SEEK_CUR) < 0) { bb_perror_msg_and_die("%s", outfile); } } while (in_full + in_part != count) { if (noerror) { /* Pre-zero the buffer when doing the noerror thing */ memset(buf, '\0', bs); } n = safe_read(ifd, buf, bs); if (n < 0) { if (noerror) { n = bs; bb_perror_msg("%s", infile); } else { bb_perror_msg_and_die("%s", infile); } } if (n == 0) { break; } if ((size_t)n == bs) { in_full++; } else { in_part++; } if (sync_flag) { memset(buf + n, '\0', bs - n); n = bs; } n = bb_full_write(ofd, buf, n); if (n < 0) { bb_perror_msg_and_die("%s", outfile); } if ((size_t)n == bs) { out_full++; } else { out_part++; } } if (close (ifd) < 0) { bb_perror_msg_and_die("%s", infile); } if (close (ofd) < 0) { bb_perror_msg_and_die("%s", outfile); } fprintf(stderr, "%ld+%ld records in\n%ld+%ld records out\n", (long)in_full, (long)in_part, (long)out_full, (long)out_part); return EXIT_SUCCESS; }