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