1edeb84a1SSheldon Hearn /* 2edeb84a1SSheldon Hearn * Copyright (c) 2000 FreeBSD, Inc. All rights reserved. 3edeb84a1SSheldon Hearn * 4edeb84a1SSheldon Hearn * Redistribution and use in source and binary forms, with or without 5edeb84a1SSheldon Hearn * modification, are permitted provided that the following conditions 6edeb84a1SSheldon Hearn * are met: 7edeb84a1SSheldon Hearn * 1. Redistributions of source code must retain the above copyright 8edeb84a1SSheldon Hearn * notice, this list of conditions and the following disclaimer. 9edeb84a1SSheldon Hearn * 2. Redistributions in binary form must reproduce the above copyright 10edeb84a1SSheldon Hearn * notice, this list of conditions and the following disclaimer in the 11edeb84a1SSheldon Hearn * documentation and/or other materials provided with the distribution. 12edeb84a1SSheldon Hearn * 13edeb84a1SSheldon Hearn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14edeb84a1SSheldon Hearn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15edeb84a1SSheldon Hearn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16edeb84a1SSheldon Hearn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17edeb84a1SSheldon Hearn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18edeb84a1SSheldon Hearn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19edeb84a1SSheldon Hearn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20edeb84a1SSheldon Hearn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21edeb84a1SSheldon Hearn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22edeb84a1SSheldon Hearn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23edeb84a1SSheldon Hearn * SUCH DAMAGE. 24edeb84a1SSheldon Hearn * 25edeb84a1SSheldon Hearn * $FreeBSD$ 26edeb84a1SSheldon Hearn */ 27edeb84a1SSheldon Hearn 28edeb84a1SSheldon Hearn #include <sys/stat.h> 29edeb84a1SSheldon Hearn #include <sys/types.h> 30edeb84a1SSheldon Hearn 31edeb84a1SSheldon Hearn #include <ctype.h> 32edeb84a1SSheldon Hearn #include <err.h> 33edeb84a1SSheldon Hearn #include <errno.h> 34edeb84a1SSheldon Hearn #include <fcntl.h> 35edeb84a1SSheldon Hearn #include <limits.h> 36edeb84a1SSheldon Hearn #include <stdio.h> 37edeb84a1SSheldon Hearn #include <stdlib.h> 38edeb84a1SSheldon Hearn #include <unistd.h> 39edeb84a1SSheldon Hearn 40edeb84a1SSheldon Hearn static off_t parselength __P((char *, off_t *)); 41edeb84a1SSheldon Hearn static void usage __P((void)); 42edeb84a1SSheldon Hearn 43edeb84a1SSheldon Hearn static int no_create; 44edeb84a1SSheldon Hearn static int do_relative; 45edeb84a1SSheldon Hearn static int do_refer; 46edeb84a1SSheldon Hearn static int got_size; 47edeb84a1SSheldon Hearn 48edeb84a1SSheldon Hearn int 49edeb84a1SSheldon Hearn main(int argc, char **argv) 50edeb84a1SSheldon Hearn { 51edeb84a1SSheldon Hearn struct stat sb; 52edeb84a1SSheldon Hearn mode_t omode; 53edeb84a1SSheldon Hearn off_t oflow, rsize, sz, tsize; 54edeb84a1SSheldon Hearn int ch, error, fd, oflags; 55edeb84a1SSheldon Hearn char *fname, *rname; 56edeb84a1SSheldon Hearn 57edeb84a1SSheldon Hearn error = 0; 58edeb84a1SSheldon Hearn while ((ch = getopt(argc, argv, "cr:s:")) != -1) 59edeb84a1SSheldon Hearn switch (ch) { 60edeb84a1SSheldon Hearn case 'c': 61edeb84a1SSheldon Hearn no_create++; 62edeb84a1SSheldon Hearn break; 63edeb84a1SSheldon Hearn case 'r': 64edeb84a1SSheldon Hearn do_refer++; 65edeb84a1SSheldon Hearn rname = optarg; 66edeb84a1SSheldon Hearn break; 67edeb84a1SSheldon Hearn case 's': 68edeb84a1SSheldon Hearn if (parselength(optarg, &sz) == -1) 69edeb84a1SSheldon Hearn errx(EXIT_FAILURE, 70edeb84a1SSheldon Hearn "invalid size argument `%s'", optarg); 71edeb84a1SSheldon Hearn if (*optarg == '+' || *optarg == '-') 72edeb84a1SSheldon Hearn do_relative++; 73edeb84a1SSheldon Hearn got_size++; 74edeb84a1SSheldon Hearn break; 75edeb84a1SSheldon Hearn default: 76edeb84a1SSheldon Hearn usage(); 77edeb84a1SSheldon Hearn /* NOTREACHED */ 78edeb84a1SSheldon Hearn } 79edeb84a1SSheldon Hearn 80edeb84a1SSheldon Hearn argv += optind; 81edeb84a1SSheldon Hearn argc -= optind; 82edeb84a1SSheldon Hearn 83edeb84a1SSheldon Hearn /* 84edeb84a1SSheldon Hearn * Exactly one of do_refer or got_size must be specified. Since 85edeb84a1SSheldon Hearn * do_relative implies got_size, do_relative and do_refer are 86edeb84a1SSheldon Hearn * also mutually exclusive. See usage() for allowed invocations. 87edeb84a1SSheldon Hearn */ 88edeb84a1SSheldon Hearn if (!(do_refer || got_size) || (do_refer && got_size) || argc < 1) 89edeb84a1SSheldon Hearn usage(); 90edeb84a1SSheldon Hearn if (do_refer) { 91edeb84a1SSheldon Hearn if (stat(rname, &sb) == -1) 92edeb84a1SSheldon Hearn err(EXIT_FAILURE, "%s", rname); 93edeb84a1SSheldon Hearn tsize = sb.st_size; 94edeb84a1SSheldon Hearn } else if (got_size) { 95edeb84a1SSheldon Hearn if (do_relative) 96edeb84a1SSheldon Hearn rsize = sz; 97edeb84a1SSheldon Hearn else 98edeb84a1SSheldon Hearn tsize = sz; 99edeb84a1SSheldon Hearn } 100edeb84a1SSheldon Hearn 101edeb84a1SSheldon Hearn if (no_create) 102edeb84a1SSheldon Hearn oflags = O_WRONLY; 103edeb84a1SSheldon Hearn else 104edeb84a1SSheldon Hearn oflags = O_WRONLY | O_CREAT; 105edeb84a1SSheldon Hearn omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 106edeb84a1SSheldon Hearn 107edeb84a1SSheldon Hearn while ((fname = *argv++) != NULL) { 108edeb84a1SSheldon Hearn if ((fd = open(fname, oflags, omode)) == -1) { 109edeb84a1SSheldon Hearn if (errno != ENOENT) { 110edeb84a1SSheldon Hearn warn("%s", fname); 111edeb84a1SSheldon Hearn error++; 112edeb84a1SSheldon Hearn } 113edeb84a1SSheldon Hearn continue; 114edeb84a1SSheldon Hearn } 115edeb84a1SSheldon Hearn if (do_relative) { 116edeb84a1SSheldon Hearn if (fstat(fd, &sb) == -1) { 117edeb84a1SSheldon Hearn warn("%s", fname); 118edeb84a1SSheldon Hearn error++; 119edeb84a1SSheldon Hearn continue; 120edeb84a1SSheldon Hearn } 121edeb84a1SSheldon Hearn oflow = sb.st_size + rsize; 122edeb84a1SSheldon Hearn if (oflow < (sb.st_size + rsize)) { 123edeb84a1SSheldon Hearn errno = EFBIG; 124edeb84a1SSheldon Hearn warn("%s", fname); 125edeb84a1SSheldon Hearn error++; 126edeb84a1SSheldon Hearn continue; 127edeb84a1SSheldon Hearn } 128edeb84a1SSheldon Hearn tsize = oflow; 129edeb84a1SSheldon Hearn } 130edeb84a1SSheldon Hearn if (tsize < 0) 131edeb84a1SSheldon Hearn tsize = 0; 132edeb84a1SSheldon Hearn 133edeb84a1SSheldon Hearn if (ftruncate(fd, tsize) == -1) { 134edeb84a1SSheldon Hearn warn("%s", fname); 135edeb84a1SSheldon Hearn error++; 136edeb84a1SSheldon Hearn continue; 137edeb84a1SSheldon Hearn } 138edeb84a1SSheldon Hearn } 139edeb84a1SSheldon Hearn 140edeb84a1SSheldon Hearn return error ? EXIT_FAILURE : EXIT_SUCCESS; 141edeb84a1SSheldon Hearn } 142edeb84a1SSheldon Hearn 143edeb84a1SSheldon Hearn /* 144edeb84a1SSheldon Hearn * Return the numeric value of a string given in the form [+-][0-9]+[GMK] 145edeb84a1SSheldon Hearn * or -1 on format error or overflow. 146edeb84a1SSheldon Hearn */ 147edeb84a1SSheldon Hearn static off_t 148edeb84a1SSheldon Hearn parselength(char *ls, off_t *sz) 149edeb84a1SSheldon Hearn { 150edeb84a1SSheldon Hearn off_t length, oflow; 151edeb84a1SSheldon Hearn int lsign; 152edeb84a1SSheldon Hearn 153edeb84a1SSheldon Hearn length = 0; 154edeb84a1SSheldon Hearn lsign = 1; 155edeb84a1SSheldon Hearn 156edeb84a1SSheldon Hearn switch (*ls) { 157edeb84a1SSheldon Hearn case '-': 158edeb84a1SSheldon Hearn lsign = -1; 159edeb84a1SSheldon Hearn case '+': 160edeb84a1SSheldon Hearn ls++; 161edeb84a1SSheldon Hearn } 162edeb84a1SSheldon Hearn 163edeb84a1SSheldon Hearn #define ASSIGN_CHK_OFLOW(x, y) if (x < y) return -1; y = x 164edeb84a1SSheldon Hearn /* 165edeb84a1SSheldon Hearn * Calculate the value of the decimal digit string, failing 166edeb84a1SSheldon Hearn * on overflow. 167edeb84a1SSheldon Hearn */ 168edeb84a1SSheldon Hearn while (isdigit(*ls)) { 169edeb84a1SSheldon Hearn oflow = length * 10 + *ls++ - '0'; 170edeb84a1SSheldon Hearn ASSIGN_CHK_OFLOW(oflow, length); 171edeb84a1SSheldon Hearn } 172edeb84a1SSheldon Hearn 173edeb84a1SSheldon Hearn switch (*ls) { 174edeb84a1SSheldon Hearn case 'G': 175edeb84a1SSheldon Hearn oflow = length * 1024; 176edeb84a1SSheldon Hearn ASSIGN_CHK_OFLOW(oflow, length); 177edeb84a1SSheldon Hearn case 'M': 178edeb84a1SSheldon Hearn oflow = length * 1024; 179edeb84a1SSheldon Hearn ASSIGN_CHK_OFLOW(oflow, length); 180edeb84a1SSheldon Hearn case 'K': 181edeb84a1SSheldon Hearn if (ls[1] != '\0') 182edeb84a1SSheldon Hearn return -1; 183edeb84a1SSheldon Hearn oflow = length * 1024; 184edeb84a1SSheldon Hearn ASSIGN_CHK_OFLOW(oflow, length); 185edeb84a1SSheldon Hearn case '\0': 186edeb84a1SSheldon Hearn break; 187edeb84a1SSheldon Hearn default: 188edeb84a1SSheldon Hearn return -1; 189edeb84a1SSheldon Hearn } 190edeb84a1SSheldon Hearn 191edeb84a1SSheldon Hearn *sz = length * lsign; 192edeb84a1SSheldon Hearn return 0; 193edeb84a1SSheldon Hearn } 194edeb84a1SSheldon Hearn 195edeb84a1SSheldon Hearn static void 196edeb84a1SSheldon Hearn usage(void) 197edeb84a1SSheldon Hearn { 198edeb84a1SSheldon Hearn fprintf(stderr, "%s\n%s\n", 199edeb84a1SSheldon Hearn "usage: truncate [-c] -s [+|-]size[K|M|G] file ...", 200edeb84a1SSheldon Hearn " truncate [-c] -r rfile file ..."); 201edeb84a1SSheldon Hearn exit(EXIT_FAILURE); 202edeb84a1SSheldon Hearn } 203