summaryrefslogtreecommitdiffstats
path: root/usr.bin/truncate/truncate.c
diff options
context:
space:
mode:
authorsheldonh <sheldonh@FreeBSD.org>2000-07-18 17:03:58 +0000
committersheldonh <sheldonh@FreeBSD.org>2000-07-18 17:03:58 +0000
commit5df055483d2201b685994082d68c1235a690c99a (patch)
tree8ec7aa73a358269417e0aa48c324f93db82f4b99 /usr.bin/truncate/truncate.c
parentbbe00ac533441c4cafca8001a4e8d43cf41406d5 (diff)
downloadFreeBSD-src-5df055483d2201b685994082d68c1235a690c99a.zip
FreeBSD-src-5df055483d2201b685994082d68c1235a690c99a.tar.gz
Import the new truncate(1) utility.
Approved by: jdp
Diffstat (limited to 'usr.bin/truncate/truncate.c')
-rw-r--r--usr.bin/truncate/truncate.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/usr.bin/truncate/truncate.c b/usr.bin/truncate/truncate.c
new file mode 100644
index 0000000..0b6fef4
--- /dev/null
+++ b/usr.bin/truncate/truncate.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2000 FreeBSD, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static off_t parselength __P((char *, off_t *));
+static void usage __P((void));
+
+static int no_create;
+static int do_relative;
+static int do_refer;
+static int got_size;
+
+int
+main(int argc, char **argv)
+{
+ struct stat sb;
+ mode_t omode;
+ off_t oflow, rsize, sz, tsize;
+ int ch, error, fd, oflags;
+ char *fname, *rname;
+
+ error = 0;
+ while ((ch = getopt(argc, argv, "cr:s:")) != -1)
+ switch (ch) {
+ case 'c':
+ no_create++;
+ break;
+ case 'r':
+ do_refer++;
+ rname = optarg;
+ break;
+ case 's':
+ if (parselength(optarg, &sz) == -1)
+ errx(EXIT_FAILURE,
+ "invalid size argument `%s'", optarg);
+ if (*optarg == '+' || *optarg == '-')
+ do_relative++;
+ got_size++;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ /*
+ * Exactly one of do_refer or got_size must be specified. Since
+ * do_relative implies got_size, do_relative and do_refer are
+ * also mutually exclusive. See usage() for allowed invocations.
+ */
+ if (!(do_refer || got_size) || (do_refer && got_size) || argc < 1)
+ usage();
+ if (do_refer) {
+ if (stat(rname, &sb) == -1)
+ err(EXIT_FAILURE, "%s", rname);
+ tsize = sb.st_size;
+ } else if (got_size) {
+ if (do_relative)
+ rsize = sz;
+ else
+ tsize = sz;
+ }
+
+ if (no_create)
+ oflags = O_WRONLY;
+ else
+ oflags = O_WRONLY | O_CREAT;
+ omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+
+ while ((fname = *argv++) != NULL) {
+ if ((fd = open(fname, oflags, omode)) == -1) {
+ if (errno != ENOENT) {
+ warn("%s", fname);
+ error++;
+ }
+ continue;
+ }
+ if (do_relative) {
+ if (fstat(fd, &sb) == -1) {
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ oflow = sb.st_size + rsize;
+ if (oflow < (sb.st_size + rsize)) {
+ errno = EFBIG;
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ tsize = oflow;
+ }
+ if (tsize < 0)
+ tsize = 0;
+
+ if (ftruncate(fd, tsize) == -1) {
+ warn("%s", fname);
+ error++;
+ continue;
+ }
+ }
+
+ return error ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/*
+ * Return the numeric value of a string given in the form [+-][0-9]+[GMK]
+ * or -1 on format error or overflow.
+ */
+static off_t
+parselength(char *ls, off_t *sz)
+{
+ off_t length, oflow;
+ int lsign;
+
+ length = 0;
+ lsign = 1;
+
+ switch (*ls) {
+ case '-':
+ lsign = -1;
+ case '+':
+ ls++;
+ }
+
+#define ASSIGN_CHK_OFLOW(x, y) if (x < y) return -1; y = x
+ /*
+ * Calculate the value of the decimal digit string, failing
+ * on overflow.
+ */
+ while (isdigit(*ls)) {
+ oflow = length * 10 + *ls++ - '0';
+ ASSIGN_CHK_OFLOW(oflow, length);
+ }
+
+ switch (*ls) {
+ case 'G':
+ oflow = length * 1024;
+ ASSIGN_CHK_OFLOW(oflow, length);
+ case 'M':
+ oflow = length * 1024;
+ ASSIGN_CHK_OFLOW(oflow, length);
+ case 'K':
+ if (ls[1] != '\0')
+ return -1;
+ oflow = length * 1024;
+ ASSIGN_CHK_OFLOW(oflow, length);
+ case '\0':
+ break;
+ default:
+ return -1;
+ }
+
+ *sz = length * lsign;
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n",
+ "usage: truncate [-c] -s [+|-]size[K|M|G] file ...",
+ " truncate [-c] -r rfile file ...");
+ exit(EXIT_FAILURE);
+}
OpenPOWER on IntegriCloud