1274116Sdteske/*- 2295110Sdteske * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org> 3274116Sdteske * All rights reserved. 4274116Sdteske * 5274116Sdteske * Redistribution and use in source and binary forms, with or without 6274116Sdteske * modification, are permitted provided that the following conditions 7274116Sdteske * are met: 8274116Sdteske * 1. Redistributions of source code must retain the above copyright 9274116Sdteske * notice, this list of conditions and the following disclaimer. 10274116Sdteske * 2. Redistributions in binary form must reproduce the above copyright 11274116Sdteske * notice, this list of conditions and the following disclaimer in the 12274116Sdteske * documentation and/or other materials provided with the distribution. 13274116Sdteske * 14274116Sdteske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15274116Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16274116Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17274116Sdteske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18274116Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19274116Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20274116Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21274116Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22274116Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23274116Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24274116Sdteske * SUCH DAMAGE. 25274116Sdteske */ 26274116Sdteske 27274116Sdteske#include <sys/cdefs.h> 28274116Sdteske__FBSDID("$FreeBSD$"); 29274116Sdteske 30274116Sdteske#include <sys/stat.h> 31274116Sdteske#include <sys/types.h> 32274116Sdteske 33274116Sdteske#define _BSD_SOURCE /* to get dprintf() prototype in stdio.h below */ 34274116Sdteske#include <dialog.h> 35274116Sdteske#include <dpv.h> 36274116Sdteske#include <err.h> 37274116Sdteske#include <errno.h> 38274116Sdteske#include <fcntl.h> 39274116Sdteske#include <limits.h> 40274116Sdteske#include <signal.h> 41274116Sdteske#include <stdio.h> 42274116Sdteske#include <stdlib.h> 43274116Sdteske#include <string.h> 44274116Sdteske#include <string_m.h> 45274116Sdteske#include <unistd.h> 46274116Sdteske 47274116Sdteske#include "dpv_util.h" 48274116Sdteske 49274116Sdteske/* Debugging */ 50274116Sdteskestatic uint8_t debug = FALSE; 51274116Sdteske 52274116Sdteske/* Data to process */ 53274116Sdteskestatic struct dpv_file_node *file_list = NULL; 54274116Sdteskestatic unsigned int nfiles = 0; 55274116Sdteske 56274116Sdteske/* Data processing */ 57274116Sdteskestatic uint8_t line_mode = FALSE; 58274116Sdteskestatic uint8_t no_overrun = FALSE; 59274116Sdteskestatic char *buf = NULL; 60274116Sdteskestatic int fd = -1; 61274116Sdteskestatic int output_type = DPV_OUTPUT_NONE; 62274116Sdteskestatic size_t bsize; 63274116Sdteskestatic char rpath[PATH_MAX]; 64274116Sdteske 65274116Sdteske/* Extra display information */ 66274116Sdteskestatic uint8_t multiple = FALSE; /* `-m' */ 67274116Sdteskestatic char *pgm; /* set to argv[0] by main() */ 68274116Sdteske 69274116Sdteske/* Function prototypes */ 70274116Sdteskestatic void sig_int(int sig); 71274116Sdteskestatic void usage(void); 72274116Sdteskeint main(int argc, char *argv[]); 73274116Sdteskestatic int operate_common(struct dpv_file_node *file, int out); 74274116Sdteskestatic int operate_on_bytes(struct dpv_file_node *file, int out); 75274116Sdteskestatic int operate_on_lines(struct dpv_file_node *file, int out); 76274116Sdteske 77274116Sdteskestatic int 78274116Sdteskeoperate_common(struct dpv_file_node *file, int out) 79274116Sdteske{ 80274116Sdteske struct stat sb; 81274116Sdteske 82274116Sdteske /* Open the file if necessary */ 83274116Sdteske if (fd < 0) { 84274116Sdteske if (multiple) { 85274116Sdteske /* Resolve the file path and attempt to open it */ 86274116Sdteske if (realpath(file->path, rpath) == 0 || 87274116Sdteske (fd = open(rpath, O_RDONLY)) < 0) { 88274116Sdteske warn("%s", file->path); 89274116Sdteske file->status = DPV_STATUS_FAILED; 90274116Sdteske return (-1); 91274116Sdteske } 92274116Sdteske } else { 93274116Sdteske /* Assume stdin, but if that's a TTY instead use the 94274116Sdteske * highest numbered file descriptor (obtained by 95274116Sdteske * generating new fd and then decrementing). 96274116Sdteske * 97274116Sdteske * NB: /dev/stdin should always be open(2)'able 98274116Sdteske */ 99274116Sdteske fd = STDIN_FILENO; 100274116Sdteske if (isatty(fd)) { 101274116Sdteske fd = open("/dev/stdin", O_RDONLY); 102274116Sdteske close(fd--); 103274116Sdteske } 104274116Sdteske 105274116Sdteske /* This answer might be wrong, if dpv(3) has (by 106274116Sdteske * request) opened an output file or pipe. If we 107274116Sdteske * told dpv(3) to open a file, subtract one from 108274116Sdteske * previous answer. If instead we told dpv(3) to 109274116Sdteske * prepare a pipe output, subtract two. 110274116Sdteske */ 111274116Sdteske switch(output_type) { 112274116Sdteske case DPV_OUTPUT_FILE: 113274116Sdteske fd -= 1; 114274116Sdteske break; 115274116Sdteske case DPV_OUTPUT_SHELL: 116274116Sdteske fd -= 2; 117274116Sdteske break; 118274116Sdteske } 119274116Sdteske } 120274116Sdteske } 121274116Sdteske 122274116Sdteske /* Allocate buffer if necessary */ 123274116Sdteske if (buf == NULL) { 124274116Sdteske /* Use output block size as buffer size if available */ 125274116Sdteske if (out >= 0) { 126274116Sdteske if (fstat(out, &sb) != 0) { 127274116Sdteske warn("%i", out); 128274116Sdteske file->status = DPV_STATUS_FAILED; 129274116Sdteske return (-1); 130274116Sdteske } 131274116Sdteske if (S_ISREG(sb.st_mode)) { 132274116Sdteske if (sysconf(_SC_PHYS_PAGES) > 133274116Sdteske PHYSPAGES_THRESHOLD) 134274116Sdteske bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 135274116Sdteske else 136274116Sdteske bsize = BUFSIZE_SMALL; 137274116Sdteske } else 138274116Sdteske bsize = MAX(sb.st_blksize, 139274116Sdteske (blksize_t)sysconf(_SC_PAGESIZE)); 140274116Sdteske } else 141274116Sdteske bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 142274116Sdteske 143274116Sdteske /* Attempt to allocate */ 144274116Sdteske if ((buf = malloc(bsize+1)) == NULL) { 145274116Sdteske end_dialog(); 146274116Sdteske err(EXIT_FAILURE, "Out of memory?!"); 147274116Sdteske } 148274116Sdteske } 149274116Sdteske 150274116Sdteske return (0); 151274116Sdteske} 152274116Sdteske 153274116Sdteskestatic int 154274116Sdteskeoperate_on_bytes(struct dpv_file_node *file, int out) 155274116Sdteske{ 156274116Sdteske int progress; 157274116Sdteske ssize_t r, w; 158274116Sdteske 159274116Sdteske if (operate_common(file, out) < 0) 160274116Sdteske return (-1); 161274116Sdteske 162274116Sdteske /* [Re-]Fill the buffer */ 163274116Sdteske if ((r = read(fd, buf, bsize)) <= 0) { 164274116Sdteske if (fd != STDIN_FILENO) 165274116Sdteske close(fd); 166274116Sdteske fd = -1; 167274116Sdteske file->status = DPV_STATUS_DONE; 168274116Sdteske return (100); 169274116Sdteske } 170274116Sdteske 171274116Sdteske /* [Re-]Dump the buffer */ 172274116Sdteske if (out >= 0) { 173274116Sdteske if ((w = write(out, buf, r)) < 0) { 174274116Sdteske end_dialog(); 175274116Sdteske err(EXIT_FAILURE, "output"); 176274116Sdteske } 177274116Sdteske fsync(out); 178274116Sdteske } 179274116Sdteske 180275040Sdteske dpv_overall_read += r; 181274116Sdteske file->read += r; 182274116Sdteske 183274116Sdteske /* Calculate percentage of completion (if possible) */ 184274116Sdteske if (file->length >= 0) { 185274116Sdteske progress = (file->read * 100 / (file->length > 0 ? 186274116Sdteske file->length : 1)); 187274116Sdteske 188274116Sdteske /* If no_overrun, do not return 100% until read >= length */ 189274116Sdteske if (no_overrun && progress == 100 && file->read < file->length) 190274116Sdteske progress--; 191274116Sdteske 192274116Sdteske return (progress); 193274116Sdteske } else 194274116Sdteske return (-1); 195274116Sdteske} 196274116Sdteske 197274116Sdteskestatic int 198274116Sdteskeoperate_on_lines(struct dpv_file_node *file, int out) 199274116Sdteske{ 200274116Sdteske char *p; 201274116Sdteske int progress; 202274116Sdteske ssize_t r, w; 203274116Sdteske 204274116Sdteske if (operate_common(file, out) < 0) 205274116Sdteske return (-1); 206274116Sdteske 207274116Sdteske /* [Re-]Fill the buffer */ 208274116Sdteske if ((r = read(fd, buf, bsize)) <= 0) { 209274116Sdteske if (fd != STDIN_FILENO) 210274116Sdteske close(fd); 211274116Sdteske fd = -1; 212274116Sdteske file->status = DPV_STATUS_DONE; 213274116Sdteske return (100); 214274116Sdteske } 215274116Sdteske buf[r] = '\0'; 216274116Sdteske 217274116Sdteske /* [Re-]Dump the buffer */ 218274116Sdteske if (out >= 0) { 219274116Sdteske if ((w = write(out, buf, r)) < 0) { 220274116Sdteske end_dialog(); 221274116Sdteske err(EXIT_FAILURE, "output"); 222274116Sdteske } 223274116Sdteske fsync(out); 224274116Sdteske } 225274116Sdteske 226274116Sdteske /* Process the buffer for number of lines */ 227274116Sdteske for (p = buf; p != NULL && *p != '\0';) 228274116Sdteske if ((p = strchr(p, '\n')) != NULL) 229275040Sdteske dpv_overall_read++, p++, file->read++; 230274116Sdteske 231274116Sdteske /* Calculate percentage of completion (if possible) */ 232274116Sdteske if (file->length >= 0) { 233274116Sdteske progress = (file->read * 100 / file->length); 234274116Sdteske 235274116Sdteske /* If no_overrun, do not return 100% until read >= length */ 236274116Sdteske if (no_overrun && progress == 100 && file->read < file->length) 237274116Sdteske progress--; 238274116Sdteske 239274116Sdteske return (progress); 240274116Sdteske } else 241274116Sdteske return (-1); 242274116Sdteske} 243274116Sdteske 244274116Sdteske/* 245274116Sdteske * Takes a list of names that are to correspond to input streams coming from 246274116Sdteske * stdin or fifos and produces necessary config to drive dpv(3) `--gauge' 247274116Sdteske * widget. If the `-d' flag is used, output is instead send to terminal 248274116Sdteske * standard output (and the output can then be saved to a file, piped into 249274116Sdteske * custom [X]dialog(1) invocation, or whatever. 250274116Sdteske */ 251274116Sdteskeint 252274116Sdteskemain(int argc, char *argv[]) 253274116Sdteske{ 254274116Sdteske char dummy; 255274116Sdteske int ch; 256274116Sdteske int n = 0; 257274116Sdteske size_t config_size = sizeof(struct dpv_config); 258274116Sdteske size_t file_node_size = sizeof(struct dpv_file_node); 259274116Sdteske struct dpv_config *config; 260274116Sdteske struct dpv_file_node *curfile; 261274116Sdteske struct sigaction act; 262274116Sdteske 263274116Sdteske pgm = argv[0]; /* store a copy of invocation name */ 264274116Sdteske 265274116Sdteske /* Allocate config structure */ 266274116Sdteske if ((config = malloc(config_size)) == NULL) 267274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 268274116Sdteske memset((void *)(config), '\0', config_size); 269274116Sdteske 270274116Sdteske /* 271274116Sdteske * Process command-line options 272274116Sdteske */ 273274116Sdteske while ((ch = getopt(argc, argv, 274295110Sdteske "a:b:dDhi:I:klL:mn:No:p:P:t:TU:wx:X")) != -1) { 275274116Sdteske switch(ch) { 276274116Sdteske case 'a': /* additional message text to append */ 277274116Sdteske if (config->aprompt == NULL) { 278274116Sdteske config->aprompt = malloc(DPV_APROMPT_MAX); 279274116Sdteske if (config->aprompt == NULL) 280274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 281274116Sdteske } 282274116Sdteske snprintf(config->aprompt, DPV_APROMPT_MAX, "%s", 283274116Sdteske optarg); 284274116Sdteske break; 285274116Sdteske case 'b': /* [X]dialog(1) backtitle */ 286274116Sdteske if (config->backtitle != NULL) 287274116Sdteske free((char *)config->backtitle); 288274116Sdteske config->backtitle = malloc(strlen(optarg) + 1); 289274116Sdteske if (config->backtitle == NULL) 290274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 291274116Sdteske *(config->backtitle) = '\0'; 292274116Sdteske strcat(config->backtitle, optarg); 293274116Sdteske break; 294274116Sdteske case 'd': /* debugging */ 295274116Sdteske debug = TRUE; 296274116Sdteske config->debug = debug; 297274116Sdteske break; 298274116Sdteske case 'D': /* use dialog(1) instead of libdialog */ 299274116Sdteske config->display_type = DPV_DISPLAY_DIALOG; 300274116Sdteske break; 301274116Sdteske case 'h': /* help/usage */ 302274116Sdteske usage(); 303274116Sdteske break; /* NOTREACHED */ 304274116Sdteske case 'i': /* status line format string for single-file */ 305274116Sdteske config->status_solo = optarg; 306274116Sdteske break; 307274116Sdteske case 'I': /* status line format string for many-files */ 308274116Sdteske config->status_many = optarg; 309274116Sdteske break; 310295110Sdteske case 'k': /* keep tite */ 311295110Sdteske config->keep_tite = TRUE; 312295110Sdteske break; 313274116Sdteske case 'l': /* Line mode */ 314274116Sdteske line_mode = TRUE; 315274116Sdteske break; 316274116Sdteske case 'L': /* custom label size */ 317274116Sdteske config->label_size = 318274116Sdteske (int)strtol(optarg, (char **)NULL, 10); 319274116Sdteske if (config->label_size == 0 && errno == EINVAL) 320274116Sdteske errx(EXIT_FAILURE, 321274116Sdteske "`-L' argument must be numeric"); 322274116Sdteske else if (config->label_size < -1) 323274116Sdteske config->label_size = -1; 324274116Sdteske break; 325274116Sdteske case 'm': /* enable multiple file arguments */ 326274116Sdteske multiple = TRUE; 327274116Sdteske break; 328274116Sdteske case 'o': /* `-o path' for sending data-read to file */ 329274116Sdteske output_type = DPV_OUTPUT_FILE; 330274116Sdteske config->output_type = DPV_OUTPUT_FILE; 331274116Sdteske config->output = optarg; 332274116Sdteske break; 333274116Sdteske case 'n': /* custom number of files per `page' */ 334274116Sdteske config->display_limit = 335274116Sdteske (int)strtol(optarg, (char **)NULL, 10); 336274116Sdteske if (config->display_limit == 0 && errno == EINVAL) 337274116Sdteske errx(EXIT_FAILURE, 338274116Sdteske "`-n' argument must be numeric"); 339274116Sdteske else if (config->display_limit < 0) 340274116Sdteske config->display_limit = -1; 341274116Sdteske break; 342274116Sdteske case 'N': /* No overrun (truncate reads of known-length) */ 343274116Sdteske no_overrun = TRUE; 344274116Sdteske config->options |= DPV_NO_OVERRUN; 345274116Sdteske break; 346274116Sdteske case 'p': /* additional message text to use as prefix */ 347274116Sdteske if (config->pprompt == NULL) { 348274116Sdteske config->pprompt = malloc(DPV_PPROMPT_MAX + 2); 349274116Sdteske if (config->pprompt == NULL) 350274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 351274116Sdteske /* +2 is for implicit "\n" appended later */ 352274116Sdteske } 353274116Sdteske snprintf(config->pprompt, DPV_PPROMPT_MAX, "%s", 354274116Sdteske optarg); 355274116Sdteske break; 356274116Sdteske case 'P': /* custom size for mini-progressbar */ 357274116Sdteske config->pbar_size = 358274116Sdteske (int)strtol(optarg, (char **)NULL, 10); 359274116Sdteske if (config->pbar_size == 0 && errno == EINVAL) 360274116Sdteske errx(EXIT_FAILURE, 361274116Sdteske "`-P' argument must be numeric"); 362274116Sdteske else if (config->pbar_size < -1) 363274116Sdteske config->pbar_size = -1; 364274116Sdteske break; 365274116Sdteske case 't': /* [X]dialog(1) title */ 366274116Sdteske if (config->title != NULL) 367274116Sdteske free(config->title); 368274116Sdteske config->title = malloc(strlen(optarg) + 1); 369274116Sdteske if (config->title == NULL) 370274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 371274116Sdteske *(config->title) = '\0'; 372274116Sdteske strcat(config->title, optarg); 373274116Sdteske break; 374274116Sdteske case 'T': /* test mode (don't read data, fake it) */ 375274116Sdteske config->options |= DPV_TEST_MODE; 376274116Sdteske break; 377274116Sdteske case 'U': /* updates per second */ 378274116Sdteske config->status_updates_per_second = 379274116Sdteske (int)strtol(optarg, (char **)NULL, 10); 380274116Sdteske if (config->status_updates_per_second == 0 && 381274116Sdteske errno == EINVAL) 382274116Sdteske errx(EXIT_FAILURE, 383274116Sdteske "`-U' argument must be numeric"); 384274116Sdteske break; 385274116Sdteske case 'w': /* `-p' and `-a' widths bump [X]dialog(1) width */ 386274116Sdteske config->options |= DPV_WIDE_MODE; 387274116Sdteske break; 388274116Sdteske case 'x': /* `-x cmd' for sending data-read to sh(1) code */ 389274116Sdteske output_type = DPV_OUTPUT_SHELL; 390274116Sdteske config->output_type = DPV_OUTPUT_SHELL; 391274116Sdteske config->output = optarg; 392274116Sdteske break; 393274116Sdteske case 'X': /* X11 support through x11/xdialog */ 394274116Sdteske config->display_type = DPV_DISPLAY_XDIALOG; 395274116Sdteske break; 396274116Sdteske case '?': /* unknown argument (based on optstring) */ 397274116Sdteske /* FALLTHROUGH */ 398274116Sdteske default: /* unhandled argument (based on switch) */ 399274116Sdteske usage(); 400274116Sdteske /* NOTREACHED */ 401274116Sdteske } 402274116Sdteske } 403274116Sdteske argc -= optind; 404274116Sdteske argv += optind; 405274116Sdteske 406274116Sdteske /* Process remaining arguments as list of names to display */ 407274116Sdteske for (curfile = file_list; n < argc; n++) { 408274116Sdteske nfiles++; 409274116Sdteske 410274116Sdteske /* Allocate a new struct for the file argument */ 411274116Sdteske if (curfile == NULL) { 412274116Sdteske if ((curfile = malloc(file_node_size)) == NULL) 413274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 414274116Sdteske memset((void *)(curfile), '\0', file_node_size); 415274116Sdteske file_list = curfile; 416274116Sdteske } else { 417274116Sdteske if ((curfile->next = malloc(file_node_size)) == NULL) 418274116Sdteske errx(EXIT_FAILURE, "Out of memory?!"); 419274116Sdteske memset((void *)(curfile->next), '\0', file_node_size); 420274116Sdteske curfile = curfile->next; 421274116Sdteske } 422274116Sdteske curfile->name = argv[n]; 423274116Sdteske 424274116Sdteske /* Read possible `lines:' prefix from label syntax */ 425274116Sdteske if (sscanf(curfile->name, "%lli:%c", &(curfile->length), 426274116Sdteske &dummy) == 2) 427274116Sdteske curfile->name = strchr(curfile->name, ':') + 1; 428274116Sdteske else 429274116Sdteske curfile->length = -1; 430274116Sdteske 431274116Sdteske /* Read path argument if enabled */ 432274116Sdteske if (multiple) { 433274116Sdteske if (++n >= argc) 434274116Sdteske errx(EXIT_FAILURE, "Missing path argument " 435274116Sdteske "for label number %i", nfiles); 436274116Sdteske curfile->path = argv[n]; 437274116Sdteske } else 438274116Sdteske break; 439274116Sdteske } 440274116Sdteske 441274116Sdteske /* Display usage and exit if not given at least one name */ 442274116Sdteske if (nfiles == 0) { 443274116Sdteske warnx("no labels provided"); 444274116Sdteske usage(); 445274116Sdteske /* NOTREACHED */ 446274116Sdteske } 447274116Sdteske 448274116Sdteske /* 449274116Sdteske * Set cleanup routine for Ctrl-C action 450274116Sdteske */ 451274116Sdteske if (config->display_type == DPV_DISPLAY_LIBDIALOG) { 452274116Sdteske act.sa_handler = sig_int; 453274116Sdteske sigaction(SIGINT, &act, 0); 454274116Sdteske } 455274116Sdteske 456274116Sdteske /* Set status formats and action */ 457274116Sdteske if (line_mode) { 458274116Sdteske config->status_solo = LINE_STATUS_SOLO; 459274116Sdteske config->status_many = LINE_STATUS_SOLO; 460274116Sdteske config->action = operate_on_lines; 461274116Sdteske } else { 462274116Sdteske config->status_solo = BYTE_STATUS_SOLO; 463274116Sdteske config->status_many = BYTE_STATUS_SOLO; 464274116Sdteske config->action = operate_on_bytes; 465274116Sdteske } 466274116Sdteske 467274116Sdteske /* 468274116Sdteske * Hand off to dpv(3)... 469274116Sdteske */ 470274116Sdteske if (dpv(config, file_list) != 0 && debug) 471274116Sdteske warnx("dpv(3) returned error!?"); 472274116Sdteske 473295110Sdteske if (!config->keep_tite) 474295110Sdteske end_dialog(); 475274116Sdteske dpv_free(); 476274116Sdteske 477274116Sdteske exit(EXIT_SUCCESS); 478274116Sdteske} 479274116Sdteske 480274116Sdteske/* 481274116Sdteske * Interrupt handler to indicate we received a Ctrl-C interrupt. 482274116Sdteske */ 483274116Sdteskestatic void 484274116Sdteskesig_int(int sig __unused) 485274116Sdteske{ 486274116Sdteske dpv_interrupt = TRUE; 487274116Sdteske} 488274116Sdteske 489274116Sdteske/* 490274116Sdteske * Print short usage statement to stderr and exit with error status. 491274116Sdteske */ 492274116Sdteskestatic void 493274116Sdteskeusage(void) 494274116Sdteske{ 495274116Sdteske 496274116Sdteske if (debug) /* No need for usage */ 497274116Sdteske exit(EXIT_FAILURE); 498274116Sdteske 499274116Sdteske fprintf(stderr, "Usage: %s [options] bytes:label\n", pgm); 500274116Sdteske fprintf(stderr, " %s [options] -m bytes1:label1 path1 " 501274116Sdteske "[bytes2:label2 path2 ...]\n", pgm); 502274116Sdteske fprintf(stderr, "OPTIONS:\n"); 503274116Sdteske#define OPTFMT "\t%-14s %s\n" 504274116Sdteske fprintf(stderr, OPTFMT, "-a text", 505274116Sdteske "Append text. Displayed below file progress indicators."); 506274116Sdteske fprintf(stderr, OPTFMT, "-b backtitle", 507274116Sdteske "String to be displayed on the backdrop, at top-left."); 508274116Sdteske fprintf(stderr, OPTFMT, "-d", 509274116Sdteske "Debug. Write to standard output instead of dialog."); 510274116Sdteske fprintf(stderr, OPTFMT, "-D", 511274116Sdteske "Use dialog(1) instead of dialog(3) [default]."); 512274116Sdteske fprintf(stderr, OPTFMT, "-h", 513274116Sdteske "Produce this output on standard error and exit."); 514274116Sdteske fprintf(stderr, OPTFMT, "-i format", 515274116Sdteske "Customize status line format. See fdpv(1) for details."); 516274116Sdteske fprintf(stderr, OPTFMT, "-I format", 517274116Sdteske "Customize status line format. See fdpv(1) for details."); 518274116Sdteske fprintf(stderr, OPTFMT, "-L size", 519274116Sdteske "Label size. Must be a number greater than 0, or -1."); 520274116Sdteske fprintf(stderr, OPTFMT, "-m", 521274116Sdteske "Enable processing of multiple file argiments."); 522274116Sdteske fprintf(stderr, OPTFMT, "-n num", 523274116Sdteske "Display at-most num files per screen. Default is -1."); 524274116Sdteske fprintf(stderr, OPTFMT, "-N", 525274116Sdteske "No overrun. Stop reading input at stated length, if any."); 526274116Sdteske fprintf(stderr, OPTFMT, "-o file", 527274116Sdteske "Output data to file. First %s replaced with label text."); 528274116Sdteske fprintf(stderr, OPTFMT, "-p text", 529274116Sdteske "Prefix text. Displayed above file progress indicators."); 530274116Sdteske fprintf(stderr, OPTFMT, "-P size", 531274116Sdteske "Mini-progressbar size. Must be a number greater than 3."); 532274116Sdteske fprintf(stderr, OPTFMT, "-t title", 533274116Sdteske "Title string to be displayed at top of dialog(1) box."); 534274116Sdteske fprintf(stderr, OPTFMT, "-T", 535274116Sdteske "Test mode. Don't actually read any data, but fake it."); 536274116Sdteske fprintf(stderr, OPTFMT, "-U num", 537274116Sdteske "Update status line num times per-second. Default is 2."); 538274116Sdteske fprintf(stderr, OPTFMT, "-w", 539274116Sdteske "Wide. Width of `-p' and `-a' text bump dialog(1) width."); 540274116Sdteske fprintf(stderr, OPTFMT, "-x cmd", 541274116Sdteske "Send data to executed cmd. First %s replaced with label."); 542274116Sdteske fprintf(stderr, OPTFMT, "-X", 543274116Sdteske "X11. Use Xdialog(1) instead of dialog(1)."); 544274116Sdteske exit(EXIT_FAILURE); 545274116Sdteske} 546