From: Richard Jones Date: Fri, 10 Apr 2009 11:52:49 +0000 (+0100) Subject: New commands: rm rmdir rm-rf mkdir mkdir-p chmod chown X-Git-Tag: 0.8~6 X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=44da812b424f5e10e268d47149d012d49edf858b;p=libguestfs.git New commands: rm rmdir rm-rf mkdir mkdir-p chmod chown --- diff --git a/daemon/Makefile.am b/daemon/Makefile.am index c5ae1ef..400f164 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -23,6 +23,7 @@ guestfsd_SOURCES = \ augeas.c \ daemon.h \ devsparts.c \ + dir.c \ file.c \ guestfsd.c \ ls.c \ diff --git a/daemon/dir.c b/daemon/dir.c new file mode 100644 index 0000000..7892682 --- /dev/null +++ b/daemon/dir.c @@ -0,0 +1,167 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../src/guestfs_protocol.h" +#include "daemon.h" +#include "actions.h" + +int +do_rmdir (const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = rmdir (path); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("rmdir: %s", path); + return -1; + } + + return 0; +} + +/* This implementation is quick and dirty, and allows people to try + * to remove parts of the initramfs (eg. "rm -r /..") but if people + * do stupid stuff, who are we to try to stop them? + */ +int +do_rm_rf (const char *path) +{ + int r, len; + char *buf, *err; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + if (strcmp (path, "/") == 0) { + reply_with_error ("rm -rf: cannot remove root directory"); + return -1; + } + + len = strlen (path) + 9; + buf = malloc (len); + if (buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + snprintf (buf, len, "/sysroot%s", path); + + r = command (NULL, &err, "rm", "-rf", buf); + free (buf); + + /* rm -rf is never supposed to fail. I/O errors perhaps? */ + if (r == -1) { + reply_with_error ("rm -rf: %s: %s", path, err); + free (err); + return -1; + } + + free (err); + + return 0; +} + +int +do_mkdir (const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = mkdir (path, 0777); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("mkdir: %s", path); + return -1; + } + + return 0; +} + +static int +recursive_mkdir (const char *path) +{ + int loop = 0; + int r; + char *ppath, *p; + + again: + r = mkdir (path, 0777); + if (r == -1) { + if (!loop && errno == ENOENT) { + loop = 1; /* Stops it looping forever. */ + + /* If we're at the root, and we failed, just give up. */ + if (path[0] == '/' && path[1] == '\0') return -1; + + /* Try to make the parent directory first. */ + ppath = strdup (path); + if (ppath == NULL) return -1; + + p = strrchr (ppath, '/'); + if (p) *p = '\0'; + + r = recursive_mkdir (ppath); + free (ppath); + + if (r == -1) return -1; + + goto again; + } else /* Failed for some other reason, so return error. */ + return -1; + } + return 0; +} + +int +do_mkdir_p (const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = recursive_mkdir (path); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("mkdir -p: %s", path); + return -1; + } + + return 0; +} diff --git a/daemon/file.c b/daemon/file.c index ce44967..43c875c 100644 --- a/daemon/file.c +++ b/daemon/file.c @@ -180,3 +180,63 @@ do_read_lines (const char *path) return r; } + +int +do_rm (const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = unlink (path); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("unlink: %s", path); + return -1; + } + + return 0; +} + +int +do_chmod (int mode, const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = chmod (path, mode); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("chmod: %s: 0%o", path, mode); + return -1; + } + + return 0; +} + +int +do_chown (int owner, int group, const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = chown (path, owner, group); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("chown: %s: %d.%d", path, owner, group); + return -1; + } + + return 0; +} diff --git a/src/generator.ml b/src/generator.ml index 067ac90..253a1e0 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -64,6 +64,14 @@ and ret = | RVGList of string | RLVList of string and args = argt list (* Function parameters, guestfs handle is implicit. *) + + (* Note in future we should allow a "variable args" parameter as + * the final parameter, to allow commands like + * chmod mode file [file(s)...] + * This is not implemented yet, but many commands (such as chmod) + * are currently defined with the argument order keeping this future + * possibility in mind. + *) and argt = | String of string (* const char *name, cannot be NULL *) | OptString of string (* const char *name, may be NULL *) @@ -483,6 +491,48 @@ details."); This is just a shortcut for listing C C and sorting the resulting nodes into alphabetical order."); + ("rm", (RErr, [String "path"]), 29, [], + "remove a file", + "\ +Remove the single file C."); + + ("rmdir", (RErr, [String "path"]), 30, [], + "remove a directory", + "\ +Remove the single directory C."); + + ("rm_rf", (RErr, [String "path"]), 31, [], + "remove a file or directory recursively", + "\ +Remove the file or directory C, recursively removing the +contents if its a directory. This is like the C shell +command."); + + ("mkdir", (RErr, [String "path"]), 32, [], + "create a directory", + "\ +Create a directory named C."); + + ("mkdir_p", (RErr, [String "path"]), 33, [], + "create a directory and parents", + "\ +Create a directory named C, creating any parent directories +as necessary. This is like the C shell command."); + + ("chmod", (RErr, [Int "mode"; String "path"]), 34, [], + "change file mode", + "\ +Change the mode (permissions) of C to C. Only +numeric modes are supported."); + + ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [], + "change file owner and group", + "\ +Change the file owner to C and group to C. + +Only numeric uid and gid are supported. If you want to use +names, you will need to locate and parse the password file +yourself (Augeas support makes this relatively easy)."); ] let all_functions = non_daemon_functions @ daemon_functions