rmdir.c (2691B)
- // 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 <errno.h>
- #include <stdbool.h>
- #include <stdio.h> // fprintf
- #include <stdlib.h> // abort
- #include <string.h> // strerror, strrchr
- #include <unistd.h> // getopt, rmdir
- #ifdef HAS_GETOPT_LONG
- #include <getopt.h>
- #endif
- static void
- usage(void)
- {
- #ifdef HAS_GETOPT_LONG
- fprintf(stderr, "Usage: rmdir [-pv] [--ignore-fail-on-non-empty] directory...\n");
- #else
- fprintf(stderr, "Usage: rmdir [-pv] directory...\n");
- #endif
- }
- int
- main(int argc, char *argv[])
- {
- bool parents = false, verbose = false, ign_enotempty = false;
- int c = -1;
- #ifdef HAS_GETOPT_LONG
- // clang-format off
- enum long_opt_vals {
- IGN_ENOTEMPTY = 1
- };
- static struct option opts[] = {
- {"ignore-fail-on-non-empty", no_argument, 0, IGN_ENOTEMPTY},
- {"parents", no_argument, 0, 'p'},
- {"verbose", no_argument, 0, 'v'},
- {0, 0, 0, 0},
- };
- // clang-format on
- // Need + as first character to get POSIX-style option parsing
- while((c = getopt_long(argc, argv, "+:pv", opts, NULL)) != -1)
- #else
- while((c = getopt(argc, argv, ":pv")) != -1)
- #endif
- {
- switch(c)
- {
- #ifdef HAS_GETOPT_LONG
- case IGN_ENOTEMPTY:
- ign_enotempty = true;
- break;
- #endif
- case 'p':
- parents = true;
- break;
- case 'v':
- verbose = true;
- break;
- case ':':
- fprintf(stderr, "rmdir: error: Missing operand for option: '-%c'\n", optopt);
- usage();
- return 1;
- case '?':
- fprintf(stderr, "rmdir: error: Unrecognised option: '-%c'\n", optopt);
- usage();
- return 1;
- default:
- abort();
- }
- }
- argc -= optind;
- argv += optind;
- if(argc == 0)
- {
- fprintf(stderr, "rmdir: error: missing operand\n");
- usage();
- return 1;
- }
- int err = 0;
- for(int i = 0; i < argc; i++)
- {
- errno = 0;
- char *path = argv[i];
- if(rmdir(path) < 0)
- {
- if(ign_enotempty && (errno == ENOTEMPTY || errno == EEXIST)) continue;
- fprintf(stderr, "rmdir: error: Failed removing '%s': %s\n", path, strerror(errno));
- err = 1;
- continue;
- }
- if(verbose) fprintf(stderr, "rmdir: Removed '%s'\n", path);
- if(!parents) continue;
- while(true)
- {
- char *sep = strrchr(path, '/');
- if(sep == NULL) break;
- *sep = 0;
- if(*path == 0) break;
- errno = 0;
- if(rmdir(path) < 0)
- {
- if(errno == ENOTDIR) break;
- if(ign_enotempty && (errno == ENOTEMPTY || errno == EEXIST)) break;
- fprintf(stderr, "rmdir: error: Failed removing '%s': %s\n", path, strerror(errno));
- err = 1;
- break;
- }
- if(verbose) fprintf(stderr, "rmdir: Removed '%s'\n", path);
- }
- }
- return err;
- }