diff --git a/appliance/packagelist.in b/appliance/packagelist.in index 1cf7d9d97..8ed3afedc 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -151,6 +151,7 @@ ifelse(SUSE,1, ntfsprogs ntfs-3g reiserfs + squashfs systemd vim xz @@ -253,6 +254,7 @@ rsync scrub sed sleuthkit +squashfs-tools strace syslinux tar diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 3e301adc7..5c4ae8e0a 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -138,6 +138,7 @@ guestfsd_SOURCES = \ sh.c \ sleep.c \ sleuthkit.c \ + squashfs.c \ stat.c \ statvfs.c \ strings.c \ diff --git a/daemon/squashfs.c b/daemon/squashfs.c new file mode 100644 index 000000000..c30777661 --- /dev/null +++ b/daemon/squashfs.c @@ -0,0 +1,150 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +#define MAX_ARGS 64 + +GUESTFSD_EXT_CMD(str_mksquashfs, mksquashfs); + +int +optgroup_squashfs_available (void) +{ + return prog_exists (str_mksquashfs); +} + +/* Takes optional arguments, consult optargs_bitmask. */ +int +do_mksquashfs (const char *path, const char *compress, char *const *excludes) +{ + CLEANUP_FREE char *buf = NULL; + CLEANUP_UNLINK_FREE char *tmpfile = NULL; + CLEANUP_UNLINK_FREE char *exclude_from_file = NULL; + CLEANUP_FREE char *err = NULL; + CLEANUP_FREE char *buffer = NULL; + int r; + const char *argv[MAX_ARGS]; + size_t i = 0; + int fd; + FILE *fp; + + buf = sysroot_path (path); + if (buf == NULL) { + reply_with_perror ("malloc/sysroot_path"); + return -1; + } + + /* /var/tmp is used instead of /tmp, as /tmp is mounted as tmpfs + * and thus a newly created filesystem might not fit in memory. + */ + tmpfile = strdup ("/var/tmp/squashfs.XXXXXX"); + if (tmpfile == NULL) { + reply_with_perror ("strdup"); + return -1; + } + + fd = mkstemp (tmpfile); + if (fd == -1) { + reply_with_perror ("mkstemp"); + return -1; + } + close (fd); + + buffer = malloc (GUESTFS_MAX_CHUNK_SIZE); + if (buffer == NULL) { + reply_with_perror ("malloc/buffer"); + return -1; + } + + ADD_ARG (argv, i, str_mksquashfs); + ADD_ARG (argv, i, buf); + ADD_ARG (argv, i, tmpfile); + ADD_ARG (argv, i, "-noappend"); + ADD_ARG (argv, i, "-root-becomes"); + ADD_ARG (argv, i, buf); + ADD_ARG (argv, i, "-wildcards"); + ADD_ARG (argv, i, "-no-recovery"); + + if (optargs_bitmask & GUESTFS_MKSQUASHFS_COMPRESS_BITMASK) { + ADD_ARG (argv, i, "-comp"); + ADD_ARG (argv, i, compress); + } + + if (optargs_bitmask & GUESTFS_MKSQUASHFS_EXCLUDES_BITMASK) { + exclude_from_file = make_exclude_from_file ("mksquashfs", excludes); + if (!exclude_from_file) + return -1; + + ADD_ARG (argv, i, "-ef"); + ADD_ARG (argv, i, exclude_from_file); + } + + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("%s: %s", path, err); + return -1; + } + + fp = fopen (tmpfile, "r"); + if (fp == NULL) { + reply_with_perror ("%s", tmpfile); + return -1; + } + + /* Now we must send the reply message, before the file contents. After + * this there is no opportunity in the protocol to send any error + * message back. Instead we can only cancel the transfer. + */ + reply (NULL, NULL); + + while ((r = fread (buffer, 1, GUESTFS_MAX_CHUNK_SIZE, fp)) > 0) { + if (send_file_write (buffer, r) < 0) { + fclose (fp); + return -1; + } + } + + if (ferror (fp)) { + fprintf (stderr, "fread: %s: %m\n", tmpfile); + send_file_end (1); /* Cancel. */ + fclose (fp); + return -1; + } + + if (fclose (fp) != 0) { + fprintf (stderr, "fclose: %s: %m\n", tmpfile); + send_file_end (1); /* Cancel. */ + return -1; + } + + if (send_file_end (0)) /* Normal end of file. */ + return -1; + + return 0; +} diff --git a/generator/actions.ml b/generator/actions.ml index 990eacb12..ed0e8cc25 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -13280,6 +13280,35 @@ is removed." }; shortdesc = "search the entries associated to the given inode"; longdesc = "Internal function for find_inode." }; + { defaults with + name = "mksquashfs"; added = (1, 35, 25); + style = RErr, [Pathname "path"; FileOut "filename"], [OString "compress"; OStringList "excludes"]; + proc_nr = Some 471; + optional = Some "squashfs"; + cancellable = true; + shortdesc = "create a squashfs filesystem"; + longdesc = "\ +Create a squashfs filesystem for the specified C. + +The optional C flag controls compression. If not given, +then the output compressed using C. Otherwise one +of the following strings may be given to select the compression +type of the squashfs: C, C, C, C, C. + +The other optional arguments are: + +=over 4 + +=item C + +A list of wildcards. Files are excluded if they match any of the +wildcards. + +=back + +Please note that this API may fail when used to compress directories +with large files, such as the resulting squashfs will be over 3GB big." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index 55a137e8f..8fa8599d3 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -89,6 +89,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-mke2fs.h \ include/guestfs-gobject/optargs-mkfs.h \ include/guestfs-gobject/optargs-mkfs_btrfs.h \ + include/guestfs-gobject/optargs-mksquashfs.h \ include/guestfs-gobject/optargs-mkswap.h \ include/guestfs-gobject/optargs-mktemp.h \ include/guestfs-gobject/optargs-mount_9p.h \ @@ -180,6 +181,7 @@ guestfs_gobject_sources= \ src/optargs-mke2fs.c \ src/optargs-mkfs.c \ src/optargs-mkfs_btrfs.c \ + src/optargs-mksquashfs.c \ src/optargs-mkswap.c \ src/optargs-mktemp.c \ src/optargs-mount_9p.c \ diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR index 5f476b68c..c305aa5ae 100644 --- a/lib/MAX_PROC_NR +++ b/lib/MAX_PROC_NR @@ -1 +1 @@ -470 +471