mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
200 lines
5.1 KiB
C
200 lines
5.1 KiB
C
/* Demonstrate the use of the 'mount-local' API.
|
|
*
|
|
* Run this program as (eg) mount-local /tmp/test.img. Note that
|
|
* '/tmp/test.img' is created or overwritten. Follow the instructions
|
|
* on screen.
|
|
*
|
|
* See "MOUNT LOCAL" in guestfs(3).
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <guestfs.h>
|
|
|
|
#ifndef O_CLOEXEC
|
|
#define O_CLOEXEC 0
|
|
#endif
|
|
|
|
/* Define a list of filesystem mount options (used on the libguestfs
|
|
* side, nothing to do with FUSE). An empty string may be used here
|
|
* instead.
|
|
*/
|
|
#define MOUNT_OPTIONS "acl,user_xattr"
|
|
|
|
/* Size of the disk (megabytes). */
|
|
#define SIZE_MB 512
|
|
|
|
static void
|
|
usage (void)
|
|
{
|
|
fprintf (stderr,
|
|
"Usage: mount-local disk.img\n"
|
|
"\n"
|
|
"NOTE: disk.img will be created or overwritten.\n"
|
|
"\n");
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
guestfs_h *g;
|
|
int r;
|
|
char tempdir[] = "/tmp/mlXXXXXX";
|
|
pid_t pid;
|
|
char *shell, *p;
|
|
|
|
if (argc != 2) {
|
|
usage ();
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
if (argv[1][0] == '-') {
|
|
usage ();
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
printf ("\n"
|
|
"This is the 'mount-local' demonstration program. Follow the\n"
|
|
"instructions on screen.\n"
|
|
"\n"
|
|
"Creating and formatting the disk image, please wait a moment ...\n");
|
|
fflush (stdout);
|
|
|
|
/* Guestfs handle. */
|
|
g = guestfs_create ();
|
|
if (g == NULL) {
|
|
perror ("could not create libguestfs handle");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
/* Create the output disk image: raw sparse. */
|
|
if (guestfs_disk_create (g, argv[1], "raw", SIZE_MB * 1024 * 1024, -1) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
/* Create the disk image and format it with a partition and a filesystem. */
|
|
if (guestfs_add_drive_opts (g, argv[1],
|
|
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
|
|
-1) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
if (guestfs_launch (g) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
/* Mount the empty filesystem. */
|
|
if (guestfs_mount_options (g, MOUNT_OPTIONS, "/dev/sda1", "/") == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
/* Create a file in the new filesystem. */
|
|
if (guestfs_touch (g, "/PUT_FILES_AND_DIRECTORIES_HERE") == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
/* Create a temporary mount directory. */
|
|
if (mkdtemp (tempdir) == NULL) {
|
|
perror ("mkdtemp");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
/* Mount the filesystem. */
|
|
if (guestfs_mount_local (g, tempdir, -1) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
/* Fork the shell for the user. */
|
|
pid = fork ();
|
|
if (pid == -1) {
|
|
perror ("fork");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
if (pid == 0) { /* Child. */
|
|
if (chdir (tempdir) == -1) {
|
|
perror (tempdir);
|
|
_exit (EXIT_FAILURE);
|
|
}
|
|
|
|
printf ("\n"
|
|
"The *current directory* is a FUSE filesystem backed by the disk\n"
|
|
"image which is managed by libguestfs. Any files or directories\n"
|
|
"you copy into here (up to %d MB) will be saved into the disk\n"
|
|
"image. You can also delete files, create certain special files\n"
|
|
"and so on.\n"
|
|
"\n"
|
|
"When you have finished adding files, hit ^D or type 'exit' to\n"
|
|
"exit the shell and return to the mount-local program.\n"
|
|
"\n",
|
|
SIZE_MB);
|
|
|
|
shell = getenv ("SHELL");
|
|
if (!shell)
|
|
r = system ("/bin/sh");
|
|
else {
|
|
/* Set a magic prompt. We only know how to do this for bash. */
|
|
p = strrchr (shell, '/');
|
|
if (p && strcmp (p+1, "bash") == 0) {
|
|
size_t len = 64 + strlen (shell);
|
|
char buf[len];
|
|
|
|
snprintf (buf, len, "PS1='mount-local-shell> ' %s --norc -i", shell);
|
|
r = system (buf);
|
|
} else
|
|
r = system (shell);
|
|
}
|
|
if (r == -1) {
|
|
fprintf (stderr, "error: failed to run sub-shell (%s) "
|
|
"(is $SHELL set correctly?)\n",
|
|
shell);
|
|
//FALLTHROUGH
|
|
}
|
|
|
|
if (chdir ("/") == -1)
|
|
perror ("chdir: /");
|
|
guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
|
|
_exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
/* Note that we are *not* waiting for the child yet. We want to
|
|
* run the FUSE code in parallel with the subshell.
|
|
*/
|
|
|
|
/* We're going to hide libguestfs errors here, but in a real program
|
|
* you would probably want to log them somewhere.
|
|
*/
|
|
guestfs_push_error_handler (g, NULL, NULL);
|
|
|
|
/* Now run the FUSE thread. */
|
|
if (guestfs_mount_local_run (g) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
guestfs_pop_error_handler (g);
|
|
|
|
waitpid (pid, NULL, 0);
|
|
|
|
/* Shutdown the handle explicitly so write errors can be detected. */
|
|
if (guestfs_shutdown (g) == -1)
|
|
exit (EXIT_FAILURE);
|
|
|
|
guestfs_close (g);
|
|
|
|
printf ("\n"
|
|
"Any files or directories that you copied in have been saved into\n"
|
|
"the disk image called '%s'.\n"
|
|
"\n"
|
|
"Try opening the disk image with guestfish to see those files:\n"
|
|
"\n"
|
|
" guestfish -a %s -m /dev/sda1\n"
|
|
"\n",
|
|
argv[1], argv[1]);
|
|
|
|
exit (EXIT_SUCCESS);
|
|
}
|