truncate.c revision 188887
1178172Simp/*- 2178172Simp * Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>. 3206713Sjmallett * All rights reserved. 4206713Sjmallett * 5206713Sjmallett * Redistribution and use in source and binary forms, with or without 6206713Sjmallett * modification, are permitted provided that the following conditions 7206713Sjmallett * are met: 8206713Sjmallett * 1. Redistributions of source code must retain the above copyright 9206713Sjmallett * notice, this list of conditions and the following disclaimer. 10206713Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 11206713Sjmallett * notice, this list of conditions and the following disclaimer in the 12206713Sjmallett * documentation and/or other materials provided with the distribution. 13206713Sjmallett * 14206713Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15206713Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16206713Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17206713Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18206713Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19206713Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20206713Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21206713Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22206713Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23206713Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24206713Sjmallett * SUCH DAMAGE. 25206713Sjmallett * 26206713Sjmallett */ 27178172Simp 28178172Simp#ifndef lint 29178172Simpstatic const char rcsid[] = 30178172Simp "$FreeBSD: head/usr.bin/truncate/truncate.c 188887 2009-02-21 03:42:31Z delphij $"; 31178172Simp#endif 32178172Simp 33178172Simp#include <sys/stat.h> 34178172Simp 35178172Simp#include <ctype.h> 36178172Simp#include <err.h> 37178172Simp#include <errno.h> 38178172Simp#include <fcntl.h> 39178172Simp#include <stdio.h> 40178172Simp#include <stdlib.h> 41178172Simp#include <unistd.h> 42178172Simp 43178172Simpstatic int parselength(char *, off_t *); 44178172Simpstatic void usage(void); 45178172Simp 46178172Simpstatic int no_create; 47178172Simpstatic int do_relative; 48178172Simpstatic int do_refer; 49178172Simpstatic int got_size; 50178172Simp 51178172Simpint 52178172Simpmain(int argc, char **argv) 53178172Simp{ 54178172Simp struct stat sb; 55178172Simp mode_t omode; 56178172Simp off_t oflow, rsize, sz, tsize; 57178172Simp int ch, error, fd, oflags; 58178172Simp char *fname, *rname; 59178172Simp 60178172Simp fd = -1; 61178172Simp rsize = tsize = sz = 0; 62178172Simp error = 0; 63178172Simp rname = NULL; 64178172Simp while ((ch = getopt(argc, argv, "cr:s:")) != -1) 65178172Simp switch (ch) { 66178172Simp case 'c': 67178172Simp no_create = 1; 68178172Simp break; 69178172Simp case 'r': 70178172Simp do_refer = 1; 71178172Simp rname = optarg; 72227658Sjchandra break; 73241374Sattilio case 's': 74218383Sjmallett if (parselength(optarg, &sz) == -1) 75178172Simp errx(EXIT_FAILURE, 76178172Simp "invalid size argument `%s'", optarg); 77178172Simp if (*optarg == '+' || *optarg == '-') 78178172Simp do_relative = 1; 79178172Simp got_size = 1; 80178172Simp break; 81178172Simp default: 82178172Simp usage(); 83178172Simp /* NOTREACHED */ 84178172Simp } 85178172Simp 86218383Sjmallett argv += optind; 87178172Simp argc -= optind; 88178172Simp 89178172Simp /* 90206713Sjmallett * Exactly one of do_refer or got_size must be specified. Since 91206713Sjmallett * do_relative implies got_size, do_relative and do_refer are 92206713Sjmallett * also mutually exclusive. See usage() for allowed invocations. 93206713Sjmallett */ 94206713Sjmallett if (do_refer + got_size != 1 || argc < 1) 95206713Sjmallett usage(); 96178172Simp if (do_refer) { 97178172Simp if (stat(rname, &sb) == -1) 98218383Sjmallett err(EXIT_FAILURE, "%s", rname); 99218383Sjmallett tsize = sb.st_size; 100218383Sjmallett } else if (do_relative) 101218383Sjmallett rsize = sz; 102218383Sjmallett else 103218383Sjmallett tsize = sz; 104178172Simp 105178172Simp if (no_create) 106218383Sjmallett oflags = O_WRONLY; 107178172Simp else 108178172Simp oflags = O_WRONLY | O_CREAT; 109178172Simp omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 110216947Sjmallett 111216947Sjmallett while ((fname = *argv++) != NULL) { 112216947Sjmallett if (fd != -1) 113216947Sjmallett close(fd); 114216947Sjmallett if ((fd = open(fname, oflags, omode)) == -1) { 115206713Sjmallett if (errno != ENOENT) { 116216972Sjmallett warn("%s", fname); 117178172Simp error++; 118178172Simp } 119178172Simp continue; 120178172Simp } 121178172Simp if (do_relative) { 122178172Simp if (fstat(fd, &sb) == -1) { 123178172Simp warn("%s", fname); 124178172Simp error++; 125178172Simp continue; 126178172Simp } 127178172Simp oflow = sb.st_size + rsize; 128178172Simp if (oflow < (sb.st_size + rsize)) { 129178172Simp errno = EFBIG; 130178172Simp warn("%s", fname); 131178172Simp error++; 132178172Simp continue; 133178172Simp } 134178172Simp tsize = oflow; 135178172Simp } 136178172Simp if (tsize < 0) 137178172Simp tsize = 0; 138218383Sjmallett 139218383Sjmallett if (ftruncate(fd, tsize) == -1) { 140218383Sjmallett warn("%s", fname); 141218383Sjmallett error++; 142218383Sjmallett continue; 143218383Sjmallett } 144218383Sjmallett } 145218383Sjmallett if (fd != -1) 146218383Sjmallett close(fd); 147218383Sjmallett 148218383Sjmallett return error ? EXIT_FAILURE : EXIT_SUCCESS; 149218383Sjmallett} 150218383Sjmallett 151218383Sjmallett/* 152218383Sjmallett * Return the numeric value of a string given in the form [+-][0-9]+[GMKT] 153218383Sjmallett * or -1 on format error or overflow. 154218383Sjmallett */ 155218383Sjmallettstatic int 156218383Sjmallettparselength(char *ls, off_t *sz) 157218383Sjmallett{ 158206713Sjmallett off_t length, oflow; 159216972Sjmallett int lsign; 160216972Sjmallett 161216972Sjmallett length = 0; 162218383Sjmallett lsign = 1; 163218383Sjmallett 164218383Sjmallett switch (*ls) { 165218383Sjmallett case '-': 166218383Sjmallett lsign = -1; 167218383Sjmallett case '+': 168206713Sjmallett ls++; 169218383Sjmallett } 170217354Sjchandra 171217354Sjchandra#define ASSIGN_CHK_OFLOW(x, y) if (x < y) return -1; y = x 172217354Sjchandra /* 173217354Sjchandra * Calculate the value of the decimal digit string, failing 174216972Sjmallett * on overflow. 175178172Simp */ 176216972Sjmallett while (isdigit(*ls)) { 177218383Sjmallett oflow = length * 10 + *ls++ - '0'; 178178172Simp ASSIGN_CHK_OFLOW(oflow, length); 179178172Simp } 180216972Sjmallett 181178172Simp switch (*ls) { 182178172Simp case 'T': 183178172Simp case 't': 184178172Simp oflow = length * 1024; 185178172Simp ASSIGN_CHK_OFLOW(oflow, length); 186178172Simp case 'G': 187178172Simp case 'g': 188178172Simp oflow = length * 1024; 189178172Simp ASSIGN_CHK_OFLOW(oflow, length); 190178172Simp case 'M': 191178172Simp case 'm': 192178172Simp oflow = length * 1024; 193178172Simp ASSIGN_CHK_OFLOW(oflow, length); 194178172Simp case 'K': 195178172Simp case 'k': 196178172Simp if (ls[1] != '\0') 197178172Simp return -1; 198178172Simp oflow = length * 1024; 199178172Simp ASSIGN_CHK_OFLOW(oflow, length); 200178172Simp case '\0': 201178172Simp break; 202216972Sjmallett default: 203202031Simp return -1; 204206829Sjmallett } 205202031Simp 206202031Simp *sz = length * lsign; 207202031Simp return 0; 208202031Simp} 209202031Simp 210202031Simpstatic void 211202031Simpusage(void) 212202031Simp{ 213206829Sjmallett fprintf(stderr, "%s\n%s\n", 214202031Simp "usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ...", 215202031Simp " truncate [-c] -r rfile file ..."); 216202031Simp exit(EXIT_FAILURE); 217202031Simp} 218202031Simp