xref: /minix3/minix/commands/truncate/truncate.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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