1188887Sdelphij/*-
263790Ssheldonh * Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>.
363790Ssheldonh * All rights reserved.
463437Ssheldonh *
563437Ssheldonh * Redistribution and use in source and binary forms, with or without
663437Ssheldonh * modification, are permitted provided that the following conditions
763437Ssheldonh * are met:
863437Ssheldonh * 1. Redistributions of source code must retain the above copyright
963437Ssheldonh *    notice, this list of conditions and the following disclaimer.
1063437Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
1163437Ssheldonh *    notice, this list of conditions and the following disclaimer in the
1263437Ssheldonh *    documentation and/or other materials provided with the distribution.
1363437Ssheldonh *
1463437Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1563437Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1663437Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1763437Ssheldonh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1863437Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1963437Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2063437Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2163437Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2263437Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2363437Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2463437Ssheldonh * SUCH DAMAGE.
2563437Ssheldonh *
2663437Ssheldonh */
2763437Ssheldonh
2863790Ssheldonh#ifndef lint
2963790Ssheldonhstatic const char rcsid[] =
3063790Ssheldonh    "$FreeBSD$";
3163790Ssheldonh#endif
3263790Ssheldonh
3363437Ssheldonh#include <sys/stat.h>
3463437Ssheldonh
3563437Ssheldonh#include <ctype.h>
3663437Ssheldonh#include <err.h>
3763437Ssheldonh#include <errno.h>
3863437Ssheldonh#include <fcntl.h>
3963437Ssheldonh#include <stdio.h>
4063437Ssheldonh#include <stdlib.h>
4163437Ssheldonh#include <unistd.h>
4263437Ssheldonh
43204654Ssobomax#include <libutil.h>
44204654Ssobomax
4592922Simpstatic void	usage(void);
4663437Ssheldonh
4763437Ssheldonhstatic int	no_create;
4863437Ssheldonhstatic int	do_relative;
4963437Ssheldonhstatic int	do_refer;
5063437Ssheldonhstatic int	got_size;
5163437Ssheldonh
5263437Ssheldonhint
5363437Ssheldonhmain(int argc, char **argv)
5463437Ssheldonh{
5563437Ssheldonh	struct stat	sb;
5663437Ssheldonh	mode_t	omode;
57204654Ssobomax	off_t	oflow, rsize, tsize;
58204654Ssobomax	int64_t sz;
5963437Ssheldonh	int	ch, error, fd, oflags;
6063437Ssheldonh	char   *fname, *rname;
6163437Ssheldonh
62181279Scperciva	fd = -1;
63188887Sdelphij	rsize = tsize = sz = 0;
6463817Ssheldonh	error = 0;
6563816Ssheldonh	rname = NULL;
6663437Ssheldonh	while ((ch = getopt(argc, argv, "cr:s:")) != -1)
6763437Ssheldonh		switch (ch) {
6863437Ssheldonh		case 'c':
6963817Ssheldonh			no_create = 1;
7063437Ssheldonh			break;
7163437Ssheldonh		case 'r':
7263817Ssheldonh			do_refer = 1;
7363437Ssheldonh			rname = optarg;
7463437Ssheldonh			break;
7563437Ssheldonh		case 's':
76204654Ssobomax			if (expand_number(optarg, &sz) == -1)
7763437Ssheldonh				errx(EXIT_FAILURE,
7863437Ssheldonh				    "invalid size argument `%s'", optarg);
7963437Ssheldonh			if (*optarg == '+' || *optarg == '-')
8063817Ssheldonh				do_relative = 1;
8163817Ssheldonh			got_size = 1;
8263437Ssheldonh			break;
8363437Ssheldonh		default:
8463437Ssheldonh			usage();
8563437Ssheldonh			/* NOTREACHED */
8663437Ssheldonh		}
8763437Ssheldonh
8863437Ssheldonh	argv += optind;
8963437Ssheldonh	argc -= optind;
9063437Ssheldonh
9163437Ssheldonh	/*
9263437Ssheldonh	 * Exactly one of do_refer or got_size must be specified.  Since
9363437Ssheldonh	 * do_relative implies got_size, do_relative and do_refer are
9463437Ssheldonh	 * also mutually exclusive.  See usage() for allowed invocations.
9563437Ssheldonh	 */
9663817Ssheldonh	if (do_refer + got_size != 1 || argc < 1)
9763437Ssheldonh		usage();
9863437Ssheldonh	if (do_refer) {
9963437Ssheldonh		if (stat(rname, &sb) == -1)
10063437Ssheldonh			err(EXIT_FAILURE, "%s", rname);
10163437Ssheldonh		tsize = sb.st_size;
10263817Ssheldonh	} else if (do_relative)
10363817Ssheldonh		rsize = sz;
10463817Ssheldonh	else
10563817Ssheldonh		tsize = sz;
10663437Ssheldonh
10763437Ssheldonh	if (no_create)
10863437Ssheldonh		oflags = O_WRONLY;
10963437Ssheldonh	else
11063437Ssheldonh		oflags = O_WRONLY | O_CREAT;
11163437Ssheldonh	omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
11263437Ssheldonh
11363437Ssheldonh	while ((fname = *argv++) != NULL) {
114162412Smaxim		if (fd != -1)
115162412Smaxim			close(fd);
11663437Ssheldonh		if ((fd = open(fname, oflags, omode)) == -1) {
11763437Ssheldonh			if (errno != ENOENT) {
11863437Ssheldonh				warn("%s", fname);
11963437Ssheldonh				error++;
12063437Ssheldonh			}
12163437Ssheldonh			continue;
12263437Ssheldonh		}
12363437Ssheldonh		if (do_relative) {
12463437Ssheldonh			if (fstat(fd, &sb) == -1) {
12563437Ssheldonh				warn("%s", fname);
12663437Ssheldonh				error++;
12763437Ssheldonh				continue;
12863437Ssheldonh			}
12963437Ssheldonh			oflow = sb.st_size + rsize;
13063437Ssheldonh			if (oflow < (sb.st_size + rsize)) {
13163437Ssheldonh				errno = EFBIG;
13263437Ssheldonh				warn("%s", fname);
13363437Ssheldonh				error++;
13463437Ssheldonh				continue;
13563437Ssheldonh			}
13663437Ssheldonh			tsize = oflow;
13763437Ssheldonh		}
13863437Ssheldonh		if (tsize < 0)
13963437Ssheldonh			tsize = 0;
14063437Ssheldonh
14163437Ssheldonh		if (ftruncate(fd, tsize) == -1) {
14263437Ssheldonh			warn("%s", fname);
14363437Ssheldonh			error++;
14463437Ssheldonh			continue;
14563437Ssheldonh		}
146162412Smaxim	}
147162412Smaxim	if (fd != -1)
14863774Ssheldonh		close(fd);
14963437Ssheldonh
15063437Ssheldonh	return error ? EXIT_FAILURE : EXIT_SUCCESS;
15163437Ssheldonh}
15263437Ssheldonh
15363437Ssheldonhstatic void
15463437Ssheldonhusage(void)
15563437Ssheldonh{
15663437Ssheldonh	fprintf(stderr, "%s\n%s\n",
157162114Sceri	    "usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ...",
15863437Ssheldonh	    "       truncate [-c] -r rfile file ...");
15963437Ssheldonh	exit(EXIT_FAILURE);
16063437Ssheldonh}
161