summaryrefslogtreecommitdiff
path: root/minecctl/misc-commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'minecctl/misc-commands.c')
-rw-r--r--minecctl/misc-commands.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c
index 752b0e9..ff802d7 100644
--- a/minecctl/misc-commands.c
+++ b/minecctl/misc-commands.c
@@ -240,6 +240,9 @@ static bool valid_name(const char *name)
return false;
}
+ if (*f == '.')
+ return false;
+
while (*f != '\0') {
if ((*f >= 'a' && *f <= 'z') ||
(*f >= 'A' && *f <= 'Z') ||
@@ -543,6 +546,124 @@ bool do_new(struct cfg *cfg)
return true;
}
+static bool recursive_unlink(int dfd)
+{
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *dent;
+ int sdfd;
+
+ dir = fdopendir(dfd);
+ if (!dir) {
+ error("fdopendir: %m");
+ close(dfd);
+ return false;
+ }
+
+ errno = 0;
+ while ((dent = readdir(dir))) {
+ if (streq(dent->d_name, ".") || streq(dent->d_name, ".."))
+ continue;
+
+ switch (dent->d_type) {
+ case DT_DIR:
+ sdfd = openat(dfd, dent->d_name, O_RDONLY | O_CLOEXEC |
+ O_DIRECTORY | O_NOCTTY | O_NOFOLLOW |
+ O_NOATIME);
+ if (sdfd < 0) {
+ error("Unable to open subdir %s: %m",
+ dent->d_name);
+ return false;
+ }
+
+ verbose("Checking subdir %s", dent->d_name);
+ if (!recursive_unlink(sdfd))
+ return false;
+
+ verbose("Deleting subdir %s", dent->d_name);
+ if (unlinkat(dfd, dent->d_name, AT_REMOVEDIR) != 0) {
+ error("Unable to unlink server subdir %s: %m",
+ dent->d_name);
+ return false;
+ }
+
+ break;
+
+ case DT_LNK:
+ _fallthrough_;
+ case DT_REG:
+ _fallthrough_;
+ case DT_UNKNOWN:
+ verbose("Unlinking file %s", dent->d_name);
+ if (unlinkat(dfd, dent->d_name, 0) != 0) {
+ error("Failed to unlink file: %s",
+ dent->d_name);
+ return false;
+ }
+
+ break;
+
+ default:
+ error("Unexpected file type in server directory: %s",
+ dent->d_name);
+ return false;
+ }
+ errno = 0;
+ }
+
+ if (errno != 0) {
+ error("readdir: %m");
+ return false;
+ }
+
+ return true;
+}
+
+bool do_delete(struct cfg *cfg)
+{
+ const char *name = cfg->commands[0];
+ char filename[strlen(name) + STRLEN(".") + STRLEN(SERVER_CONFIG_FILE_SUFFIX) + 1];
+ int dfd;
+
+ sprintf(filename, "%s.%s", name, SERVER_CONFIG_FILE_SUFFIX);
+
+ if (!valid_name(name))
+ return false;
+
+ server_load_all_known(cfg);
+
+ /* FIXME: Stop server first */
+
+ if (unlinkat(dirfd(cfg->cfg_dir), filename, 0) != 0) {
+ error("Unable to remove \"%s\": %m", filename);
+ if (!cfg->force)
+ return false;
+ } else {
+ verbose("Removed \"%s\"", filename);
+ if (!cfg->force)
+ return true;
+ }
+
+ dfd = openat(dirfd(cfg->data_dir), name, O_RDONLY | O_CLOEXEC |
+ O_DIRECTORY | O_NOCTTY | O_NOFOLLOW | O_NOATIME);
+ if (dfd < 0) {
+ error("Unable to open server directory: %m");
+ return false;
+ }
+
+ if (!recursive_unlink(dfd)) {
+ error("Failed to remove some file(s) in server directory");
+ return false;
+ }
+
+ verbose("Deleting server directory %s", name);
+ if (unlinkat(dirfd(cfg->data_dir), name, AT_REMOVEDIR)) {
+ error("Failed to remove server directory: %m");
+ return false;
+ }
+
+ return true;
+}
+
bool do_list(struct cfg *cfg)
{
struct server *server;