1041394f3SDevin Teske /*- 2041394f3SDevin Teske * Copyright (c) 2013-2014 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 180*964b46aaSDevin 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) 229*964b46aaSDevin 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, 274041394f3SDevin Teske "a:b:dDhi:I:lL: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; 310041394f3SDevin Teske case 'l': /* Line mode */ 311041394f3SDevin Teske line_mode = TRUE; 312041394f3SDevin Teske break; 313041394f3SDevin Teske case 'L': /* custom label size */ 314041394f3SDevin Teske config->label_size = 315041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 316041394f3SDevin Teske if (config->label_size == 0 && errno == EINVAL) 317041394f3SDevin Teske errx(EXIT_FAILURE, 318041394f3SDevin Teske "`-L' argument must be numeric"); 319041394f3SDevin Teske else if (config->label_size < -1) 320041394f3SDevin Teske config->label_size = -1; 321041394f3SDevin Teske break; 322041394f3SDevin Teske case 'm': /* enable multiple file arguments */ 323041394f3SDevin Teske multiple = TRUE; 324041394f3SDevin Teske break; 325041394f3SDevin Teske case 'o': /* `-o path' for sending data-read to file */ 326041394f3SDevin Teske output_type = DPV_OUTPUT_FILE; 327041394f3SDevin Teske config->output_type = DPV_OUTPUT_FILE; 328041394f3SDevin Teske config->output = optarg; 329041394f3SDevin Teske break; 330041394f3SDevin Teske case 'n': /* custom number of files per `page' */ 331041394f3SDevin Teske config->display_limit = 332041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 333041394f3SDevin Teske if (config->display_limit == 0 && errno == EINVAL) 334041394f3SDevin Teske errx(EXIT_FAILURE, 335041394f3SDevin Teske "`-n' argument must be numeric"); 336041394f3SDevin Teske else if (config->display_limit < 0) 337041394f3SDevin Teske config->display_limit = -1; 338041394f3SDevin Teske break; 339041394f3SDevin Teske case 'N': /* No overrun (truncate reads of known-length) */ 340041394f3SDevin Teske no_overrun = TRUE; 341041394f3SDevin Teske config->options |= DPV_NO_OVERRUN; 342041394f3SDevin Teske break; 343041394f3SDevin Teske case 'p': /* additional message text to use as prefix */ 344041394f3SDevin Teske if (config->pprompt == NULL) { 345041394f3SDevin Teske config->pprompt = malloc(DPV_PPROMPT_MAX + 2); 346041394f3SDevin Teske if (config->pprompt == NULL) 347041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 348041394f3SDevin Teske /* +2 is for implicit "\n" appended later */ 349041394f3SDevin Teske } 350041394f3SDevin Teske snprintf(config->pprompt, DPV_PPROMPT_MAX, "%s", 351041394f3SDevin Teske optarg); 352041394f3SDevin Teske break; 353041394f3SDevin Teske case 'P': /* custom size for mini-progressbar */ 354041394f3SDevin Teske config->pbar_size = 355041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 356041394f3SDevin Teske if (config->pbar_size == 0 && errno == EINVAL) 357041394f3SDevin Teske errx(EXIT_FAILURE, 358041394f3SDevin Teske "`-P' argument must be numeric"); 359041394f3SDevin Teske else if (config->pbar_size < -1) 360041394f3SDevin Teske config->pbar_size = -1; 361041394f3SDevin Teske break; 362041394f3SDevin Teske case 't': /* [X]dialog(1) title */ 363041394f3SDevin Teske if (config->title != NULL) 364041394f3SDevin Teske free(config->title); 365041394f3SDevin Teske config->title = malloc(strlen(optarg) + 1); 366041394f3SDevin Teske if (config->title == NULL) 367041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 368041394f3SDevin Teske *(config->title) = '\0'; 369041394f3SDevin Teske strcat(config->title, optarg); 370041394f3SDevin Teske break; 371041394f3SDevin Teske case 'T': /* test mode (don't read data, fake it) */ 372041394f3SDevin Teske config->options |= DPV_TEST_MODE; 373041394f3SDevin Teske break; 374041394f3SDevin Teske case 'U': /* updates per second */ 375041394f3SDevin Teske config->status_updates_per_second = 376041394f3SDevin Teske (int)strtol(optarg, (char **)NULL, 10); 377041394f3SDevin Teske if (config->status_updates_per_second == 0 && 378041394f3SDevin Teske errno == EINVAL) 379041394f3SDevin Teske errx(EXIT_FAILURE, 380041394f3SDevin Teske "`-U' argument must be numeric"); 381041394f3SDevin Teske break; 382041394f3SDevin Teske case 'w': /* `-p' and `-a' widths bump [X]dialog(1) width */ 383041394f3SDevin Teske config->options |= DPV_WIDE_MODE; 384041394f3SDevin Teske break; 385041394f3SDevin Teske case 'x': /* `-x cmd' for sending data-read to sh(1) code */ 386041394f3SDevin Teske output_type = DPV_OUTPUT_SHELL; 387041394f3SDevin Teske config->output_type = DPV_OUTPUT_SHELL; 388041394f3SDevin Teske config->output = optarg; 389041394f3SDevin Teske break; 390041394f3SDevin Teske case 'X': /* X11 support through x11/xdialog */ 391041394f3SDevin Teske config->display_type = DPV_DISPLAY_XDIALOG; 392041394f3SDevin Teske break; 393041394f3SDevin Teske case '?': /* unknown argument (based on optstring) */ 394041394f3SDevin Teske /* FALLTHROUGH */ 395041394f3SDevin Teske default: /* unhandled argument (based on switch) */ 396041394f3SDevin Teske usage(); 397041394f3SDevin Teske /* NOTREACHED */ 398041394f3SDevin Teske } 399041394f3SDevin Teske } 400041394f3SDevin Teske argc -= optind; 401041394f3SDevin Teske argv += optind; 402041394f3SDevin Teske 403041394f3SDevin Teske /* Process remaining arguments as list of names to display */ 404041394f3SDevin Teske for (curfile = file_list; n < argc; n++) { 405041394f3SDevin Teske nfiles++; 406041394f3SDevin Teske 407041394f3SDevin Teske /* Allocate a new struct for the file argument */ 408041394f3SDevin Teske if (curfile == NULL) { 409041394f3SDevin Teske if ((curfile = malloc(file_node_size)) == NULL) 410041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 411041394f3SDevin Teske memset((void *)(curfile), '\0', file_node_size); 412041394f3SDevin Teske file_list = curfile; 413041394f3SDevin Teske } else { 414041394f3SDevin Teske if ((curfile->next = malloc(file_node_size)) == NULL) 415041394f3SDevin Teske errx(EXIT_FAILURE, "Out of memory?!"); 416041394f3SDevin Teske memset((void *)(curfile->next), '\0', file_node_size); 417041394f3SDevin Teske curfile = curfile->next; 418041394f3SDevin Teske } 419041394f3SDevin Teske curfile->name = argv[n]; 420041394f3SDevin Teske 421041394f3SDevin Teske /* Read possible `lines:' prefix from label syntax */ 422041394f3SDevin Teske if (sscanf(curfile->name, "%lli:%c", &(curfile->length), 423041394f3SDevin Teske &dummy) == 2) 424041394f3SDevin Teske curfile->name = strchr(curfile->name, ':') + 1; 425041394f3SDevin Teske else 426041394f3SDevin Teske curfile->length = -1; 427041394f3SDevin Teske 428041394f3SDevin Teske /* Read path argument if enabled */ 429041394f3SDevin Teske if (multiple) { 430041394f3SDevin Teske if (++n >= argc) 431041394f3SDevin Teske errx(EXIT_FAILURE, "Missing path argument " 432041394f3SDevin Teske "for label number %i", nfiles); 433041394f3SDevin Teske curfile->path = argv[n]; 434041394f3SDevin Teske } else 435041394f3SDevin Teske break; 436041394f3SDevin Teske } 437041394f3SDevin Teske 438041394f3SDevin Teske /* Display usage and exit if not given at least one name */ 439041394f3SDevin Teske if (nfiles == 0) { 440041394f3SDevin Teske warnx("no labels provided"); 441041394f3SDevin Teske usage(); 442041394f3SDevin Teske /* NOTREACHED */ 443041394f3SDevin Teske } 444041394f3SDevin Teske 445041394f3SDevin Teske /* 446041394f3SDevin Teske * Set cleanup routine for Ctrl-C action 447041394f3SDevin Teske */ 448041394f3SDevin Teske if (config->display_type == DPV_DISPLAY_LIBDIALOG) { 449041394f3SDevin Teske act.sa_handler = sig_int; 450041394f3SDevin Teske sigaction(SIGINT, &act, 0); 451041394f3SDevin Teske } 452041394f3SDevin Teske 453041394f3SDevin Teske /* Set status formats and action */ 454041394f3SDevin Teske if (line_mode) { 455041394f3SDevin Teske config->status_solo = LINE_STATUS_SOLO; 456041394f3SDevin Teske config->status_many = LINE_STATUS_SOLO; 457041394f3SDevin Teske config->action = operate_on_lines; 458041394f3SDevin Teske } else { 459041394f3SDevin Teske config->status_solo = BYTE_STATUS_SOLO; 460041394f3SDevin Teske config->status_many = BYTE_STATUS_SOLO; 461041394f3SDevin Teske config->action = operate_on_bytes; 462041394f3SDevin Teske } 463041394f3SDevin Teske 464041394f3SDevin Teske /* 465041394f3SDevin Teske * Hand off to dpv(3)... 466041394f3SDevin Teske */ 467041394f3SDevin Teske if (dpv(config, file_list) != 0 && debug) 468041394f3SDevin Teske warnx("dpv(3) returned error!?"); 469041394f3SDevin Teske 470041394f3SDevin Teske end_dialog(); 471041394f3SDevin Teske dpv_free(); 472041394f3SDevin Teske 473041394f3SDevin Teske exit(EXIT_SUCCESS); 474041394f3SDevin Teske } 475041394f3SDevin Teske 476041394f3SDevin Teske /* 477041394f3SDevin Teske * Interrupt handler to indicate we received a Ctrl-C interrupt. 478041394f3SDevin Teske */ 479041394f3SDevin Teske static void 480041394f3SDevin Teske sig_int(int sig __unused) 481041394f3SDevin Teske { 482041394f3SDevin Teske dpv_interrupt = TRUE; 483041394f3SDevin Teske } 484041394f3SDevin Teske 485041394f3SDevin Teske /* 486041394f3SDevin Teske * Print short usage statement to stderr and exit with error status. 487041394f3SDevin Teske */ 488041394f3SDevin Teske static void 489041394f3SDevin Teske usage(void) 490041394f3SDevin Teske { 491041394f3SDevin Teske 492041394f3SDevin Teske if (debug) /* No need for usage */ 493041394f3SDevin Teske exit(EXIT_FAILURE); 494041394f3SDevin Teske 495041394f3SDevin Teske fprintf(stderr, "Usage: %s [options] bytes:label\n", pgm); 496041394f3SDevin Teske fprintf(stderr, " %s [options] -m bytes1:label1 path1 " 497041394f3SDevin Teske "[bytes2:label2 path2 ...]\n", pgm); 498041394f3SDevin Teske fprintf(stderr, "OPTIONS:\n"); 499041394f3SDevin Teske #define OPTFMT "\t%-14s %s\n" 500041394f3SDevin Teske fprintf(stderr, OPTFMT, "-a text", 501041394f3SDevin Teske "Append text. Displayed below file progress indicators."); 502041394f3SDevin Teske fprintf(stderr, OPTFMT, "-b backtitle", 503041394f3SDevin Teske "String to be displayed on the backdrop, at top-left."); 504041394f3SDevin Teske fprintf(stderr, OPTFMT, "-d", 505041394f3SDevin Teske "Debug. Write to standard output instead of dialog."); 506041394f3SDevin Teske fprintf(stderr, OPTFMT, "-D", 507041394f3SDevin Teske "Use dialog(1) instead of dialog(3) [default]."); 508041394f3SDevin Teske fprintf(stderr, OPTFMT, "-h", 509041394f3SDevin Teske "Produce this output on standard error and exit."); 510041394f3SDevin Teske fprintf(stderr, OPTFMT, "-i format", 511041394f3SDevin Teske "Customize status line format. See fdpv(1) for details."); 512041394f3SDevin Teske fprintf(stderr, OPTFMT, "-I format", 513041394f3SDevin Teske "Customize status line format. See fdpv(1) for details."); 514041394f3SDevin Teske fprintf(stderr, OPTFMT, "-L size", 515041394f3SDevin Teske "Label size. Must be a number greater than 0, or -1."); 516041394f3SDevin Teske fprintf(stderr, OPTFMT, "-m", 517041394f3SDevin Teske "Enable processing of multiple file argiments."); 518041394f3SDevin Teske fprintf(stderr, OPTFMT, "-n num", 519041394f3SDevin Teske "Display at-most num files per screen. Default is -1."); 520041394f3SDevin Teske fprintf(stderr, OPTFMT, "-N", 521041394f3SDevin Teske "No overrun. Stop reading input at stated length, if any."); 522041394f3SDevin Teske fprintf(stderr, OPTFMT, "-o file", 523041394f3SDevin Teske "Output data to file. First %s replaced with label text."); 524041394f3SDevin Teske fprintf(stderr, OPTFMT, "-p text", 525041394f3SDevin Teske "Prefix text. Displayed above file progress indicators."); 526041394f3SDevin Teske fprintf(stderr, OPTFMT, "-P size", 527041394f3SDevin Teske "Mini-progressbar size. Must be a number greater than 3."); 528041394f3SDevin Teske fprintf(stderr, OPTFMT, "-t title", 529041394f3SDevin Teske "Title string to be displayed at top of dialog(1) box."); 530041394f3SDevin Teske fprintf(stderr, OPTFMT, "-T", 531041394f3SDevin Teske "Test mode. Don't actually read any data, but fake it."); 532041394f3SDevin Teske fprintf(stderr, OPTFMT, "-U num", 533041394f3SDevin Teske "Update status line num times per-second. Default is 2."); 534041394f3SDevin Teske fprintf(stderr, OPTFMT, "-w", 535041394f3SDevin Teske "Wide. Width of `-p' and `-a' text bump dialog(1) width."); 536041394f3SDevin Teske fprintf(stderr, OPTFMT, "-x cmd", 537041394f3SDevin Teske "Send data to executed cmd. First %s replaced with label."); 538041394f3SDevin Teske fprintf(stderr, OPTFMT, "-X", 539041394f3SDevin Teske "X11. Use Xdialog(1) instead of dialog(1)."); 540041394f3SDevin Teske exit(EXIT_FAILURE); 541041394f3SDevin Teske } 542