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