truncate.c (2735B)
- // utils-std: Collection of commonly available Unix tools
- // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include "../lib/bitmasks.h" // FIELD_CLR
- #include "../lib/truncation.h" // parse_size
- #include <errno.h>
- #include <fcntl.h> // open
- #include <stdbool.h>
- #include <stdio.h> // fprintf
- #include <stdlib.h> // abort
- #include <string.h> // strerror
- #include <sys/stat.h>
- #include <unistd.h> // getopt
- const char *argv0 = "truncate";
- static void
- usage(void)
- {
- fprintf(stderr, "Usage: truncate [-co] [-r ref_file] [-s size] file...\n");
- }
- int
- main(int argc, char *argv[])
- {
- int open_flags = O_WRONLY | O_CREAT | O_NONBLOCK;
- bool size_set = false;
- struct truncation tr = {
- .op = OP_SET,
- .size = 0,
- };
- char *ref_file = NULL;
- int c = -1;
- while((c = getopt(argc, argv, ":cr:s:")) != -1)
- {
- switch(c)
- {
- case 'c':
- FIELD_CLR(open_flags, O_CREAT);
- break;
- case 'r':
- if(size_set)
- {
- fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
- usage();
- return 1;
- }
- ref_file = optarg;
- size_set = true;
- break;
- case 's':
- if(size_set)
- {
- fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
- usage();
- return 1;
- }
- if(parse_size(optarg, &tr) < 0)
- {
- usage();
- return 1;
- }
- size_set = true;
- break;
- case ':':
- fprintf(stderr, "truncate: error: Missing operand for option: '-%c'\n", optopt);
- usage();
- return 1;
- case '?':
- fprintf(stderr, "truncate: error: Unrecognised option: '-%c'\n", optopt);
- usage();
- return 1;
- default:
- abort();
- }
- }
- argc -= optind;
- argv += optind;
- if(argc < 1) usage();
- if(!size_set)
- {
- fprintf(stderr,
- "truncate: error: target size wasn't set, you need to pass one of -d / -r / -s\n");
- return 1;
- }
- if(ref_file != NULL)
- {
- struct stat ref_stats;
- if(stat(optarg, &ref_stats) < 0)
- {
- fprintf(stderr,
- "truncate: error: Couldn't get status for file '%s': %s\n",
- optarg,
- strerror(errno));
- return 1;
- }
- tr.op = OP_SET;
- tr.size = ref_stats.st_size;
- }
- for(int argi = 0; argi < argc; argi++)
- {
- char *arg = argv[argi];
- // same flags to open as touch(1)
- int fd = open(arg, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
- if(fd < 0)
- {
- fprintf(stderr, "truncate: error: Failed to open '%s': %s\n", arg, strerror(errno));
- return 1;
- }
- if(apply_truncation(fd, tr, arg) < 0) return 1;
- if(close(fd) < 0)
- {
- fprintf(stderr, "truncate: error: Failed closing fd for '%s': %s\n", arg, strerror(errno));
- return 1;
- }
- }
- return 0;
- }