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 int 50 main(int argc, char **argv) 51 { 52 struct stat sb; 53 mode_t omode; 54 off_t oflow, rsize, sz, tsize; 55 uint64_t usz; 56 int ch, error, fd, oflags; 57 int no_create; 58 int do_relative; 59 int do_round; 60 int do_refer; 61 int got_size; 62 int round; 63 char *fname, *rname; 64 65 fd = -1; 66 rsize = tsize = sz = 0; 67 no_create = do_relative = do_round = do_refer = got_size = 0; 68 error = 0; 69 rname = NULL; 70 while ((ch = getopt(argc, argv, "cr:s:")) != -1) 71 switch (ch) { 72 case 'c': 73 no_create = 1; 74 break; 75 case 'r': 76 do_refer = 1; 77 rname = optarg; 78 break; 79 case 's': 80 if (*optarg == '+' || *optarg == '-') { 81 do_relative = 1; 82 } else if (*optarg == '%' || *optarg == '/') { 83 do_round = 1; 84 } 85 if (expand_number(do_relative || do_round ? 86 optarg + 1 : optarg, 87 &usz) == -1 || (off_t)usz < 0) 88 errx(EXIT_FAILURE, 89 "invalid size argument `%s'", optarg); 90 91 sz = (*optarg == '-' || *optarg == '/') ? 92 -(off_t)usz : (off_t)usz; 93 got_size = 1; 94 break; 95 default: 96 usage(); 97 /* NOTREACHED */ 98 } 99 100 argv += optind; 101 argc -= optind; 102 103 /* 104 * Exactly one of do_refer or got_size must be specified. Since 105 * do_relative implies got_size, do_relative and do_refer are 106 * also mutually exclusive. See usage() for allowed invocations. 107 */ 108 if (do_refer + got_size != 1 || argc < 1) 109 usage(); 110 if (do_refer) { 111 if (stat(rname, &sb) == -1) 112 err(EXIT_FAILURE, "%s", rname); 113 tsize = sb.st_size; 114 } else if (do_relative || do_round) 115 rsize = sz; 116 else 117 tsize = sz; 118 119 if (no_create) 120 oflags = O_WRONLY; 121 else 122 oflags = O_WRONLY | O_CREAT; 123 omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 124 125 while ((fname = *argv++) != NULL) { 126 if (fd != -1) 127 close(fd); 128 if ((fd = open(fname, oflags, omode)) == -1) { 129 if (errno != ENOENT) { 130 warn("%s", fname); 131 error++; 132 } 133 continue; 134 } 135 if (do_relative) { 136 if (fstat(fd, &sb) == -1) { 137 warn("%s", fname); 138 error++; 139 continue; 140 } 141 oflow = sb.st_size + rsize; 142 if (oflow < (sb.st_size + rsize)) { 143 errno = EFBIG; 144 warn("%s", fname); 145 error++; 146 continue; 147 } 148 tsize = oflow; 149 } 150 if (do_round) { 151 if (fstat(fd, &sb) == -1) { 152 warn("%s", fname); 153 error++; 154 continue; 155 } 156 sz = rsize; 157 if (sz < 0) 158 sz = -sz; 159 if (sb.st_size % sz) { 160 round = sb.st_size / sz; 161 if (round != sz && rsize < 0) 162 round--; 163 else if (rsize > 0) 164 round++; 165 tsize = (round < 0 ? 0 : round) * sz; 166 } else 167 tsize = sb.st_size; 168 } 169 if (tsize < 0) 170 tsize = 0; 171 172 if (ftruncate(fd, tsize) == -1) { 173 warn("%s", fname); 174 error++; 175 continue; 176 } 177 } 178 if (fd != -1) 179 close(fd); 180 181 return error ? EXIT_FAILURE : EXIT_SUCCESS; 182 } 183 184 static void 185 usage(void) 186 { 187 fprintf(stderr, "%s\n%s\n", 188 "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...", 189 " truncate [-c] -r rfile file ..."); 190 exit(EXIT_FAILURE); 191 } 192