1041394f3SDevin Teske /*- 2*21838a13SDevin Teske * Copyright (c) 2013-2016 Devin Teske <dteske@FreeBSD.org> 3041394f3SDevin Teske * All rights reserved. 4041394f3SDevin Teske * 5041394f3SDevin Teske * Redistribution and use in source and binary forms, with or without 6041394f3SDevin Teske * modification, are permitted provided that the following conditions 7041394f3SDevin Teske * are met: 8041394f3SDevin Teske * 1. Redistributions of source code must retain the above copyright 9041394f3SDevin Teske * notice, this list of conditions and the following disclaimer. 10041394f3SDevin Teske * 2. Redistributions in binary form must reproduce the above copyright 11041394f3SDevin Teske * notice, this list of conditions and the following disclaimer in the 12041394f3SDevin Teske * documentation and/or other materials provided with the distribution. 13041394f3SDevin Teske * 14041394f3SDevin Teske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15041394f3SDevin Teske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16041394f3SDevin Teske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17041394f3SDevin Teske * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18041394f3SDevin Teske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19041394f3SDevin Teske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20041394f3SDevin Teske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21041394f3SDevin Teske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22041394f3SDevin Teske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23041394f3SDevin Teske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24041394f3SDevin Teske * SUCH DAMAGE. 25041394f3SDevin Teske */ 26041394f3SDevin Teske 27041394f3SDevin Teske #include <sys/cdefs.h> 28041394f3SDevin Teske __FBSDID("$FreeBSD$"); 29041394f3SDevin Teske 30041394f3SDevin Teske #include <sys/stat.h> 31041394f3SDevin Teske #include <sys/types.h> 32041394f3SDevin Teske 33041394f3SDevin Teske #define _BSD_SOURCE /* to get dprintf() prototype in stdio.h below */ 34041394f3SDevin Teske #include <dialog.h> 35041394f3SDevin Teske #include <dpv.h> 36041394f3SDevin Teske #include <err.h> 37041394f3SDevin Teske #include <errno.h> 38041394f3SDevin Teske #include <fcntl.h> 39041394f3SDevin Teske #include <limits.h> 40041394f3SDevin Teske #include <signal.h> 41041394f3SDevin Teske #include <stdio.h> 42041394f3SDevin Teske #include <stdlib.h> 43041394f3SDevin Teske #include <string.h> 44041394f3SDevin Teske #include <string_m.h> 45041394f3SDevin Teske #include <unistd.h> 46041394f3SDevin Teske 47041394f3SDevin Teske #include "dpv_util.h" 48041394f3SDevin Teske 49041394f3SDevin Teske /* Debugging */ 50041394f3SDevin Teske static uint8_t debug = FALSE; 51041394f3SDevin Teske 52041394f3SDevin Teske /* Data to process */ 53041394f3SDevin Teske static struct dpv_file_node *file_list = NULL; 54041394f3SDevin Teske static unsigned int nfiles = 0; 55041394f3SDevin Teske 56041394f3SDevin Teske /* Data processing */ 57041394f3SDevin Teske static uint8_t line_mode = FALSE; 58041394f3SDevin Teske static uint8_t no_overrun = FALSE; 59041394f3SDevin Teske static char *buf = NULL; 60041394f3SDevin Teske static int fd = -1; 61041394f3SDevin Teske static int output_type = DPV_OUTPUT_NONE; 62041394f3SDevin Teske static size_t bsize; 63041394f3SDevin Teske static char rpath[PATH_MAX]; 64041394f3SDevin Teske 65041394f3SDevin Teske /* Extra display information */ 66041394f3SDevin Teske static uint8_t multiple = FALSE; /* `-m' */ 67041394f3SDevin Teske static char *pgm; /* set to argv[0] by main() */ 68041394f3SDevin Teske 69041394f3SDevin Teske /* Function prototypes */ 70041394f3SDevin Teske static void sig_int(int sig); 71041394f3SDevin Teske static void usage(void); 72041394f3SDevin Teske int main(int argc, char *argv[]); 73041394f3SDevin Teske static int operate_common(struct dpv_file_node *file, int out); 74041394f3SDevin Teske static int operate_on_bytes(struct dpv_file_node *file, int out); 75041394f3SDevin Teske static int operate_on_lines(struct dpv_file_node *file, int out); 76041394f3SDevin Teske 77041394f3SDevin Teske static int 78041394f3SDevin Teske operate_common(struct dpv_file_node *file, int out) 79041394f3SDevin Teske { 80041394f3SDevin Teske struct stat sb; 81041394f3SDevin Teske 82041394f3SDevin Teske /* Open the file if necessary */ 83041394f3SDevin Teske if (fd < 0) { 84041394f3SDevin Teske if (multiple) { 85041394f3SDevin Teske /* Resolve the file path and attempt to open it */ 86041394f3SDevin Teske if (realpath(file->path, rpath) == 0 || 87041394f3SDevin Teske (fd = open(rpath, O_RDONLY)) < 0) { 88041394f3SDevin Teske warn("%s", file->path); 89041394f3SDevin Teske file->status = DPV_STATUS_FAILED; 90041394f3SDevin Teske return (-1); 91041394f3SDevin Teske } 92041394f3SDevin Teske } else { 93041394f3SDevin Teske /* Assume stdin, but if that's a TTY instead use the 94041394f3SDevin Teske * highest numbered file descriptor (obtained by 95041394f3SDevin Teske * generating new fd and then decrementing). 96041394f3SDevin Teske * 97041394f3SDevin Teske * NB: /dev/stdin should always be open(2)'able 98041394f3SDevin Teske */ 99041394f3SDevin Teske fd = STDIN_FILENO; 100041394f3SDevin Teske if (isatty(fd)) { 101041394f3SDevin Teske fd = open("/dev/stdin", O_RDONLY); 102041394f3SDevin Teske close(fd--); 103041394f3SDevin Teske } 104041394f3SDevin Teske 105041394f3SDevin Teske /* This answer might be wrong, if dpv(3) has (by 106041394f3SDevin Teske * request) opened an output file or pipe. If we 107041394f3SDevin Teske * told dpv(3) to open a file, subtract one from 108041394f3SDevin Teske * previous answer. If instead we told dpv(3) to 109041394f3SDevin Teske * prepare a pipe output, subtract two. 110041394f3SDevin Teske */ 111041394f3SDevin Teske switch(output_type) { 112041394f3SDevin Teske case DPV_OUTPUT_FILE: 113041394f3SDevin Teske fd -= 1; 114041394f3SDevin Teske break; 115041394f3SDevin Teske case DPV_OUTPUT_SHELL: 116041394f3SDevin Teske fd -= 2; 117041394f3SDevin Teske break; 118041394f3SDevin Teske } 119041394f3SDevin Teske } 120041394f3SDevin Teske } 121041394f3SDevin Teske 122041394f3SDevin Teske /* Allocate buffer if necessary */ 123041394f3SDevin Teske if (buf == NULL) { 124041394f3SDevin Teske /* Use output block size as buffer size if available */ 125041394f3SDevin Teske if (out >= 0) { 126041394f3SDevin Teske if (fstat(out, &sb) != 0) { 127041394f3SDevin Teske warn("%i", out); 128041394f3SDevin Teske file->status = DPV_STATUS_FAILED; 129041394f3SDevin Teske return (-1); 130041394f3SDevin Teske } 131041394f3SDevin Teske if (S_ISREG(sb.st_mode)) { 132041394f3SDevin Teske if (sysconf(_SC_PHYS_PAGES) > 133041394f3SDevin Teske PHYSPAGES_THRESHOLD) 134041394f3SDevin Teske bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 135041394f3SDevin Teske else 136041394f3SDevin Teske bsize = BUFSIZE_SMALL; 137041394f3SDevin Teske } else 138041394f3SDevin Teske bsize = MAX(sb.st_blksize, 139041394f3SDevin Teske (blksize_t)sysconf(_SC_PAGESIZE)); 140041394f3SDevin Teske } else 141041394f3SDevin Teske bsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 142041394f3SDevin Teske 143041394f3SDevin Teske /* Attempt to allocate */ 144041394f3SDevin Teske if ((buf = malloc(bsize+1)) == NULL) { 145041394f3SDevin Teske end_dialog(); 146041394f3SDevin Teske err(EXIT_FAILURE, "Out of memory?!"); 147041394f3SDevin Teske } 148041394f3SDevin Teske } 149041394f3SDevin Teske 150041394f3SDevin Teske return (0); 151041394f3SDevin Teske } 152041394f3SDevin Teske 153041394f3SDevin Teske static int 154041394f3SDevin Teske operate_on_bytes(struct dpv_file_node *file, int out) 155041394f3SDevin Teske { 156041394f3SDevin Teske int progress; 157041394f3SDevin Teske ssize_t r, w; 158041394f3SDevin Teske 159041394f3SDevin Teske if (operate_common(file, out) < 0) 160041394f3SDevin Teske return (-1); 161041394f3SDevin Teske 162041394f3SDevin Teske /* [Re-]Fill the buffer */ 163041394f3SDevin Teske if ((r = read(fd, buf, bsize)) <= 0) { 164041394f3SDevin Teske if (fd != STDIN_FILENO) 165041394f3SDevin Teske close(fd); 166041394f3SDevin Teske fd = -1; 167041394f3SDevin Teske file->status = DPV_STATUS_DONE; 168041394f3SDevin Teske return (100); 169041394f3SDevin Teske } 170041394f3SDevin Teske 171041394f3SDevin Teske /* [Re-]Dump the buffer */ 172041394f3SDevin Teske if (out >= 0) { 173041394f3SDevin Teske if ((w = write(out, buf, r)) < 0) { 174041394f3SDevin Teske end_dialog(); 175041394f3SDevin Teske err(EXIT_FAILURE, "output"); 176041394f3SDevin Teske } 177041394f3SDevin Teske fsync(out); 178041394f3SDevin Teske } 179041394f3SDevin Teske 180964b46aaSDevin Teske dpv_overall_read += r; 181041394f3SDevin Teske file->read += r; 182041394f3SDevin Teske 183041394f3SDevin Teske /* Calculate percentage of completion (if possible) */ 184041394f3SDevin Teske if (file->length >= 0) { 185041394f3SDevin Teske progress = (file->read * 100 / (file->length > 0 ? 186041394f3SDevin Teske file->length : 1)); 187041394f3SDevin Teske 188041394f3SDevin Teske /* If no_overrun, do not return 100% until read >= length */ 189041394f3SDevin Teske if (no_overrun && progress == 100 && file->read < file->length) 190041394f3SDevin Teske progress--; 191041394f3SDevin Teske 192041394f3SDevin Teske return (progress); 193041394f3SDevin Teske } else 194041394f3SDevin Teske return (-1); 195041394f3SDevin Teske } 196041394f3SDevin Teske 197041394f3SDevin Teske static int 198041394f3SDevin Teske operate_on_lines(struct dpv_file_node *file, int out) 199041394f3SDevin Teske { 200041394f3SDevin Teske char *p; 201041394f3SDevin Teske int progress; 202041394f3SDevin Teske ssize_t r, w; 203041394f3SDevin Teske 204041394f3SDevin Teske if (operate_common(file, out) < 0) 205041394f3SDevin Teske return (-1); 206041394f3SDevin Teske 207041394f3SDevin Teske /* [Re-]Fill the buffer */ 208041394f3SDevin Teske if ((r = read(fd, buf, bsize)) <= 0) { 209041394f3SDevin Teske if (fd != STDIN_FILENO) 210041394f3SDevin Teske close(fd); 211041394f3SDevin Teske fd = -1; 212041394f3SDevin Teske file->status = DPV_STATUS_DONE; 213041394f3SDevin Teske return (100); 214041394f3SDevin Teske } 215041394f3SDevin Teske buf[r] = '\0'; 216041394f3SDevin Teske 217041394f3SDevin Teske /* [Re-]Dump the buffer */ 218041394f3SDevin Teske if (out >= 0) { 219041394f3SDevin Teske if ((w = write(out, buf, r)) < 0) { 220041394f3SDevin Teske end_dialog(); 221041394f3SDevin Teske err(EXIT_FAILURE, "output"); 222041394f3SDevin Teske } 223041394f3SDevin Teske fsync(out); 224041394f3SDevin Teske } 225041394f3SDevin Teske 226041394f3SDevin Teske /* Process the buffer for number of lines */ 227041394f3SDevin Teske for (p = buf; p != NULL && *p != '\0';) 228041394f3SDevin Teske if ((p = strchr(p, '\n')) != NULL) 229964b46aaSDevin Teske dpv_overall_read++, p++, file->read++; 230041394f3SDevin Teske 231041394f3SDevin Teske /* Calculate percentage of completion (if possible) */ 232041394f3SDevin Teske if (file->length >= 0) { 233041394f3SDevin Teske progress = (file->read * 100 / file->length); 234041394f3SDevin Teske 235041394f3SDevin Teske /* If no_overrun, do not return 100% until read >= length */ 236041394f3SDevin Teske if (no_overrun && progress == 100 && file->read < file->length) 237041394f3SDevin Teske progress--; 238041394f3SDevin Teske 239041394f3SDevin Teske return (progress); 240041394f3SDevin Teske } else 241041394f3SDevin Teske return (-1); 242041394f3SDevin Teske } 243041394f3SDevin Teske 244041394f3SDevin Teske /* 245041394f3SDevin Teske * Takes a list of names that are to correspond to input streams coming from 246041394f3SDevin Teske * stdin or fifos and produces necessary config to drive dpv(3) `--gauge' 247041394f3SDevin Teske * widget. If the `-d' flag is used, output is instead send to terminal 248041394f3SDevin Teske * standard output (and the output can then be saved to a file, piped into 249041394f3SDevin Teske * custom [X]dialog(1) invocation, or whatever. 250041394f3SDevin Teske */ 251041394f3SDevin Teske int 252041394f3SDevin Teske main(int argc, char *argv[]) 253041394f3SDevin Teske { 254041394f3SDevin Teske char dummy; 255041394f3SDevin Teske int ch; 256041394f3SDevin Teske int n = 0; 257041394f3SDevin Teske size_t config_size = sizeof(struct dpv_config); 258041394f3SDevin Teske size_t file_node_size = sizeof(struct dpv_file_node); 259041394f3SDevin Teske struct dpv_config *config; 260041394f3SDevin Teske struct dpv_file_node *curfile; 261041394f3SDevin Teske struct sigaction act; 262041394f3SDevin Teske 263041394f3SDevin Teske pgm = argv[0]; /* store a copy of invocation name */ 264041394f3SDevin Teske 265041394f3SDevin Teske /* Allocate config structure */ 266041394f3SDevin Teske if ((config = malloc(config_size)) == NULL) 267041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 268041394f3SDevin Teske memset((void *)(config), '\0', config_size); 269041394f3SDevin Teske 270041394f3SDevin Teske /* 271041394f3SDevin Teske * Process command-line options 272041394f3SDevin Teske */ 273041394f3SDevin Teske while ((ch = getopt(argc, argv, 27456b38aa6SDevin Teske "a:b:dDhi:I:klL:mn:No:p:P:t:TU:wx:X")) != -1) { 275041394f3SDevin Teske switch(ch) { 276041394f3SDevin Teske case 'a': /* additional message text to append */ 277041394f3SDevin Teske if (config->aprompt == NULL) { 278041394f3SDevin Teske config->aprompt = malloc(DPV_APROMPT_MAX); 279041394f3SDevin Teske if (config->aprompt == NULL) 280041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 281041394f3SDevin Teske } 282041394f3SDevin Teske snprintf(config->aprompt, DPV_APROMPT_MAX, "%s", 283041394f3SDevin Teske optarg); 284041394f3SDevin Teske break; 285041394f3SDevin Teske case 'b': /* [X]dialog(1) backtitle */ 286041394f3SDevin Teske if (config->backtitle != NULL) 287041394f3SDevin Teske free((char *)config->backtitle); 288041394f3SDevin Teske config->backtitle = malloc(strlen(optarg) + 1); 289041394f3SDevin Teske if (config->backtitle == NULL) 290041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 291041394f3SDevin Teske *(config->backtitle) = '\0'; 292041394f3SDevin Teske strcat(config->backtitle, optarg); 293041394f3SDevin Teske break; 294041394f3SDevin Teske case 'd': /* debugging */ 295041394f3SDevin Teske debug = TRUE; 296041394f3SDevin Teske config->debug = debug; 297041394f3SDevin Teske break; 298041394f3SDevin Teske case 'D': /* use dialog(1) instead of libdialog */ 299041394f3SDevin Teske config->display_type = DPV_DISPLAY_DIALOG; 300041394f3SDevin Teske break; 301041394f3SDevin Teske case 'h': /* help/usage */ 302041394f3SDevin Teske usage(); 303041394f3SDevin Teske break; /* NOTREACHED */ 304041394f3SDevin Teske case 'i': /* status line format string for single-file */ 305041394f3SDevin Teske config->status_solo = optarg; 306041394f3SDevin Teske break; 307041394f3SDevin Teske case 'I': /* status line format string for many-files */ 308041394f3SDevin Teske config->status_many = optarg; 309041394f3SDevin Teske break; 31056b38aa6SDevin Teske case 'k': /* keep tite */ 31156b38aa6SDevin Teske config->keep_tite = TRUE; 31256b38aa6SDevin Teske break; 313041394f3SDevin Teske case 'l': /* Line mode */ 314041394f3SDevin Teske line_mode = TRUE; 315041394f3SDevin Teske break; 316041394f3SDevin Teske case 'L': /* custom label size */ 317041394f3SDevin Teske config->label_size = 318041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 319041394f3SDevin Teske if (config->label_size == 0 && errno == EINVAL) 320041394f3SDevin Teske errx(EXIT_FAILURE, 321041394f3SDevin Teske "`-L' argument must be numeric"); 322041394f3SDevin Teske else if (config->label_size < -1) 323041394f3SDevin Teske config->label_size = -1; 324041394f3SDevin Teske break; 325041394f3SDevin Teske case 'm': /* enable multiple file arguments */ 326041394f3SDevin Teske multiple = TRUE; 327041394f3SDevin Teske break; 328041394f3SDevin Teske case 'o': /* `-o path' for sending data-read to file */ 329041394f3SDevin Teske output_type = DPV_OUTPUT_FILE; 330041394f3SDevin Teske config->output_type = DPV_OUTPUT_FILE; 331041394f3SDevin Teske config->output = optarg; 332041394f3SDevin Teske break; 333041394f3SDevin Teske case 'n': /* custom number of files per `page' */ 334041394f3SDevin Teske config->display_limit = 335041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 336041394f3SDevin Teske if (config->display_limit == 0 && errno == EINVAL) 337041394f3SDevin Teske errx(EXIT_FAILURE, 338041394f3SDevin Teske "`-n' argument must be numeric"); 339041394f3SDevin Teske else if (config->display_limit < 0) 340041394f3SDevin Teske config->display_limit = -1; 341041394f3SDevin Teske break; 342041394f3SDevin Teske case 'N': /* No overrun (truncate reads of known-length) */ 343041394f3SDevin Teske no_overrun = TRUE; 344041394f3SDevin Teske config->options |= DPV_NO_OVERRUN; 345041394f3SDevin Teske break; 346041394f3SDevin Teske case 'p': /* additional message text to use as prefix */ 347041394f3SDevin Teske if (config->pprompt == NULL) { 348041394f3SDevin Teske config->pprompt = malloc(DPV_PPROMPT_MAX + 2); 349041394f3SDevin Teske if (config->pprompt == NULL) 350041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 351041394f3SDevin Teske /* +2 is for implicit "\n" appended later */ 352041394f3SDevin Teske } 353041394f3SDevin Teske snprintf(config->pprompt, DPV_PPROMPT_MAX, "%s", 354041394f3SDevin Teske optarg); 355041394f3SDevin Teske break; 356041394f3SDevin Teske case 'P': /* custom size for mini-progressbar */ 357041394f3SDevin Teske config->pbar_size = 358041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 359041394f3SDevin Teske if (config->pbar_size == 0 && errno == EINVAL) 360041394f3SDevin Teske errx(EXIT_FAILURE, 361041394f3SDevin Teske "`-P' argument must be numeric"); 362041394f3SDevin Teske else if (config->pbar_size < -1) 363041394f3SDevin Teske config->pbar_size = -1; 364041394f3SDevin Teske break; 365041394f3SDevin Teske case 't': /* [X]dialog(1) title */ 366041394f3SDevin Teske if (config->title != NULL) 367041394f3SDevin Teske free(config->title); 368041394f3SDevin Teske config->title = malloc(strlen(optarg) + 1); 369041394f3SDevin Teske if (config->title == NULL) 370041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 371041394f3SDevin Teske *(config->title) = '\0'; 372041394f3SDevin Teske strcat(config->title, optarg); 373041394f3SDevin Teske break; 374041394f3SDevin Teske case 'T': /* test mode (don't read data, fake it) */ 375041394f3SDevin Teske config->options |= DPV_TEST_MODE; 376041394f3SDevin Teske break; 377041394f3SDevin Teske case 'U': /* updates per second */ 378041394f3SDevin Teske config->status_updates_per_second = 379041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 380041394f3SDevin Teske if (config->status_updates_per_second == 0 && 381041394f3SDevin Teske errno == EINVAL) 382041394f3SDevin Teske errx(EXIT_FAILURE, 383041394f3SDevin Teske "`-U' argument must be numeric"); 384041394f3SDevin Teske break; 385041394f3SDevin Teske case 'w': /* `-p' and `-a' widths bump [X]dialog(1) width */ 386041394f3SDevin Teske config->options |= DPV_WIDE_MODE; 387041394f3SDevin Teske break; 388041394f3SDevin Teske case 'x': /* `-x cmd' for sending data-read to sh(1) code */ 389041394f3SDevin Teske output_type = DPV_OUTPUT_SHELL; 390041394f3SDevin Teske config->output_type = DPV_OUTPUT_SHELL; 391041394f3SDevin Teske config->output = optarg; 392041394f3SDevin Teske break; 393041394f3SDevin Teske case 'X': /* X11 support through x11/xdialog */ 394041394f3SDevin Teske config->display_type = DPV_DISPLAY_XDIALOG; 395041394f3SDevin Teske break; 396041394f3SDevin Teske case '?': /* unknown argument (based on optstring) */ 397041394f3SDevin Teske /* FALLTHROUGH */ 398041394f3SDevin Teske default: /* unhandled argument (based on switch) */ 399041394f3SDevin Teske usage(); 400041394f3SDevin Teske /* NOTREACHED */ 401041394f3SDevin Teske } 402041394f3SDevin Teske } 403041394f3SDevin Teske argc -= optind; 404041394f3SDevin Teske argv += optind; 405041394f3SDevin Teske 406041394f3SDevin Teske /* Process remaining arguments as list of names to display */ 407041394f3SDevin Teske for (curfile = file_list; n < argc; n++) { 408041394f3SDevin Teske nfiles++; 409041394f3SDevin Teske 410041394f3SDevin Teske /* Allocate a new struct for the file argument */ 411041394f3SDevin Teske if (curfile == NULL) { 412041394f3SDevin Teske if ((curfile = malloc(file_node_size)) == NULL) 413041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 414041394f3SDevin Teske memset((void *)(curfile), '\0', file_node_size); 415041394f3SDevin Teske file_list = curfile; 416041394f3SDevin Teske } else { 417041394f3SDevin Teske if ((curfile->next = malloc(file_node_size)) == NULL) 418041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 419041394f3SDevin Teske memset((void *)(curfile->next), '\0', file_node_size); 420041394f3SDevin Teske curfile = curfile->next; 421041394f3SDevin Teske } 422041394f3SDevin Teske curfile->name = argv[n]; 423041394f3SDevin Teske 424041394f3SDevin Teske /* Read possible `lines:' prefix from label syntax */ 425041394f3SDevin Teske if (sscanf(curfile->name, "%lli:%c", &(curfile->length), 426041394f3SDevin Teske &dummy) == 2) 427041394f3SDevin Teske curfile->name = strchr(curfile->name, ':') + 1; 428041394f3SDevin Teske else 429041394f3SDevin Teske curfile->length = -1; 430041394f3SDevin Teske 431041394f3SDevin Teske /* Read path argument if enabled */ 432041394f3SDevin Teske if (multiple) { 433041394f3SDevin Teske if (++n >= argc) 434041394f3SDevin Teske errx(EXIT_FAILURE, "Missing path argument " 435041394f3SDevin Teske "for label number %i", nfiles); 436041394f3SDevin Teske curfile->path = argv[n]; 437041394f3SDevin Teske } else 438041394f3SDevin Teske break; 439041394f3SDevin Teske } 440041394f3SDevin Teske 441041394f3SDevin Teske /* Display usage and exit if not given at least one name */ 442041394f3SDevin Teske if (nfiles == 0) { 443041394f3SDevin Teske warnx("no labels provided"); 444041394f3SDevin Teske usage(); 445041394f3SDevin Teske /* NOTREACHED */ 446041394f3SDevin Teske } 447041394f3SDevin Teske 448041394f3SDevin Teske /* 449041394f3SDevin Teske * Set cleanup routine for Ctrl-C action 450041394f3SDevin Teske */ 451041394f3SDevin Teske if (config->display_type == DPV_DISPLAY_LIBDIALOG) { 452041394f3SDevin Teske act.sa_handler = sig_int; 453041394f3SDevin Teske sigaction(SIGINT, &act, 0); 454041394f3SDevin Teske } 455041394f3SDevin Teske 456041394f3SDevin Teske /* Set status formats and action */ 457041394f3SDevin Teske if (line_mode) { 458041394f3SDevin Teske config->status_solo = LINE_STATUS_SOLO; 459041394f3SDevin Teske config->status_many = LINE_STATUS_SOLO; 460041394f3SDevin Teske config->action = operate_on_lines; 461041394f3SDevin Teske } else { 462041394f3SDevin Teske config->status_solo = BYTE_STATUS_SOLO; 463041394f3SDevin Teske config->status_many = BYTE_STATUS_SOLO; 464041394f3SDevin Teske config->action = operate_on_bytes; 465041394f3SDevin Teske } 466041394f3SDevin Teske 467041394f3SDevin Teske /* 468041394f3SDevin Teske * Hand off to dpv(3)... 469041394f3SDevin Teske */ 470041394f3SDevin Teske if (dpv(config, file_list) != 0 && debug) 471041394f3SDevin Teske warnx("dpv(3) returned error!?"); 472041394f3SDevin Teske 47356b38aa6SDevin Teske if (!config->keep_tite) 474041394f3SDevin Teske end_dialog(); 475041394f3SDevin Teske dpv_free(); 476041394f3SDevin Teske 477041394f3SDevin Teske exit(EXIT_SUCCESS); 478041394f3SDevin Teske } 479041394f3SDevin Teske 480041394f3SDevin Teske /* 481041394f3SDevin Teske * Interrupt handler to indicate we received a Ctrl-C interrupt. 482041394f3SDevin Teske */ 483041394f3SDevin Teske static void 484041394f3SDevin Teske sig_int(int sig __unused) 485041394f3SDevin Teske { 486041394f3SDevin Teske dpv_interrupt = TRUE; 487041394f3SDevin Teske } 488041394f3SDevin Teske 489041394f3SDevin Teske /* 490041394f3SDevin Teske * Print short usage statement to stderr and exit with error status. 491041394f3SDevin Teske */ 492041394f3SDevin Teske static void 493041394f3SDevin Teske usage(void) 494041394f3SDevin Teske { 495041394f3SDevin Teske 496041394f3SDevin Teske if (debug) /* No need for usage */ 497041394f3SDevin Teske exit(EXIT_FAILURE); 498041394f3SDevin Teske 499041394f3SDevin Teske fprintf(stderr, "Usage: %s [options] bytes:label\n", pgm); 500041394f3SDevin Teske fprintf(stderr, " %s [options] -m bytes1:label1 path1 " 501041394f3SDevin Teske "[bytes2:label2 path2 ...]\n", pgm); 502041394f3SDevin Teske fprintf(stderr, "OPTIONS:\n"); 503041394f3SDevin Teske #define OPTFMT "\t%-14s %s\n" 504041394f3SDevin Teske fprintf(stderr, OPTFMT, "-a text", 505041394f3SDevin Teske "Append text. Displayed below file progress indicators."); 506041394f3SDevin Teske fprintf(stderr, OPTFMT, "-b backtitle", 507041394f3SDevin Teske "String to be displayed on the backdrop, at top-left."); 508041394f3SDevin Teske fprintf(stderr, OPTFMT, "-d", 509041394f3SDevin Teske "Debug. Write to standard output instead of dialog."); 510041394f3SDevin Teske fprintf(stderr, OPTFMT, "-D", 511041394f3SDevin Teske "Use dialog(1) instead of dialog(3) [default]."); 512041394f3SDevin Teske fprintf(stderr, OPTFMT, "-h", 513041394f3SDevin Teske "Produce this output on standard error and exit."); 514041394f3SDevin Teske fprintf(stderr, OPTFMT, "-i format", 515041394f3SDevin Teske "Customize status line format. See fdpv(1) for details."); 516041394f3SDevin Teske fprintf(stderr, OPTFMT, "-I format", 517041394f3SDevin Teske "Customize status line format. See fdpv(1) for details."); 518041394f3SDevin Teske fprintf(stderr, OPTFMT, "-L size", 519041394f3SDevin Teske "Label size. Must be a number greater than 0, or -1."); 520041394f3SDevin Teske fprintf(stderr, OPTFMT, "-m", 521041394f3SDevin Teske "Enable processing of multiple file argiments."); 522041394f3SDevin Teske fprintf(stderr, OPTFMT, "-n num", 523041394f3SDevin Teske "Display at-most num files per screen. Default is -1."); 524041394f3SDevin Teske fprintf(stderr, OPTFMT, "-N", 525041394f3SDevin Teske "No overrun. Stop reading input at stated length, if any."); 526041394f3SDevin Teske fprintf(stderr, OPTFMT, "-o file", 527041394f3SDevin Teske "Output data to file. First %s replaced with label text."); 528041394f3SDevin Teske fprintf(stderr, OPTFMT, "-p text", 529041394f3SDevin Teske "Prefix text. Displayed above file progress indicators."); 530041394f3SDevin Teske fprintf(stderr, OPTFMT, "-P size", 531041394f3SDevin Teske "Mini-progressbar size. Must be a number greater than 3."); 532041394f3SDevin Teske fprintf(stderr, OPTFMT, "-t title", 533041394f3SDevin Teske "Title string to be displayed at top of dialog(1) box."); 534041394f3SDevin Teske fprintf(stderr, OPTFMT, "-T", 535041394f3SDevin Teske "Test mode. Don't actually read any data, but fake it."); 536041394f3SDevin Teske fprintf(stderr, OPTFMT, "-U num", 537041394f3SDevin Teske "Update status line num times per-second. Default is 2."); 538041394f3SDevin Teske fprintf(stderr, OPTFMT, "-w", 539041394f3SDevin Teske "Wide. Width of `-p' and `-a' text bump dialog(1) width."); 540041394f3SDevin Teske fprintf(stderr, OPTFMT, "-x cmd", 541041394f3SDevin Teske "Send data to executed cmd. First %s replaced with label."); 542041394f3SDevin Teske fprintf(stderr, OPTFMT, "-X", 543041394f3SDevin Teske "X11. Use Xdialog(1) instead of dialog(1)."); 544041394f3SDevin Teske exit(EXIT_FAILURE); 545041394f3SDevin Teske } 546