truncate.c revision 63437
1207618Srdivacky/* 2207618Srdivacky * Copyright (c) 2000 FreeBSD, Inc. All rights reserved. 3207618Srdivacky * 4207618Srdivacky * Redistribution and use in source and binary forms, with or without 5207618Srdivacky * modification, are permitted provided that the following conditions 6207618Srdivacky * are met: 7207618Srdivacky * 1. Redistributions of source code must retain the above copyright 8207618Srdivacky * notice, this list of conditions and the following disclaimer. 9207618Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 10207618Srdivacky * notice, this list of conditions and the following disclaimer in the 11207618Srdivacky * documentation and/or other materials provided with the distribution. 12207618Srdivacky * 13207618Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14207618Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15208599Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16207618Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17207618Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18208599Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19208599Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20208599Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21207618Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22207618Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23207618Srdivacky * SUCH DAMAGE. 24207618Srdivacky * 25208599Srdivacky * $FreeBSD: head/usr.bin/truncate/truncate.c 63437 2000-07-18 17:03:58Z sheldonh $ 26208599Srdivacky */ 27208599Srdivacky 28208599Srdivacky#include <sys/stat.h> 29208599Srdivacky#include <sys/types.h> 30208599Srdivacky 31208599Srdivacky#include <ctype.h> 32208599Srdivacky#include <err.h> 33208599Srdivacky#include <errno.h> 34208599Srdivacky#include <fcntl.h> 35208599Srdivacky#include <limits.h> 36208599Srdivacky#include <stdio.h> 37208599Srdivacky#include <stdlib.h> 38208599Srdivacky#include <unistd.h> 39208599Srdivacky 40208599Srdivackystatic off_t parselength __P((char *, off_t *)); 41208599Srdivackystatic void usage __P((void)); 42208599Srdivacky 43208599Srdivackystatic int no_create; 44208599Srdivackystatic int do_relative; 45208599Srdivackystatic int do_refer; 46208599Srdivackystatic int got_size; 47208599Srdivacky 48208599Srdivackyint 49208599Srdivackymain(int argc, char **argv) 50208599Srdivacky{ 51208599Srdivacky struct stat sb; 52208599Srdivacky mode_t omode; 53208599Srdivacky off_t oflow, rsize, sz, tsize; 54208599Srdivacky int ch, error, fd, oflags; 55208599Srdivacky char *fname, *rname; 56208599Srdivacky 57208599Srdivacky error = 0; 58208599Srdivacky while ((ch = getopt(argc, argv, "cr:s:")) != -1) 59208599Srdivacky switch (ch) { 60208599Srdivacky case 'c': 61208599Srdivacky no_create++; 62208599Srdivacky break; 63208599Srdivacky case 'r': 64208599Srdivacky do_refer++; 65208599Srdivacky rname = optarg; 66208599Srdivacky break; 67208599Srdivacky case 's': 68208599Srdivacky if (parselength(optarg, &sz) == -1) 69208599Srdivacky errx(EXIT_FAILURE, 70208599Srdivacky "invalid size argument `%s'", optarg); 71208599Srdivacky if (*optarg == '+' || *optarg == '-') 72208599Srdivacky do_relative++; 73208599Srdivacky got_size++; 74208599Srdivacky break; 75208599Srdivacky default: 76208599Srdivacky usage(); 77208599Srdivacky /* NOTREACHED */ 78208599Srdivacky } 79208599Srdivacky 80208599Srdivacky argv += optind; 81208599Srdivacky argc -= optind; 82208599Srdivacky 83208599Srdivacky /* 84208599Srdivacky * Exactly one of do_refer or got_size must be specified. Since 85208599Srdivacky * do_relative implies got_size, do_relative and do_refer are 86208599Srdivacky * also mutually exclusive. See usage() for allowed invocations. 87208599Srdivacky */ 88208599Srdivacky if (!(do_refer || got_size) || (do_refer && got_size) || argc < 1) 89208599Srdivacky usage(); 90208599Srdivacky if (do_refer) { 91208599Srdivacky if (stat(rname, &sb) == -1) 92208599Srdivacky err(EXIT_FAILURE, "%s", rname); 93208599Srdivacky tsize = sb.st_size; 94208599Srdivacky } else if (got_size) { 95208599Srdivacky if (do_relative) 96208599Srdivacky rsize = sz; 97208599Srdivacky else 98208599Srdivacky tsize = sz; 99208599Srdivacky } 100208599Srdivacky 101208599Srdivacky if (no_create) 102208599Srdivacky oflags = O_WRONLY; 103208599Srdivacky else 104208599Srdivacky oflags = O_WRONLY | O_CREAT; 105208599Srdivacky omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 106208599Srdivacky 107208599Srdivacky while ((fname = *argv++) != NULL) { 108208599Srdivacky if ((fd = open(fname, oflags, omode)) == -1) { 109208599Srdivacky if (errno != ENOENT) { 110208599Srdivacky warn("%s", fname); 111208599Srdivacky error++; 112208599Srdivacky } 113208599Srdivacky continue; 114208599Srdivacky } 115208599Srdivacky if (do_relative) { 116208599Srdivacky if (fstat(fd, &sb) == -1) { 117208599Srdivacky warn("%s", fname); 118208599Srdivacky error++; 119208599Srdivacky continue; 120208599Srdivacky } 121208599Srdivacky oflow = sb.st_size + rsize; 122208599Srdivacky if (oflow < (sb.st_size + rsize)) { 123208599Srdivacky errno = EFBIG; 124208599Srdivacky warn("%s", fname); 125208599Srdivacky error++; 126208599Srdivacky continue; 127208599Srdivacky } 128208599Srdivacky tsize = oflow; 129208599Srdivacky } 130208599Srdivacky if (tsize < 0) 131208599Srdivacky tsize = 0; 132208599Srdivacky 133208599Srdivacky if (ftruncate(fd, tsize) == -1) { 134208599Srdivacky warn("%s", fname); 135 error++; 136 continue; 137 } 138 } 139 140 return error ? EXIT_FAILURE : EXIT_SUCCESS; 141} 142 143/* 144 * Return the numeric value of a string given in the form [+-][0-9]+[GMK] 145 * or -1 on format error or overflow. 146 */ 147static off_t 148parselength(char *ls, off_t *sz) 149{ 150 off_t length, oflow; 151 int lsign; 152 153 length = 0; 154 lsign = 1; 155 156 switch (*ls) { 157 case '-': 158 lsign = -1; 159 case '+': 160 ls++; 161 } 162 163#define ASSIGN_CHK_OFLOW(x, y) if (x < y) return -1; y = x 164 /* 165 * Calculate the value of the decimal digit string, failing 166 * on overflow. 167 */ 168 while (isdigit(*ls)) { 169 oflow = length * 10 + *ls++ - '0'; 170 ASSIGN_CHK_OFLOW(oflow, length); 171 } 172 173 switch (*ls) { 174 case 'G': 175 oflow = length * 1024; 176 ASSIGN_CHK_OFLOW(oflow, length); 177 case 'M': 178 oflow = length * 1024; 179 ASSIGN_CHK_OFLOW(oflow, length); 180 case 'K': 181 if (ls[1] != '\0') 182 return -1; 183 oflow = length * 1024; 184 ASSIGN_CHK_OFLOW(oflow, length); 185 case '\0': 186 break; 187 default: 188 return -1; 189 } 190 191 *sz = length * lsign; 192 return 0; 193} 194 195static void 196usage(void) 197{ 198 fprintf(stderr, "%s\n%s\n", 199 "usage: truncate [-c] -s [+|-]size[K|M|G] file ...", 200 " truncate [-c] -r rfile file ..."); 201 exit(EXIT_FAILURE); 202} 203