static void f_ibs(char *arg) { if (!(ddflags & C_BS)) in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX); }
static void f_obs(char *arg) { if (!(ddflags & C_BS)) out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX); }
static void f_files(char *arg) { files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX); if (!files_cnt) terminate(0); }
static void f_count(char *arg) { cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX); if (!cpy_cnt) terminate(0); }
int set_option(option_t *options, const char *var, const char *val) { int i; for (i = 0; options[i].name != NULL; i++) { if (strcmp(options[i].name, var) != 0) continue; *options[i].value = (int)strsuftoll(options[i].desc, val, options[i].minimum, options[i].maximum); return (1); } warnx("Unknown option `%s'", var); return (0); }
static void config(int argc, char **argv) { int fd, isreg, istmp, ispersistent; char full[64], path[MAXPATHLEN]; off_t bssize; dev_t mountdev; struct stat sbuf; struct statvfs fsbuf; struct fss_set fss; if (argc < 3) usage(); istmp = ispersistent = 0; fss.fss_mount = argv[1]; fss.fss_bstore = argv[2]; if (prog_statvfs1(argv[1], &fsbuf, ST_WAIT) != 0 || prog_stat(argv[1], &sbuf) != 0) err(1, "stat %s", argv[1]); mountdev = sbuf.st_dev; if (stat(argv[2], &sbuf) == 0 && S_ISREG(sbuf.st_mode) && sbuf.st_dev == mountdev) { if ((sbuf.st_flags & SF_SNAPSHOT) == 0) errx(1, "%s: exists and is not a snapshot", argv[2]); if (argc != 3) usage(); isreg = ispersistent = 1; goto configure; } if (argc > 5) usage(); if (argc > 3) fss.fss_csize = strsuftoll("cluster size", argv[3], 0, INT_MAX); else fss.fss_csize = 0; if (argc > 4) bssize = strsuftoll("bs size", argv[4], 0, LLONG_MAX); else bssize = (off_t)fsbuf.f_blocks*fsbuf.f_frsize; /* * Create the backing store. If it is a directory, create a temporary * file and set the unlink flag. */ fd = prog_open(fss.fss_bstore, O_CREAT|O_TRUNC|O_WRONLY, 0600); if (fd < 0) { if (errno != EISDIR) err(1, "create: %s", fss.fss_bstore); snprintf(path, sizeof(path), "%s/XXXXXXXXXX", fss.fss_bstore); if ((fd = mkstemp(path)) < 0) err(1, "mkstemp: %s", path); fss.fss_bstore = path; istmp = 1; } if (prog_fstat(fd, &sbuf) < 0) err(1, "stat: %s", fss.fss_bstore); if (!ispersistent && sbuf.st_dev == mountdev) ispersistent = 1; isreg = S_ISREG(sbuf.st_mode); if (!ispersistent && isreg && ftruncate(fd, bssize) < 0) err(1, "truncate %s", fss.fss_bstore); prog_close(fd); configure: fd = opendisk1(argv[0], O_RDWR, full, sizeof(full), 0, prog_open); if (fd < 0) { if (istmp) unlink(fss.fss_bstore); err(1, "open: %s", argv[0]); } fss.fss_flags = 0; if ((xflag || istmp) && isreg) fss.fss_flags |= FSS_UNLINK_ON_CREATE; if (prog_ioctl(fd, FSSIOCSET, &fss) < 0) { if (istmp) unlink(fss.fss_bstore); err(1, "%s: FSSIOCSET", full); } if (vflag) list(1, argv); }
static void f_progress(char *arg) { progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX); }
static void f_skip(char *arg) { in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX); }
static void f_seek(char *arg) { out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX); }
static void f_cbs(char *arg) { cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX); }
static void f_bs(char *arg) { in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX); }
int main(int argc, char *argv[]) { char *fb_buf; char *infile = NULL; pid_t pid = 0, gzippid = 0, deadpid; int ch, fd, outpipe[2]; int ws, gzipstat, cmdstat; int eflag = 0, lflag = 0, zflag = 0; ssize_t nr, nw, off; size_t buffersize; struct stat statb; struct ttysize ts; setprogname(argv[0]); /* defaults: Read from stdin, 0 filesize (no completion estimate) */ fd = STDIN_FILENO; filesize = 0; buffersize = 64 * 1024; prefix = NULL; while ((ch = getopt(argc, argv, "b:ef:l:p:z")) != -1) switch (ch) { case 'b': buffersize = (size_t) strsuftoll("buffer size", optarg, 0, SIZE_T_MAX); break; case 'e': eflag++; break; case 'f': infile = optarg; break; case 'l': lflag++; filesize = strsuftoll("input size", optarg, 0, LLONG_MAX); break; case 'p': prefix = optarg; break; case 'z': zflag++; break; case '?': default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; if (argc < 1) usage(); if (infile && (fd = open(infile, O_RDONLY, 0)) < 0) err(1, "%s", infile); /* stat() to get the filesize unless overridden, or -z */ if (!zflag && !lflag && (fstat(fd, &statb) == 0)) { if (S_ISFIFO(statb.st_mode)) { /* stat(2) on pipe may return only the * first few bytes with more coming. * Don't trust! */ } else { filesize = statb.st_size; } } /* gzip -l the file if we have the name and -z is given */ if (zflag && !lflag && infile != NULL) { FILE *gzipsizepipe; char buf[256], *cp, *cmd; /* * Read second word of last line of gzip -l output. Looks like: * % gzip -l ../etc.tgz * compressed uncompressed ratio uncompressed_name * 119737 696320 82.8% ../etc.tar */ asprintf(&cmd, "gzip -l %s", infile); if ((gzipsizepipe = popen(cmd, "r")) == NULL) err(1, "reading compressed file length"); for (; fgets(buf, 256, gzipsizepipe) != NULL;) continue; strtoimax(buf, &cp, 10); filesize = strtoimax(cp, NULL, 10); if (pclose(gzipsizepipe) < 0) err(1, "closing compressed file length pipe"); free(cmd); } /* Pipe input through gzip -dc if -z is given */ if (zflag) { int gzippipe[2]; if (pipe(gzippipe) < 0) err(1, "gzip pipe"); gzippid = fork(); if (gzippid < 0) err(1, "fork for gzip"); if (gzippid) { /* parent */ dup2(gzippipe[0], fd); close(gzippipe[0]); close(gzippipe[1]); } else { dup2(gzippipe[1], STDOUT_FILENO); dup2(fd, STDIN_FILENO); close(gzippipe[0]); close(gzippipe[1]); if (execlp("gzip", "gzip", "-dc", NULL)) err(1, "exec()ing gzip"); } } /* Initialize progressbar.c's global state */ bytes = 0; progress = 1; ttyout = eflag ? stderr : stdout; if (ioctl(fileno(ttyout), TIOCGSIZE, &ts) == -1) ttywidth = 80; else ttywidth = ts.ts_cols; fb_buf = malloc(buffersize); if (fb_buf == NULL) err(1, "malloc for buffersize"); if (pipe(outpipe) < 0) err(1, "output pipe"); pid = fork(); if (pid < 0) err(1, "fork for output pipe"); if (pid == 0) { /* child */ dup2(outpipe[0], STDIN_FILENO); close(outpipe[0]); close(outpipe[1]); execvp(argv[0], argv); err(1, "could not exec %s", argv[0]); } close(outpipe[0]); signal(SIGPIPE, broken_pipe); progressmeter(-1); while ((nr = read(fd, fb_buf, buffersize)) > 0) for (off = 0; nr; nr -= nw, off += nw, bytes += nw) if ((nw = write(outpipe[1], fb_buf + off, (size_t) nr)) < 0) { progressmeter(1); err(1, "writing %u bytes to output pipe", (unsigned) nr); } close(outpipe[1]); gzipstat = 0; cmdstat = 0; while (pid || gzippid) { deadpid = wait(&ws); /* * We need to exit with an error if the command (or gzip) * exited abnormally. * Unfortunately we can't generate a true 'exited by signal' * error without sending the signal to ourselves :-( */ ws = WIFSIGNALED(ws) ? WTERMSIG(ws) : WEXITSTATUS(ws); if (deadpid != -1 && errno == EINTR) continue; if (deadpid == pid) { pid = 0; cmdstat = ws; continue; } if (deadpid == gzippid) { gzippid = 0; gzipstat = ws; continue; } break; } progressmeter(1); signal(SIGPIPE, SIG_DFL); free(fb_buf); exit(cmdstat ? cmdstat : gzipstat); }
int main(int argc, char *argv[]) { struct stat sb; struct timeval start; fstype_t *fstype; fsinfo_t fsoptions; fsnode *root; int ch, i, len; char *subtree; char *specfile; setprogname(argv[0]); debug = 0; if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); /* set default fsoptions */ (void)memset(&fsoptions, 0, sizeof(fsoptions)); fsoptions.fd = -1; fsoptions.sectorsize = -1; if (fstype->prepare_options) fstype->prepare_options(&fsoptions); specfile = NULL; if (gettimeofday(&start, NULL) == -1) err(1, "Unable to get system time"); start_time.tv_sec = start.tv_sec; start_time.tv_nsec = start.tv_usec * 1000; while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pr:s:S:t:xZ")) != -1) { switch (ch) { case 'B': if (strcmp(optarg, "be") == 0 || strcmp(optarg, "4321") == 0 || strcmp(optarg, "big") == 0) { #if BYTE_ORDER == LITTLE_ENDIAN fsoptions.needswap = 1; #endif } else if (strcmp(optarg, "le") == 0 || strcmp(optarg, "1234") == 0 || strcmp(optarg, "little") == 0) { #if BYTE_ORDER == BIG_ENDIAN fsoptions.needswap = 1; #endif } else { warnx("Invalid endian `%s'.", optarg); usage(); } break; case 'b': len = strlen(optarg) - 1; if (optarg[len] == '%') { optarg[len] = '\0'; fsoptions.freeblockpc = strsuftoll("free block percentage", optarg, 0, 99); } else { fsoptions.freeblocks = strsuftoll("free blocks", optarg, 0, LLONG_MAX); } break; case 'D': dupsok = 1; break; case 'd': debug = strtoll(optarg, NULL, 0); break; case 'f': len = strlen(optarg) - 1; if (optarg[len] == '%') { optarg[len] = '\0'; fsoptions.freefilepc = strsuftoll("free file percentage", optarg, 0, 99); } else { fsoptions.freefiles = strsuftoll("free files", optarg, 0, LLONG_MAX); } break; case 'F': specfile = optarg; break; case 'M': fsoptions.minsize = strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); break; case 'N': if (! setup_getid(optarg)) errx(1, "Unable to use user and group databases in `%s'", optarg); break; case 'm': fsoptions.maxsize = strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); break; case 'o': { char *p; while ((p = strsep(&optarg, ",")) != NULL) { if (*p == '\0') errx(1, "Empty option"); if (! fstype->parse_options(p, &fsoptions)) usage(); } break; } case 'p': /* Deprecated in favor of 'Z' */ fsoptions.sparse = 1; break; case 'r': /* Round image size up to specified block size */ fsoptions.roundup = strsuftoll("roundup", optarg, 0, LLONG_MAX); break; case 's': fsoptions.minsize = fsoptions.maxsize = strsuftoll("size", optarg, 1LL, LLONG_MAX); break; case 'S': fsoptions.sectorsize = (int)strsuftoll("sector size", optarg, 1LL, INT_MAX); break; case 't': /* Check current one and cleanup if necessary. */ if (fstype->cleanup_options) fstype->cleanup_options(&fsoptions); fsoptions.fs_specific = NULL; if ((fstype = get_fstype(optarg)) == NULL) errx(1, "Unknown fs type `%s'.", optarg); fstype->prepare_options(&fsoptions); break; case 'x': fsoptions.onlyspec = 1; break; case 'Z': /* Superscedes 'p' for compatibility with NetBSD makefs(8) */ fsoptions.sparse = 1; break; case '?': default: usage(); /* NOTREACHED */ } } if (debug) { printf("debug mask: 0x%08x\n", debug); printf("start time: %ld.%ld, %s", (long)start_time.tv_sec, (long)start_time.tv_nsec, ctime(&start_time.tv_sec)); } argc -= optind; argv += optind; if (argc < 2) usage(); /* -x must be accompanied by -F */ if (fsoptions.onlyspec != 0 && specfile == NULL) errx(1, "-x requires -F mtree-specfile."); /* Accept '-' as meaning "read from standard input". */ if (strcmp(argv[1], "-") == 0) sb.st_mode = S_IFREG; else { if (stat(argv[1], &sb) == -1) err(1, "Can't stat `%s'", argv[1]); } switch (sb.st_mode & S_IFMT) { case S_IFDIR: /* walk the tree */ subtree = argv[1]; TIMER_START(start); root = walk_dir(subtree, ".", NULL, NULL); TIMER_RESULTS(start, "walk_dir"); break; case S_IFREG: /* read the manifest file */ subtree = "."; TIMER_START(start); root = read_mtree(argv[1], NULL); TIMER_RESULTS(start, "manifest"); break; default: errx(1, "%s: not a file or directory", argv[1]); /* NOTREACHED */ } /* append extra directory */ for (i = 2; i < argc; i++) { if (stat(argv[i], &sb) == -1) err(1, "Can't stat `%s'", argv[i]); if (!S_ISDIR(sb.st_mode)) errx(1, "%s: not a directory", argv[i]); TIMER_START(start); root = walk_dir(argv[i], ".", NULL, root); TIMER_RESULTS(start, "walk_dir2"); } if (specfile) { /* apply a specfile */ TIMER_START(start); apply_specfile(specfile, subtree, root, fsoptions.onlyspec); TIMER_RESULTS(start, "apply_specfile"); } if (debug & DEBUG_DUMP_FSNODES) { printf("\nparent: %s\n", subtree); dump_fsnodes(root); putchar('\n'); } /* build the file system */ TIMER_START(start); fstype->make_fs(argv[0], subtree, root, &fsoptions); TIMER_RESULTS(start, "make_fs"); free_fsnodes(root); exit(0); /* NOTREACHED */ }