/* An command-line interface to ftruncate
*
* Dylan Simon
*/
#include
#include
#include
#include
#include
#include
#include
static const struct argp_option options[] = {
{"size", 'l', "BYTES", 0, "set file size", 0},
{"adjust", 'a', "BYTES", 0, "adjust file size", 0},
{"interactive", 'i', 0, 0, "prompt before any loss", 0},
{"force", 'f', 0, 0, "never prompt", 0},
{}
};
error_t parse(int, char *, struct argp_state *);
static const struct argp parser = {
.options = options,
.parser = &parse,
.args_doc = "FILE ...",
.doc = "Truncate a file to the specified size (or 0)."
};
off_t Len = 0;
long long Adj = 0;
bool Interactive = false;
error_t parse(int key, char *optarg, struct argp_state *state)
{
char *e;
int f = -1;
switch (key) {
case 'l':
if (Adj)
argp_error(state, "only one of -l or -a may be specified");
Len = strtoull(optarg, &e, 0);
if (*e || !*optarg)
argp_error(state, "invalid file length: %s", optarg);
break;
case 'a':
if (Len)
argp_error(state, "only one of -l or -a may be specified");
Adj = strtoll(optarg, &e, 0);
if (*e || !*optarg)
argp_error(state, "invalid file adjustment: %s", optarg);
break;
case 'i':
Interactive = true;
break;
case 'f':
Interactive = false;
break;
case ARGP_KEY_ARG:
if ((f = open(optarg, O_WRONLY | O_CREAT, 0666)) < 0)
argp_failure(state, 1, errno, "%s", optarg);
struct stat s = {};
if (Adj || Interactive)
if (fstat(f, &s) < 0)
argp_failure(state, 1, errno, "%s", optarg);
if (Adj)
{
if (s.st_size + Adj < 0)
Len = 0;
else
Len = s.st_size + Adj;
}
if (Interactive)
{
if (Len < s.st_size)
{
fprintf(stderr, "%s: remove %lu bytes of %s? ", state->name, s.st_size - Len, optarg);
int yn = -1;
int c;
while ((c = getchar()) != EOF && c != '\n')
{
if (yn != -1);
else if (c == 'y' || c == 'Y')
yn = 1;
else if (!isspace(c))
yn = 0;
}
if (yn != 1)
break;
}
}
if (ftruncate(f, Len) < 0)
argp_failure(state, 1, errno, "%s", optarg);
break;
case ARGP_KEY_NO_ARGS:
argp_usage(state);
default:
return ARGP_ERR_UNKNOWN;
}
if (f != -1)
close(f);
return 0;
}
int main(int argc, char **argv)
{
if ((errno = argp_parse(&parser, argc, argv, 0, 0, 0)))
{
fprintf(stderr, "%s: argp: %m\n", argv[0]);
exit(1);
}
exit(0);
}