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 * 7*5ee2c357SKa Ho Ng * Copyright (c) 2021 The FreeBSD Foundation 8*5ee2c357SKa Ho Ng * 9*5ee2c357SKa Ho Ng * Portions of this software were developed by Ka Ho Ng <khng@FreeBSD.org> 10*5ee2c357SKa Ho Ng * under sponsorship from the FreeBSD Foundation. 11*5ee2c357SKa Ho Ng * 12edeb84a1SSheldon Hearn * Redistribution and use in source and binary forms, with or without 13edeb84a1SSheldon Hearn * modification, are permitted provided that the following conditions 14edeb84a1SSheldon Hearn * are met: 15edeb84a1SSheldon Hearn * 1. Redistributions of source code must retain the above copyright 16edeb84a1SSheldon Hearn * notice, this list of conditions and the following disclaimer. 17edeb84a1SSheldon Hearn * 2. Redistributions in binary form must reproduce the above copyright 18edeb84a1SSheldon Hearn * notice, this list of conditions and the following disclaimer in the 19edeb84a1SSheldon Hearn * documentation and/or other materials provided with the distribution. 20edeb84a1SSheldon Hearn * 21edeb84a1SSheldon Hearn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22edeb84a1SSheldon Hearn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23edeb84a1SSheldon Hearn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24edeb84a1SSheldon Hearn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25edeb84a1SSheldon Hearn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26edeb84a1SSheldon Hearn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27edeb84a1SSheldon Hearn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28edeb84a1SSheldon Hearn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29edeb84a1SSheldon Hearn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30edeb84a1SSheldon Hearn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31edeb84a1SSheldon Hearn * SUCH DAMAGE. 32edeb84a1SSheldon Hearn * 33edeb84a1SSheldon Hearn */ 34edeb84a1SSheldon Hearn 356b88e76bSSheldon Hearn static const char rcsid[] = 366b88e76bSSheldon Hearn "$FreeBSD$"; 376b88e76bSSheldon Hearn 38edeb84a1SSheldon Hearn #include <sys/stat.h> 39edeb84a1SSheldon Hearn 40edeb84a1SSheldon Hearn #include <ctype.h> 41edeb84a1SSheldon Hearn #include <err.h> 42edeb84a1SSheldon Hearn #include <errno.h> 43edeb84a1SSheldon Hearn #include <fcntl.h> 44edeb84a1SSheldon Hearn #include <stdio.h> 45edeb84a1SSheldon Hearn #include <stdlib.h> 46edeb84a1SSheldon Hearn #include <unistd.h> 47edeb84a1SSheldon Hearn 4832bdc2b6SMaxim Sobolev #include <libutil.h> 4932bdc2b6SMaxim Sobolev 503f330d7dSWarner Losh static void usage(void); 51edeb84a1SSheldon Hearn 52edeb84a1SSheldon Hearn int 53edeb84a1SSheldon Hearn main(int argc, char **argv) 54edeb84a1SSheldon Hearn { 55edeb84a1SSheldon Hearn struct stat sb; 56edeb84a1SSheldon Hearn mode_t omode; 57*5ee2c357SKa Ho Ng off_t oflow, rsize, sz, tsize, round, off, len; 58fc96358cSJilles Tjoelker uint64_t usz; 59*5ee2c357SKa Ho Ng int ch, error, fd, oflags, r; 60*5ee2c357SKa Ho Ng int do_dealloc; 61*5ee2c357SKa Ho Ng int do_truncate; 62dde27dbcSEmmanuel Vadot int no_create; 63dde27dbcSEmmanuel Vadot int do_relative; 6410173270SEmmanuel Vadot int do_round; 65dde27dbcSEmmanuel Vadot int do_refer; 66dde27dbcSEmmanuel Vadot int got_size; 67edeb84a1SSheldon Hearn char *fname, *rname; 68*5ee2c357SKa Ho Ng struct spacectl_range sr; 69edeb84a1SSheldon Hearn 70d59e8ae8SColin Percival fd = -1; 71*5ee2c357SKa Ho Ng rsize = tsize = sz = off = 0; 72*5ee2c357SKa Ho Ng len = -1; 73*5ee2c357SKa Ho Ng do_dealloc = no_create = do_relative = do_round = do_refer = 74*5ee2c357SKa Ho Ng got_size = 0; 75*5ee2c357SKa Ho Ng do_truncate = 1; 76*5ee2c357SKa Ho Ng error = r = 0; 77b86e825aSSheldon Hearn rname = NULL; 78*5ee2c357SKa Ho Ng while ((ch = getopt(argc, argv, "cdr:s:o:l:")) != -1) 79edeb84a1SSheldon Hearn switch (ch) { 80edeb84a1SSheldon Hearn case 'c': 81b86e825aSSheldon Hearn no_create = 1; 82edeb84a1SSheldon Hearn break; 83*5ee2c357SKa Ho Ng case 'd': 84*5ee2c357SKa Ho Ng do_dealloc = 1; 85*5ee2c357SKa Ho Ng do_truncate = 0; 86*5ee2c357SKa Ho Ng break; 87edeb84a1SSheldon Hearn case 'r': 88b86e825aSSheldon Hearn do_refer = 1; 89edeb84a1SSheldon Hearn rname = optarg; 90edeb84a1SSheldon Hearn break; 91edeb84a1SSheldon Hearn case 's': 9210173270SEmmanuel Vadot if (*optarg == '+' || *optarg == '-') { 9310173270SEmmanuel Vadot do_relative = 1; 9410173270SEmmanuel Vadot } else if (*optarg == '%' || *optarg == '/') { 9510173270SEmmanuel Vadot do_round = 1; 9610173270SEmmanuel Vadot } 9710173270SEmmanuel Vadot if (expand_number(do_relative || do_round ? 9810173270SEmmanuel Vadot optarg + 1 : optarg, 99fc96358cSJilles Tjoelker &usz) == -1 || (off_t)usz < 0) 100edeb84a1SSheldon Hearn errx(EXIT_FAILURE, 101edeb84a1SSheldon Hearn "invalid size argument `%s'", optarg); 102fc96358cSJilles Tjoelker 10310173270SEmmanuel Vadot sz = (*optarg == '-' || *optarg == '/') ? 10410173270SEmmanuel Vadot -(off_t)usz : (off_t)usz; 105b86e825aSSheldon Hearn got_size = 1; 106edeb84a1SSheldon Hearn break; 107*5ee2c357SKa Ho Ng case 'o': 108*5ee2c357SKa Ho Ng if (expand_number(optarg, &usz) == -1 || 109*5ee2c357SKa Ho Ng (off_t)usz < 0) 110*5ee2c357SKa Ho Ng errx(EXIT_FAILURE, 111*5ee2c357SKa Ho Ng "invalid offset argument `%s'", optarg); 112*5ee2c357SKa Ho Ng 113*5ee2c357SKa Ho Ng off = usz; 114*5ee2c357SKa Ho Ng break; 115*5ee2c357SKa Ho Ng case 'l': 116*5ee2c357SKa Ho Ng if (expand_number(optarg, &usz) == -1 || 117*5ee2c357SKa Ho Ng (off_t)usz <= 0) 118*5ee2c357SKa Ho Ng errx(EXIT_FAILURE, 119*5ee2c357SKa Ho Ng "invalid length argument `%s'", optarg); 120*5ee2c357SKa Ho Ng 121*5ee2c357SKa Ho Ng len = usz; 122*5ee2c357SKa Ho Ng break; 123edeb84a1SSheldon Hearn default: 124edeb84a1SSheldon Hearn usage(); 125edeb84a1SSheldon Hearn /* NOTREACHED */ 126edeb84a1SSheldon Hearn } 127edeb84a1SSheldon Hearn 128edeb84a1SSheldon Hearn argv += optind; 129edeb84a1SSheldon Hearn argc -= optind; 130edeb84a1SSheldon Hearn 131edeb84a1SSheldon Hearn /* 132*5ee2c357SKa Ho Ng * Exactly one of do_refer, got_size or do_dealloc must be specified. 133*5ee2c357SKa Ho Ng * Since do_relative implies got_size, do_relative, do_refer and 134*5ee2c357SKa Ho Ng * do_dealloc are also mutually exclusive. If do_dealloc is specified, 135*5ee2c357SKa Ho Ng * the length argument must be set. See usage() for allowed 136*5ee2c357SKa Ho Ng * invocations. 137edeb84a1SSheldon Hearn */ 138*5ee2c357SKa Ho Ng if (argc < 1 || do_refer + got_size + do_dealloc != 1 || 139*5ee2c357SKa Ho Ng (do_dealloc == 1 && len == -1)) 140edeb84a1SSheldon Hearn usage(); 141*5ee2c357SKa Ho Ng if (do_refer == 1) { 142edeb84a1SSheldon Hearn if (stat(rname, &sb) == -1) 143edeb84a1SSheldon Hearn err(EXIT_FAILURE, "%s", rname); 144edeb84a1SSheldon Hearn tsize = sb.st_size; 145*5ee2c357SKa Ho Ng } else if (do_relative == 1 || do_round == 1) 146edeb84a1SSheldon Hearn rsize = sz; 147*5ee2c357SKa Ho Ng else if (do_dealloc == 0) 148edeb84a1SSheldon Hearn tsize = sz; 149edeb84a1SSheldon Hearn 150edeb84a1SSheldon Hearn if (no_create) 151edeb84a1SSheldon Hearn oflags = O_WRONLY; 152edeb84a1SSheldon Hearn else 153edeb84a1SSheldon Hearn oflags = O_WRONLY | O_CREAT; 154edeb84a1SSheldon Hearn omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 155edeb84a1SSheldon Hearn 156edeb84a1SSheldon Hearn while ((fname = *argv++) != NULL) { 157a39846b5SMaxim Konovalov if (fd != -1) 158a39846b5SMaxim Konovalov close(fd); 159edeb84a1SSheldon Hearn if ((fd = open(fname, oflags, omode)) == -1) { 160edeb84a1SSheldon Hearn if (errno != ENOENT) { 161edeb84a1SSheldon Hearn warn("%s", fname); 162edeb84a1SSheldon Hearn error++; 163edeb84a1SSheldon Hearn } 164edeb84a1SSheldon Hearn continue; 165edeb84a1SSheldon Hearn } 166*5ee2c357SKa Ho Ng if (do_relative == 1) { 167edeb84a1SSheldon Hearn if (fstat(fd, &sb) == -1) { 168edeb84a1SSheldon Hearn warn("%s", fname); 169edeb84a1SSheldon Hearn error++; 170edeb84a1SSheldon Hearn continue; 171edeb84a1SSheldon Hearn } 172edeb84a1SSheldon Hearn oflow = sb.st_size + rsize; 173edeb84a1SSheldon Hearn if (oflow < (sb.st_size + rsize)) { 174edeb84a1SSheldon Hearn errno = EFBIG; 175edeb84a1SSheldon Hearn warn("%s", fname); 176edeb84a1SSheldon Hearn error++; 177edeb84a1SSheldon Hearn continue; 178edeb84a1SSheldon Hearn } 179edeb84a1SSheldon Hearn tsize = oflow; 180edeb84a1SSheldon Hearn } 181*5ee2c357SKa Ho Ng if (do_round == 1) { 18210173270SEmmanuel Vadot if (fstat(fd, &sb) == -1) { 18310173270SEmmanuel Vadot warn("%s", fname); 18410173270SEmmanuel Vadot error++; 18510173270SEmmanuel Vadot continue; 18610173270SEmmanuel Vadot } 18710173270SEmmanuel Vadot sz = rsize; 18810173270SEmmanuel Vadot if (sz < 0) 18910173270SEmmanuel Vadot sz = -sz; 19010173270SEmmanuel Vadot if (sb.st_size % sz) { 19110173270SEmmanuel Vadot round = sb.st_size / sz; 19210173270SEmmanuel Vadot if (round != sz && rsize < 0) 19310173270SEmmanuel Vadot round--; 19410173270SEmmanuel Vadot else if (rsize > 0) 19510173270SEmmanuel Vadot round++; 19610173270SEmmanuel Vadot tsize = (round < 0 ? 0 : round) * sz; 19710173270SEmmanuel Vadot } else 19810173270SEmmanuel Vadot tsize = sb.st_size; 19910173270SEmmanuel Vadot } 200edeb84a1SSheldon Hearn if (tsize < 0) 201edeb84a1SSheldon Hearn tsize = 0; 202edeb84a1SSheldon Hearn 203*5ee2c357SKa Ho Ng if (do_dealloc == 1) { 204*5ee2c357SKa Ho Ng sr.r_offset = off; 205*5ee2c357SKa Ho Ng sr.r_len = len; 206*5ee2c357SKa Ho Ng r = fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, &sr); 207*5ee2c357SKa Ho Ng } 208*5ee2c357SKa Ho Ng if (do_truncate == 1) 209*5ee2c357SKa Ho Ng r = ftruncate(fd, tsize); 210*5ee2c357SKa Ho Ng if (r == -1) { 211edeb84a1SSheldon Hearn warn("%s", fname); 212edeb84a1SSheldon Hearn error++; 213edeb84a1SSheldon Hearn } 214edeb84a1SSheldon Hearn } 215a39846b5SMaxim Konovalov if (fd != -1) 216a39846b5SMaxim Konovalov close(fd); 217edeb84a1SSheldon Hearn 21889c0d2b1SKa Ho Ng return (error ? EXIT_FAILURE : EXIT_SUCCESS); 219edeb84a1SSheldon Hearn } 220edeb84a1SSheldon Hearn 221edeb84a1SSheldon Hearn static void 222edeb84a1SSheldon Hearn usage(void) 223edeb84a1SSheldon Hearn { 224*5ee2c357SKa Ho Ng fprintf(stderr, "%s\n%s\n%s\n", 22510173270SEmmanuel Vadot "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...", 226*5ee2c357SKa Ho Ng " truncate [-c] -r rfile file ...", 227*5ee2c357SKa Ho Ng " truncate [-c] -d [-o offset[K|k|M|m|G|g|T|t]] -l length[K|k|M|m|G|g|T|t] file ..."); 228edeb84a1SSheldon Hearn exit(EXIT_FAILURE); 229edeb84a1SSheldon Hearn } 230