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