/* 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); }