1188887Sdelphij/*- 263790Ssheldonh * Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>. 363790Ssheldonh * All rights reserved. 463437Ssheldonh * 563437Ssheldonh * Redistribution and use in source and binary forms, with or without 663437Ssheldonh * modification, are permitted provided that the following conditions 763437Ssheldonh * are met: 863437Ssheldonh * 1. Redistributions of source code must retain the above copyright 963437Ssheldonh * notice, this list of conditions and the following disclaimer. 1063437Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright 1163437Ssheldonh * notice, this list of conditions and the following disclaimer in the 1263437Ssheldonh * documentation and/or other materials provided with the distribution. 1363437Ssheldonh * 1463437Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1563437Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1663437Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1763437Ssheldonh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1863437Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1963437Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2063437Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2163437Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2263437Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2363437Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2463437Ssheldonh * SUCH DAMAGE. 2563437Ssheldonh * 2663437Ssheldonh */ 2763437Ssheldonh 2863790Ssheldonh#ifndef lint 2963790Ssheldonhstatic const char rcsid[] = 3063790Ssheldonh "$FreeBSD$"; 3163790Ssheldonh#endif 3263790Ssheldonh 3363437Ssheldonh#include <sys/stat.h> 3463437Ssheldonh 3563437Ssheldonh#include <ctype.h> 3663437Ssheldonh#include <err.h> 3763437Ssheldonh#include <errno.h> 3863437Ssheldonh#include <fcntl.h> 3963437Ssheldonh#include <stdio.h> 4063437Ssheldonh#include <stdlib.h> 4163437Ssheldonh#include <unistd.h> 4263437Ssheldonh 43204654Ssobomax#include <libutil.h> 44204654Ssobomax 4592922Simpstatic void usage(void); 4663437Ssheldonh 4763437Ssheldonhstatic int no_create; 4863437Ssheldonhstatic int do_relative; 4963437Ssheldonhstatic int do_refer; 5063437Ssheldonhstatic int got_size; 5163437Ssheldonh 5263437Ssheldonhint 5363437Ssheldonhmain(int argc, char **argv) 5463437Ssheldonh{ 5563437Ssheldonh struct stat sb; 5663437Ssheldonh mode_t omode; 57204654Ssobomax off_t oflow, rsize, tsize; 58204654Ssobomax int64_t sz; 5963437Ssheldonh int ch, error, fd, oflags; 6063437Ssheldonh char *fname, *rname; 6163437Ssheldonh 62181279Scperciva fd = -1; 63188887Sdelphij rsize = tsize = sz = 0; 6463817Ssheldonh error = 0; 6563816Ssheldonh rname = NULL; 6663437Ssheldonh while ((ch = getopt(argc, argv, "cr:s:")) != -1) 6763437Ssheldonh switch (ch) { 6863437Ssheldonh case 'c': 6963817Ssheldonh no_create = 1; 7063437Ssheldonh break; 7163437Ssheldonh case 'r': 7263817Ssheldonh do_refer = 1; 7363437Ssheldonh rname = optarg; 7463437Ssheldonh break; 7563437Ssheldonh case 's': 76204654Ssobomax if (expand_number(optarg, &sz) == -1) 7763437Ssheldonh errx(EXIT_FAILURE, 7863437Ssheldonh "invalid size argument `%s'", optarg); 7963437Ssheldonh if (*optarg == '+' || *optarg == '-') 8063817Ssheldonh do_relative = 1; 8163817Ssheldonh got_size = 1; 8263437Ssheldonh break; 8363437Ssheldonh default: 8463437Ssheldonh usage(); 8563437Ssheldonh /* NOTREACHED */ 8663437Ssheldonh } 8763437Ssheldonh 8863437Ssheldonh argv += optind; 8963437Ssheldonh argc -= optind; 9063437Ssheldonh 9163437Ssheldonh /* 9263437Ssheldonh * Exactly one of do_refer or got_size must be specified. Since 9363437Ssheldonh * do_relative implies got_size, do_relative and do_refer are 9463437Ssheldonh * also mutually exclusive. See usage() for allowed invocations. 9563437Ssheldonh */ 9663817Ssheldonh if (do_refer + got_size != 1 || argc < 1) 9763437Ssheldonh usage(); 9863437Ssheldonh if (do_refer) { 9963437Ssheldonh if (stat(rname, &sb) == -1) 10063437Ssheldonh err(EXIT_FAILURE, "%s", rname); 10163437Ssheldonh tsize = sb.st_size; 10263817Ssheldonh } else if (do_relative) 10363817Ssheldonh rsize = sz; 10463817Ssheldonh else 10563817Ssheldonh tsize = sz; 10663437Ssheldonh 10763437Ssheldonh if (no_create) 10863437Ssheldonh oflags = O_WRONLY; 10963437Ssheldonh else 11063437Ssheldonh oflags = O_WRONLY | O_CREAT; 11163437Ssheldonh omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 11263437Ssheldonh 11363437Ssheldonh while ((fname = *argv++) != NULL) { 114162412Smaxim if (fd != -1) 115162412Smaxim close(fd); 11663437Ssheldonh if ((fd = open(fname, oflags, omode)) == -1) { 11763437Ssheldonh if (errno != ENOENT) { 11863437Ssheldonh warn("%s", fname); 11963437Ssheldonh error++; 12063437Ssheldonh } 12163437Ssheldonh continue; 12263437Ssheldonh } 12363437Ssheldonh if (do_relative) { 12463437Ssheldonh if (fstat(fd, &sb) == -1) { 12563437Ssheldonh warn("%s", fname); 12663437Ssheldonh error++; 12763437Ssheldonh continue; 12863437Ssheldonh } 12963437Ssheldonh oflow = sb.st_size + rsize; 13063437Ssheldonh if (oflow < (sb.st_size + rsize)) { 13163437Ssheldonh errno = EFBIG; 13263437Ssheldonh warn("%s", fname); 13363437Ssheldonh error++; 13463437Ssheldonh continue; 13563437Ssheldonh } 13663437Ssheldonh tsize = oflow; 13763437Ssheldonh } 13863437Ssheldonh if (tsize < 0) 13963437Ssheldonh tsize = 0; 14063437Ssheldonh 14163437Ssheldonh if (ftruncate(fd, tsize) == -1) { 14263437Ssheldonh warn("%s", fname); 14363437Ssheldonh error++; 14463437Ssheldonh continue; 14563437Ssheldonh } 146162412Smaxim } 147162412Smaxim if (fd != -1) 14863774Ssheldonh close(fd); 14963437Ssheldonh 15063437Ssheldonh return error ? EXIT_FAILURE : EXIT_SUCCESS; 15163437Ssheldonh} 15263437Ssheldonh 15363437Ssheldonhstatic void 15463437Ssheldonhusage(void) 15563437Ssheldonh{ 15663437Ssheldonh fprintf(stderr, "%s\n%s\n", 157162114Sceri "usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ...", 15863437Ssheldonh " truncate [-c] -r rfile file ..."); 15963437Ssheldonh exit(EXIT_FAILURE); 16063437Ssheldonh} 161