int guestfs_impl_mount_local_run (guestfs_h *g) { int r, mounted; gl_lock_lock (mount_local_lock); mounted = g->localmountpoint != NULL; gl_lock_unlock (mount_local_lock); if (!mounted) { error (g, _("you must call guestfs_mount_local first")); return -1; } /* Test if root is mounted. We do this by using a side-effect of * guestfs_exists (which is that it calls NEED_ROOT). */ guestfs_push_error_handler (g, NULL, NULL); r = guestfs_exists (g, "/"); guestfs_pop_error_handler (g); if (r == -1) { error (g, _("you must call 'guestfs_mount' first to mount a filesystem on '/'.\nNote: '%s' is still mounted. Use 'guestunmount %s' to clean up."), g->localmountpoint, g->localmountpoint); return -1; } debug (g, "%s: entering fuse_loop", __func__); /* Enter the main loop. */ r = fuse_loop (g->fuse); if (r != 0) perrorf (g, _("fuse_loop: %s"), g->localmountpoint); debug (g, "%s: leaving fuse_loop", __func__); guestfs_int_free_fuse (g); gl_lock_lock (mount_local_lock); g->localmountpoint = NULL; gl_lock_unlock (mount_local_lock); /* By inspection, I found that fuse_loop only returns 0 or -1, but * don't rely on this in future. */ return r == 0 ? 0 : -1; }
void guestfs_close (guestfs_h *g) { struct hv_param *hp, *hp_next; guestfs_h **gg; if (g->state == NO_HANDLE) { /* Not safe to call ANY callbacks here, so ... */ fprintf (stderr, _("guestfs_close: called twice on the same handle\n")); return; } /* Remove the handle from the handles list. */ if (g->close_on_exit) { gl_lock_lock (handles_lock); for (gg = &handles; *gg != g; gg = &(*gg)->next) ; *gg = g->next; gl_lock_unlock (handles_lock); } if (g->trace) { const char trace_msg[] = "close"; guestfs_int_call_callbacks_message (g, GUESTFS_EVENT_TRACE, trace_msg, strlen (trace_msg)); } debug (g, "closing guestfs handle %p (state %d)", g, (int) g->state); if (g->state != CONFIG) shutdown_backend (g, 0); /* Run user close callbacks. */ guestfs_int_call_callbacks_void (g, GUESTFS_EVENT_CLOSE); /* Test output file used by bindtests. */ if (g->test_fp != NULL) fclose (g->test_fp); /* Remove temporary directory. */ guestfs_int_remove_tmpdir (g); /* Mark the handle as dead and then free up all memory. */ g->state = NO_HANDLE; free (g->events); g->nr_events = 0; g->events = NULL; #if HAVE_FUSE guestfs_int_free_fuse (g); #endif guestfs_int_free_inspect_info (g); guestfs_int_free_drives (g); for (hp = g->hv_params; hp; hp = hp_next) { free (hp->hv_param); free (hp->hv_value); hp_next = hp->next; free (hp); } while (g->error_cb_stack) guestfs_pop_error_handler (g); if (g->pda) hash_free (g->pda); free (g->tmpdir); free (g->env_tmpdir); free (g->int_tmpdir); free (g->int_cachedir); free (g->last_error); free (g->identifier); free (g->program); free (g->path); free (g->hv); free (g->backend); free (g->backend_data); guestfs_int_free_string_list (g->backend_settings); free (g->append); free (g); }
int guestfs_impl_mount_local (guestfs_h *g, const char *localmountpoint, const struct guestfs_mount_local_argv *optargs) { const char *t; struct fuse_args args = FUSE_ARGS_INIT (0, NULL); struct fuse_chan *ch; int fd; /* You can only mount each handle in one place in one thread. */ gl_lock_lock (mount_local_lock); t = g->localmountpoint; gl_lock_unlock (mount_local_lock); if (t) { error (g, _("filesystem is already mounted in another thread")); return -1; } if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_READONLY_BITMASK) g->ml_read_only = optargs->readonly; else g->ml_read_only = 0; if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_CACHETIMEOUT_BITMASK) g->ml_dir_cache_timeout = optargs->cachetimeout; else g->ml_dir_cache_timeout = 60; if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_DEBUGCALLS_BITMASK) g->ml_debug_calls = optargs->debugcalls; else g->ml_debug_calls = 0; /* Initialize the directory caches in the handle. */ if (init_dir_caches (g) == -1) return -1; /* Create the FUSE 'args'. */ /* XXX we don't have a program name */ if (fuse_opt_add_arg (&args, "guestfs_mount_local") == -1) { arg_error: perrorf (g, _("fuse_opt_add_arg: %s"), localmountpoint); fuse_opt_free_args (&args); guestfs_int_free_fuse (g); return -1; } if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_OPTIONS_BITMASK) { if (fuse_opt_add_arg (&args, "-o") == -1 || fuse_opt_add_arg (&args, optargs->options) == -1) goto arg_error; } debug (g, "%s: fuse_mount %s", __func__, localmountpoint); /* Create the FUSE mountpoint. */ ch = fuse_mount (localmountpoint, &args); if (ch == NULL) { perrorf (g, _("fuse_mount: %s"), localmountpoint); fuse_opt_free_args (&args); guestfs_int_free_fuse (g); return -1; } /* Set F_CLOEXEC on the channel. XXX libfuse should do this. */ fd = fuse_chan_fd (ch); if (fd >= 0) set_cloexec_flag (fd, 1); debug (g, "%s: fuse_new", __func__); /* Create the FUSE handle. */ g->fuse = fuse_new (ch, &args, &mount_local_operations, sizeof mount_local_operations, g); if (!g->fuse) { perrorf (g, _("fuse_new: %s"), localmountpoint); fuse_unmount (localmountpoint, ch); fuse_opt_free_args (&args); guestfs_int_free_fuse (g); return -1; } fuse_opt_free_args (&args); debug (g, "%s: leaving fuse_mount_local", __func__); /* Set g->localmountpoint in the handle. */ gl_lock_lock (mount_local_lock); g->localmountpoint = localmountpoint; gl_lock_unlock (mount_local_lock); return 0; }