progress.c revision 1.9
11.9Slukem/* $NetBSD: progress.c,v 1.9 2004/04/03 06:19:22 lukem Exp $ */ 21.1Sjhawk 31.1Sjhawk/*- 41.1Sjhawk * Copyright (c) 2003 The NetBSD Foundation, Inc. 51.1Sjhawk * All rights reserved. 61.1Sjhawk * 71.1Sjhawk * This code is derived from software contributed to The NetBSD Foundation 81.1Sjhawk * by John Hawkinson. 91.1Sjhawk * 101.1Sjhawk * Redistribution and use in source and binary forms, with or without 111.1Sjhawk * modification, are permitted provided that the following conditions 121.1Sjhawk * are met: 131.1Sjhawk * 1. Redistributions of source code must retain the above copyright 141.1Sjhawk * notice, this list of conditions and the following disclaimer. 151.1Sjhawk * 2. Redistributions in binary form must reproduce the above copyright 161.1Sjhawk * notice, this list of conditions and the following disclaimer in the 171.1Sjhawk * documentation and/or other materials provided with the distribution. 181.1Sjhawk * 3. Neither the name of The NetBSD Foundation nor the names of its 191.1Sjhawk * contributors may be used to endorse or promote products derived 201.1Sjhawk * from this software without specific prior written permission. 211.1Sjhawk * 221.1Sjhawk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 231.1Sjhawk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 241.1Sjhawk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 251.1Sjhawk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 261.1Sjhawk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 271.1Sjhawk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 281.1Sjhawk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 291.1Sjhawk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 301.1Sjhawk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 311.1Sjhawk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 321.1Sjhawk * POSSIBILITY OF SUCH DAMAGE. 331.1Sjhawk */ 341.1Sjhawk 351.1Sjhawk#include <sys/cdefs.h> 361.1Sjhawk#ifndef lint 371.9Slukem__RCSID("$NetBSD: progress.c,v 1.9 2004/04/03 06:19:22 lukem Exp $"); 381.1Sjhawk#endif /* not lint */ 391.1Sjhawk 401.1Sjhawk#include <sys/types.h> 411.1Sjhawk#include <sys/param.h> 421.1Sjhawk#include <sys/socket.h> 431.1Sjhawk#include <sys/ioctl.h> 441.1Sjhawk#include <sys/time.h> 451.1Sjhawk#include <sys/wait.h> 461.1Sjhawk#include <netinet/in.h> 471.1Sjhawk#include <arpa/ftp.h> 481.1Sjhawk 491.1Sjhawk#include <ctype.h> 501.1Sjhawk#include <err.h> 511.1Sjhawk#include <errno.h> 521.1Sjhawk#include <fcntl.h> 531.1Sjhawk#include <glob.h> 541.1Sjhawk#include <signal.h> 551.1Sjhawk#include <limits.h> 561.1Sjhawk#include <netdb.h> 571.1Sjhawk#include <stdio.h> 581.1Sjhawk#include <stdlib.h> 591.1Sjhawk#include <string.h> 601.1Sjhawk#include <termios.h> 611.1Sjhawk#include <time.h> 621.1Sjhawk#include <tzfile.h> 631.1Sjhawk#include <unistd.h> 641.1Sjhawk 651.1Sjhawk#define GLOBAL /* force GLOBAL decls in progressbar.h to be 661.1Sjhawk * declared */ 671.1Sjhawk#include "progressbar.h" 681.1Sjhawk 691.1Sjhawkstatic void usage(void); 701.1Sjhawkint main(int, char *[]); 711.1Sjhawk 721.1Sjhawkstatic void 731.1Sjhawkusage(void) 741.1Sjhawk{ 751.1Sjhawk fprintf(stderr, 761.8Shubertf "usage: %s [-z] [-f file] [-l length] [-p prefix] cmd [args...]\n", 771.1Sjhawk getprogname()); 781.1Sjhawk exit(1); 791.1Sjhawk} 801.1Sjhawk 811.1Sjhawk 821.1Sjhawkint 831.1Sjhawkmain(int argc, char *argv[]) 841.1Sjhawk{ 851.1Sjhawk static char fb_buf[BUFSIZ]; 861.1Sjhawk char *infile = NULL; 871.7Sross pid_t pid = 0, gzippid = 0; 881.1Sjhawk int ch, fd, outpipe[2], waitstat; 891.1Sjhawk int lflag = 0, zflag = 0; 901.1Sjhawk ssize_t nr, nw, off; 911.1Sjhawk struct stat statb; 921.3Schristos struct ttysize ts; 931.1Sjhawk 941.1Sjhawk setprogname(argv[0]); 951.1Sjhawk 961.1Sjhawk /* defaults: Read from stdin, 0 filesize (no completion estimate) */ 971.1Sjhawk fd = STDIN_FILENO; 981.1Sjhawk filesize = 0; 991.8Shubertf prefix=NULL; 1001.1Sjhawk 1011.8Shubertf while ((ch = getopt(argc, argv, "f:l:p:z")) != -1) 1021.1Sjhawk switch (ch) { 1031.1Sjhawk case 'f': 1041.1Sjhawk infile = optarg; 1051.1Sjhawk break; 1061.1Sjhawk case 'l': 1071.1Sjhawk lflag++; 1081.9Slukem filesize = strsuftoll("input size", optarg, 0, 1091.9Slukem LLONG_MAX); 1101.1Sjhawk break; 1111.8Shubertf case 'p': 1121.8Shubertf prefix = optarg; 1131.8Shubertf break; 1141.1Sjhawk case 'z': 1151.1Sjhawk zflag++; 1161.1Sjhawk break; 1171.1Sjhawk default: 1181.1Sjhawk case '?': 1191.1Sjhawk usage(); 1201.1Sjhawk /* NOTREACHED */ 1211.1Sjhawk } 1221.1Sjhawk argc -= optind; 1231.1Sjhawk argv += optind; 1241.1Sjhawk 1251.1Sjhawk if (argc < 1) 1261.1Sjhawk usage(); 1271.1Sjhawk if (infile && (fd = open(infile, O_RDONLY, 0)) < 0) 1281.1Sjhawk err(1, "%s", infile); 1291.1Sjhawk 1301.1Sjhawk /* stat() to get the filesize unless overridden, or -z */ 1311.1Sjhawk if (!zflag && !lflag && (fstat(fd, &statb) == 0)) 1321.1Sjhawk filesize = statb.st_size; 1331.1Sjhawk 1341.1Sjhawk /* gzip -l the file if we have the name and -z is given */ 1351.1Sjhawk if (zflag && !lflag && infile != NULL) { 1361.1Sjhawk FILE *gzipsizepipe; 1371.1Sjhawk char buf[256], *cmd; 1381.1Sjhawk long size; 1391.1Sjhawk 1401.1Sjhawk /* 1411.1Sjhawk * Read second word of last line of gzip -l output. Looks like: 1421.1Sjhawk * % gzip -l ../etc.tgz 1431.1Sjhawk * compressed uncompressed ratio uncompressed_name 1441.1Sjhawk * 119737 696320 82.8% ../etc.tar 1451.1Sjhawk */ 1461.1Sjhawk 1471.1Sjhawk asprintf(&cmd, "gzip -l %s", infile); 1481.1Sjhawk if ((gzipsizepipe = popen(cmd, "r")) == NULL) 1491.1Sjhawk err(1, "reading compressed file length"); 1501.1Sjhawk for (; fgets(buf, 256, gzipsizepipe) != NULL;) 1511.1Sjhawk continue; 1521.1Sjhawk sscanf(buf, "%*d %ld", &size); 1531.1Sjhawk filesize = size; 1541.1Sjhawk if (pclose(gzipsizepipe) < 0) 1551.1Sjhawk err(1, "closing compressed file length pipe"); 1561.1Sjhawk free(cmd); 1571.1Sjhawk } 1581.1Sjhawk /* Pipe input through gzip -dc if -z is given */ 1591.1Sjhawk if (zflag) { 1601.1Sjhawk int gzippipe[2]; 1611.1Sjhawk 1621.1Sjhawk if (pipe(gzippipe) < 0) 1631.1Sjhawk err(1, "gzip pipe"); 1641.1Sjhawk gzippid = fork(); 1651.1Sjhawk if (gzippid < 0) 1661.1Sjhawk err(1, "fork for gzip"); 1671.1Sjhawk 1681.1Sjhawk if (gzippid) { 1691.1Sjhawk /* parent */ 1701.1Sjhawk dup2(gzippipe[0], fd); 1711.1Sjhawk close(gzippipe[0]); 1721.1Sjhawk close(gzippipe[1]); 1731.1Sjhawk } else { 1741.1Sjhawk dup2(gzippipe[1], STDOUT_FILENO); 1751.1Sjhawk dup2(fd, STDIN_FILENO); 1761.1Sjhawk close(gzippipe[0]); 1771.1Sjhawk close(gzippipe[1]); 1781.1Sjhawk if (execlp("gzip", "gzip", "-dc", NULL)) 1791.1Sjhawk err(1, "exec()ing gzip"); 1801.1Sjhawk } 1811.1Sjhawk } 1821.1Sjhawk 1831.1Sjhawk /* Initialize progressbar.c's global state */ 1841.1Sjhawk bytes = 0; 1851.1Sjhawk progress = 1; 1861.1Sjhawk ttyout = stdout; 1871.3Schristos 1881.3Schristos if (ioctl(fileno(ttyout), TIOCGSIZE, &ts) == -1) { 1891.3Schristos ttywidth = 80; 1901.3Schristos } else 1911.3Schristos ttywidth = ts.ts_cols; 1921.1Sjhawk 1931.1Sjhawk if (pipe(outpipe) < 0) 1941.1Sjhawk err(1, "output pipe"); 1951.1Sjhawk pid = fork(); 1961.1Sjhawk if (pid < 0) 1971.1Sjhawk err(1, "fork for output pipe"); 1981.1Sjhawk 1991.1Sjhawk if (pid == 0) { 2001.1Sjhawk /* child */ 2011.1Sjhawk dup2(outpipe[0], STDIN_FILENO); 2021.1Sjhawk close(outpipe[0]); 2031.1Sjhawk close(outpipe[1]); 2041.1Sjhawk execvp(argv[0], argv); 2051.1Sjhawk err(1, "could not exec %s", argv[0]); 2061.1Sjhawk } 2071.1Sjhawk close(outpipe[0]); 2081.1Sjhawk 2091.1Sjhawk progressmeter(-1); 2101.1Sjhawk while ((nr = read(fd, fb_buf, BUFSIZ)) > 0) 2111.2Senami for (off = 0; nr; nr -= nw, off += nw, bytes += nw) 2121.2Senami if ((nw = write(outpipe[1], fb_buf + off, 2131.2Senami (size_t) nr)) < 0) 2141.5Sagc err(1, "writing %u bytes to output pipe", 2151.5Sagc (unsigned) nr); 2161.1Sjhawk close(outpipe[1]); 2171.1Sjhawk 2181.7Sross while (pid || gzippid) { 2191.7Sross int deadpid; 2201.7Sross 2211.7Sross deadpid = wait(&waitstat); 2221.7Sross 2231.7Sross if (deadpid == pid) 2241.7Sross pid = 0; 2251.7Sross else if (deadpid == gzippid) 2261.7Sross gzippid = 0; 2271.7Sross else if (deadpid != -1) 2281.7Sross continue; 2291.7Sross else if (errno == EINTR) 2301.7Sross continue; 2311.7Sross else break; 2321.7Sross } 2331.1Sjhawk 2341.1Sjhawk progressmeter(1); 2351.1Sjhawk return 0; 2361.1Sjhawk} 237