int guestfs__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; } 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___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; }
/* Given one or more fields from the header of a CD/DVD/ISO, look up * the media in the libosinfo database and return our best guess for * the operating system. * * This returns: * -1 => a fatal error ('error' has been called, caller must not ignore it) * 0 => could not locate the OS * 1 => matching OS found, the osinfo_ret pointer has been filled in */ int guestfs_int_osinfo_map (guestfs_h *g, const struct guestfs_isoinfo *isoinfo, const struct osinfo **osinfo_ret) { size_t i; /* We only need to lock the database when reading it for the first time. */ gl_lock_lock (osinfo_db_lock); if (osinfo_db_size == 0) { if (read_osinfo_db (g) == -1) { gl_lock_unlock (osinfo_db_lock); return -1; } } gl_lock_unlock (osinfo_db_lock); if (osinfo_db_size <= 0) return 0; /* Look in the database to see if we can find a match. */ for (i = 0; i < (size_t) osinfo_db_size; ++i) { if (osinfo_db[i].re_system_id) { if (!isoinfo->iso_system_id || !match (g, isoinfo->iso_system_id, osinfo_db[i].re_system_id)) continue; } if (osinfo_db[i].re_volume_id) { if (!isoinfo->iso_volume_id || !match (g, isoinfo->iso_volume_id, osinfo_db[i].re_volume_id)) continue; } if (osinfo_db[i].re_publisher_id) { if (!isoinfo->iso_publisher_id || !match (g, isoinfo->iso_publisher_id, osinfo_db[i].re_publisher_id)) continue; } if (osinfo_db[i].re_application_id) { if (!isoinfo->iso_application_id || !match (g, isoinfo->iso_application_id, osinfo_db[i].re_application_id)) continue; } debug (g, "osinfo: mapped disk to database entry %zu", i); if (osinfo_ret) *osinfo_ret = &osinfo_db[i]; return 1; } debug (g, "osinfo: no mapping found"); return 0; }
int guestfs___get_lpj (guestfs_h *g) { int r; gl_lock_lock (lpj_lock); if (lpj != 0) goto out; /* Try reading lpj from these sources: * - /proc/cpuinfo [in future] * - dmesg * - files: * + /var/log/dmesg * + /var/log/boot.msg */ r = read_lpj_from_dmesg (g); if (r > 0) { lpj = r; goto out; } lpj = read_lpj_from_files (g); out: gl_lock_unlock (lpj_lock); return lpj; }
void test_cond () { int remain = 2; gl_thread_t thread; cond_value = 0; thread = gl_thread_create (cond_routine, NULL); do { yield (); remain = sleep (remain); } while (remain); /* signal condition */ gl_lock_lock (lockcond); cond_value = 1; gl_cond_signal (condtest); gl_lock_unlock (lockcond); gl_thread_join (thread, NULL); if (cond_value != 2) abort (); }
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 requiem_fork_parent(void) { #ifdef HAVE_PTHREAD_ATFORK return; #endif _requiem_async_fork_parent(); _requiem_timer_fork_parent(); _idmef_path_cache_unlock(); gl_lock_unlock(_criteria_parse_mutex); }
/** * prelude_client_profile_get_prefix: * @cp: pointer on a #prelude_client_profile_t object. * @buf: buffer to write the returned filename to. * @size: size of @buf. * * Retrieve current prefix used with this profile. */ void prelude_client_profile_get_prefix(const prelude_client_profile_t *cp, char *buf, size_t size) { const char *prefix; prelude_return_if_fail(buf); gl_lock_lock(lock); prefix = init_once_and_get_prefix(); snprintf(buf, size, "%s", prefix); gl_lock_unlock(lock); }
static void * cond_routine (void *arg) { gl_lock_lock (lockcond); while (!cond_value) { gl_cond_wait (condtest, lockcond); } gl_lock_unlock (lockcond); cond_value = 2; return NULL; }
static void init_libguestfs (void) { gl_lock_lock (init_lock); #ifdef HAVE_LIBVIRT virInitialize (); #endif xmlInitParser (); LIBXML_TEST_VERSION; gl_lock_unlock (init_lock); }
/** * prelude_client_profile_get_analyzerid_filename: * @cp: pointer on a #prelude_client_profile_t object. * @buf: buffer to write the returned filename to. * @size: size of @buf. * * Writes the filename used to store @cp unique and permanent analyzer ident. */ void prelude_client_profile_get_default_config_dirname(const prelude_client_profile_t *cp, char *buf, size_t size) { const char *prefix; prelude_return_if_fail(buf); gl_lock_lock(lock); prefix = init_once_and_get_prefix(); if ( ! relative_config_default_dir ) snprintf(buf, size, "%s", PRELUDE_CONFIG_DEFAULT_DIR); else snprintf(buf, size, "%s/%s", prefix, relative_config_default_dir); gl_lock_unlock(lock); }
static void init_libguestfs (void) { #if defined(HAVE_LIBVIRT) || defined(HAVE_LIBXML2) gl_lock_lock (init_lock); #endif #ifdef HAVE_LIBVIRT virInitialize (); #endif #ifdef HAVE_LIBXML2 xmlInitParser (); LIBXML_TEST_VERSION; #endif #if defined(HAVE_LIBVIRT) || defined(HAVE_LIBXML2) gl_lock_unlock (init_lock); #endif }
int guestfs_impl_umount_local (guestfs_h *g, const struct guestfs_umount_local_argv *optargs) { const char *retry; int r; CLEANUP_FREE char *localmountpoint = NULL; CLEANUP_CMD_CLOSE struct command *cmd = NULL; /* How many times should we try the fusermount command? */ if (optargs->bitmask & GUESTFS_UMOUNT_LOCAL_RETRY_BITMASK) retry = optargs->retry ? "--retry=5" : "--no-retry"; else retry = "--no-retry"; /* Make a local copy of g->localmountpoint. It could be freed from * under us by another thread, except when we are holding the lock. */ gl_lock_lock (mount_local_lock); if (g->localmountpoint) localmountpoint = safe_strdup (g, g->localmountpoint); else localmountpoint = NULL; gl_lock_unlock (mount_local_lock); if (!localmountpoint) { error (g, _("no filesystem is mounted")); return -1; } /* Run guestunmount --retry=... localmountpoint. */ cmd = guestfs_int_new_command (g); guestfs_int_cmd_add_arg (cmd, "guestunmount"); guestfs_int_cmd_add_arg (cmd, retry); guestfs_int_cmd_add_arg (cmd, localmountpoint); r = guestfs_int_cmd_run (cmd); if (r == -1) return -1; if (WIFEXITED (r) && WEXITSTATUS (r) == EXIT_SUCCESS) /* External fusermount succeeded. Note that the original thread * is responsible for setting g->localmountpoint to NULL. */ return 0; return -1; }
/** * prelude_client_profile_set_prefix: * @cp: pointer on a #prelude_client_profile_t object. * @prefix: Prefix to use for various libprelude files. * * This function allow to dynamically change the prefix used to acess * libprelude related file. This is particularly usefull in case of * application running under certain condition (chroot). * * Returns: 0 on success, a negative value if an error occured. */ int prelude_client_profile_set_prefix(prelude_client_profile_t *cp, const char *prefix) { char *n; n = strdup(prefix); gl_lock_lock(lock); if ( user_prefix ) free(user_prefix); user_prefix = n; gl_lock_unlock(lock); return (n) ? 0 : prelude_error_from_errno(errno); }
/** * prelude_client_profile_get_tls_client_keycert_filename: * @cp: pointer on a #prelude_client_profile_t object. * @buf: buffer to write the returned filename to. * @size: size of @buf. * * Writes the filename used to store public certificate for @cp private key. * This only apply to client connecting to a peer. */ void prelude_client_profile_get_tls_client_keycert_filename(const prelude_client_profile_t *cp, char *buf, size_t size) { const char *prefix; prelude_return_if_fail(cp); prelude_return_if_fail(buf); gl_lock_lock(lock); prefix = init_once_and_get_prefix(); if ( ! relative_profile_dir ) snprintf(buf, size, "%s/%s/client.keycrt", PRELUDE_PROFILE_DIR, cp->name); else snprintf(buf, size, "%s/%s/%s/client.keycrt", prefix, relative_profile_dir, cp->name); gl_lock_unlock(lock); }
/** * prelude_client_profile_get_backup_dirname: * @cp: pointer on a #prelude_client_profile_t object. * @buf: buffer to write the returned filename to. * @size: size of @buf. * * Writes the directory name where message sent by @cp will be stored, * in case writing the message to the peer fail. */ void prelude_client_profile_get_backup_dirname(const prelude_client_profile_t *cp, char *buf, size_t size) { const char *prefix; prelude_return_if_fail(cp); prelude_return_if_fail(buf); gl_lock_lock(lock); prefix = init_once_and_get_prefix(); if ( ! relative_spool_dir ) snprintf(buf, size, "%s/%s", PRELUDE_SPOOL_DIR, cp->name); else snprintf(buf, size, "%s/%s/%s", prefix, relative_spool_dir, cp->name); gl_lock_unlock(lock); }
static void * timedcond_routine (void *arg) { int ret; struct timespec ts; gl_lock_lock (lockcond); while (!cond_value) { get_ts (&ts); ret = glthread_cond_timedwait (&condtest, &lockcond, &ts); if (ret == ETIMEDOUT) cond_timeout = 1; } gl_lock_unlock (lockcond); return NULL; }
/** * prelude_client_profile_get_backup_dirname: * @cp: pointer on a #prelude_client_profile_t object. * @buf: buffer to write the returned filename to. * @size: size of @buf. * * Writes the directory name where the profile for @cp is stored. If * @cp is NULL or has no name, then this function will provide the main * profile directory. */ void prelude_client_profile_get_profile_dirname(const prelude_client_profile_t *cp, char *buf, size_t size) { const char *prefix, *name_sep = "", *name = ""; prelude_return_if_fail(buf); if ( cp && cp->name ) { name_sep = "/"; name = cp->name; } gl_lock_lock(lock); prefix = init_once_and_get_prefix(); if ( ! relative_profile_dir ) snprintf(buf, size, "%s/%s%s", PRELUDE_PROFILE_DIR, name_sep, name); else snprintf(buf, size, "%s/%s%s%s", prefix, relative_profile_dir, name_sep, name); gl_lock_unlock(lock); }
guestfs_h * guestfs_create_flags (unsigned flags, ...) { guestfs_h *g; g = calloc (1, sizeof (*g)); if (!g) return NULL; g->state = CONFIG; g->conn = NULL; guestfs_int_init_error_handler (g); g->abort_cb = abort; g->recovery_proc = 1; g->autosync = 1; g->memsize = DEFAULT_MEMSIZE; /* Start with large serial numbers so they are easy to spot * inside the protocol. */ g->msg_next_serial = 0x00123400; /* Default is uniprocessor appliance. */ g->smp = 1; g->path = strdup (GUESTFS_DEFAULT_PATH); if (!g->path) goto error; #ifdef QEMU g->hv = strdup (QEMU); #else /* configure --without-qemu, so set QEMU to something which will * definitely fail. The user is expected to override the hypervisor * by setting an environment variable or calling set_hv. */ g->hv = strdup ("false"); #endif if (!g->hv) goto error; /* Get program name. */ #if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME == 1 if (STRPREFIX (program_invocation_short_name, "lt-")) /* Remove libtool (lt-*) prefix from short name. */ g->program = strdup (program_invocation_short_name + 3); else g->program = strdup (program_invocation_short_name); #else g->program = strdup (""); #endif if (!g->program) goto error; g->identifier = strdup (""); if (!g->identifier) goto error; if (guestfs_int_set_backend (g, DEFAULT_BACKEND) == -1) { warning (g, _("libguestfs was built with an invalid default backend, using 'direct' instead")); if (guestfs_int_set_backend (g, "direct") == -1) { warning (g, _("'direct' backend does not work")); goto error; } } if (!(flags & GUESTFS_CREATE_NO_ENVIRONMENT)) ignore_value (guestfs_parse_environment (g)); if (!(flags & GUESTFS_CREATE_NO_CLOSE_ON_EXIT)) { g->close_on_exit = true; /* Link the handles onto a global list. */ gl_lock_lock (handles_lock); g->next = handles; handles = g; if (!atexit_handler_set) { atexit (close_handles); atexit_handler_set = 1; } gl_lock_unlock (handles_lock); } debug (g, "create: flags = %u, handle = %p, program = %s", flags, g, g->program); return g; error: guestfs_int_free_string_list (g->backend_settings); free (g->backend); free (g->identifier); free (g->program); free (g->path); free (g->hv); free (g->append); free (g); return NULL; }
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); }
guestfs_h * guestfs_create (void) { guestfs_h *g; const char *str; g = malloc (sizeof (*g)); if (!g) return NULL; memset (g, 0, sizeof (*g)); g->state = CONFIG; g->fd[0] = -1; g->fd[1] = -1; g->sock = -1; g->abort_cb = abort; g->error_cb = default_error_cb; g->error_cb_data = NULL; g->recovery_proc = 1; g->autosync = 1; str = getenv ("LIBGUESTFS_DEBUG"); g->verbose = str != NULL && STREQ (str, "1"); str = getenv ("LIBGUESTFS_TRACE"); g->trace = str != NULL && STREQ (str, "1"); str = getenv ("LIBGUESTFS_PATH"); g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH); if (!g->path) goto error; str = getenv ("LIBGUESTFS_QEMU"); g->qemu = str != NULL ? strdup (str) : strdup (QEMU); if (!g->qemu) goto error; str = getenv ("LIBGUESTFS_APPEND"); if (str) { g->append = strdup (str); if (!g->append) goto error; } /* Choose a suitable memory size. Previously we tried to choose * a minimal memory size, but this isn't really necessary since * recent QEMU and KVM don't do anything nasty like locking * memory into core any more. Thus we can safely choose a * large, generous amount of memory, and it'll just get swapped * on smaller systems. */ str = getenv ("LIBGUESTFS_MEMSIZE"); if (str) { if (sscanf (str, "%d", &g->memsize) != 1 || g->memsize <= 256) { warning (g, "non-numeric or too small value for LIBGUESTFS_MEMSIZE"); goto error; } } else g->memsize = 500; /* Start with large serial numbers so they are easy to spot * inside the protocol. */ g->msg_next_serial = 0x00123400; /* Default is uniprocessor appliance. */ g->smp = 1; /* Link the handles onto a global list. */ gl_lock_lock (handles_lock); g->next = handles; handles = g; if (!atexit_handler_set) { atexit (close_handles); atexit_handler_set = 1; } gl_lock_unlock (handles_lock); debug (g, "new guestfs handle %p", g); return g; error: free (g->path); free (g->qemu); free (g->append); free (g); return NULL; }
void guestfs_close (guestfs_h *g) { 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; } if (g->trace) { const char trace_msg[] = "close"; guestfs___call_callbacks_message (g, GUESTFS_EVENT_TRACE, trace_msg, strlen (trace_msg)); } debug (g, "closing guestfs handle %p (state %d)", g, g->state); /* Try to sync if autosync flag is set. */ if (g->autosync && g->state == READY) guestfs_internal_autosync (g); /* If we are valgrinding the daemon, then we *don't* want to kill * the subprocess because we want the final valgrind messages sent * when we close sockets below. However for normal production use, * killing the subprocess is the right thing to do (in case the * daemon or qemu is not responding). */ #ifndef VALGRIND_DAEMON /* Kill the qemu subprocess. */ if (g->state != CONFIG) guestfs_kill_subprocess (g); #endif /* Run user close callbacks. */ guestfs___call_callbacks_void (g, GUESTFS_EVENT_CLOSE); /* Remove all other registered callbacks. Since we've already * called the close callbacks, we shouldn't call any others. */ free (g->events); g->nr_events = 0; g->events = NULL; guestfs___free_inspect_info (g); guestfs___free_drives (&g->drives); /* Close sockets. */ if (g->fd[0] >= 0) close (g->fd[0]); if (g->fd[1] >= 0) close (g->fd[1]); if (g->sock >= 0) close (g->sock); g->fd[0] = -1; g->fd[1] = -1; g->sock = -1; /* Wait for subprocess(es) to exit. */ if (g->pid > 0) waitpid (g->pid, NULL, 0); if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); /* Remove whole temporary directory. */ guestfs___remove_tmpdir (g->tmpdir); free (g->tmpdir); if (g->cmdline) { size_t i; for (i = 0; i < g->cmdline_size; ++i) free (g->cmdline[i]); free (g->cmdline); } /* Mark the handle as dead before freeing it. */ g->state = NO_HANDLE; gl_lock_lock (handles_lock); if (handles == g) handles = g->next; else { guestfs_h *gg; for (gg = handles; gg->next != g; gg = gg->next) ; gg->next = g->next; } gl_lock_unlock (handles_lock); if (g->pda) hash_free (g->pda); free (g->last_error); free (g->path); free (g->qemu); free (g->append); free (g->qemu_help); free (g->qemu_version); free (g); }
void _hivex_release_iconv (hive_h *h, recode_type t) { gl_lock_unlock (h->iconv_cache[t].mutex); }
void guestfs_close (guestfs_h *g) { struct qemu_param *qp, *qp_next; 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. */ gl_lock_lock (handles_lock); if (handles == g) handles = g->next; else { guestfs_h *gg; for (gg = handles; gg->next != g; gg = gg->next) ; gg->next = g->next; } gl_lock_unlock (handles_lock); if (g->trace) { const char trace_msg[] = "close"; guestfs___call_callbacks_message (g, GUESTFS_EVENT_TRACE, trace_msg, strlen (trace_msg)); } debug (g, "closing guestfs handle %p (state %d)", g, g->state); /* If we are valgrinding the daemon, then we *don't* want to kill * the subprocess because we want the final valgrind messages sent * when we close sockets below. However for normal production use, * killing the subprocess is the right thing to do (in case the * daemon or qemu is not responding). */ #ifndef VALGRIND_DAEMON if (g->state != CONFIG) ignore_value (guestfs_shutdown (g)); #endif /* Run user close callbacks. */ guestfs___call_callbacks_void (g, GUESTFS_EVENT_CLOSE); /* Remove whole temporary directory. */ guestfs___remove_tmpdir (g->tmpdir); /* 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___free_fuse (g); #endif guestfs___free_inspect_info (g); guestfs___free_drives (&g->drives); for (qp = g->qemu_params; qp; qp = qp_next) { free (qp->qemu_param); free (qp->qemu_value); qp_next = qp->next; free (qp); } if (g->pda) hash_free (g->pda); free (g->tmpdir); free (g->last_error); free (g->path); free (g->qemu); free (g->append); free (g); }
int strerror_r (int errnum, char *buf, size_t buflen) #undef strerror_r { /* Filter this out now, so that rest of this replacement knows that there is room for a non-empty message and trailing NUL. */ if (buflen <= 1) { if (buflen) *buf = '\0'; return ERANGE; } *buf = '\0'; /* Check for gnulib overrides. */ { char const *msg = strerror_override (errnum); if (msg) return safe_copy (buf, buflen, msg); } { int ret; int saved_errno = errno; #if USE_XPG_STRERROR_R { ret = __xpg_strerror_r (errnum, buf, buflen); if (ret < 0) ret = errno; if (!*buf) { /* glibc 2.13 would not touch buf on err, so we have to fall back to GNU strerror_r which always returns a thread-safe untruncated string to (partially) copy into our buf. */ safe_copy (buf, buflen, strerror_r (errnum, buf, buflen)); } } #elif USE_SYSTEM_STRERROR_R if (buflen > INT_MAX) buflen = INT_MAX; # ifdef __hpux /* On HP-UX 11.31, strerror_r always fails when buflen < 80; it also fails to change buf on EINVAL. */ { char stackbuf[80]; if (buflen < sizeof stackbuf) { ret = strerror_r (errnum, stackbuf, sizeof stackbuf); if (ret == 0) ret = safe_copy (buf, buflen, stackbuf); } else ret = strerror_r (errnum, buf, buflen); } # else ret = strerror_r (errnum, buf, buflen); /* Some old implementations may return (-1, EINVAL) instead of EINVAL. */ if (ret < 0) ret = errno; # endif # ifdef _AIX /* AIX returns 0 rather than ERANGE when truncating strings; try again until we are sure we got the entire string. */ if (!ret && strlen (buf) == buflen - 1) { char stackbuf[STACKBUF_LEN]; size_t len; strerror_r (errnum, stackbuf, sizeof stackbuf); len = strlen (stackbuf); /* STACKBUF_LEN should have been large enough. */ if (len + 1 == sizeof stackbuf) abort (); if (buflen <= len) ret = ERANGE; } # else /* Solaris 10 does not populate buf on ERANGE. OpenBSD 4.7 truncates early on ERANGE rather than return a partial integer. We prefer the maximal string. We set buf[0] earlier, and we know of no implementation that modifies buf to be an unterminated string, so this strlen should be portable in practice (rather than pulling in a safer strnlen). */ if (ret == ERANGE && strlen (buf) < buflen - 1) { char stackbuf[STACKBUF_LEN]; /* STACKBUF_LEN should have been large enough. */ if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE) abort (); safe_copy (buf, buflen, stackbuf); } # endif #else /* USE_SYSTEM_STRERROR */ /* Try to do what strerror (errnum) does, but without clobbering the buffer used by strerror(). */ # if defined __NetBSD__ || defined __hpux || ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Windows, Cygwin */ /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE and <errno.h> above. HP-UX: sys_nerr, sys_errlist are declared explicitly above. native Windows: sys_nerr, sys_errlist are declared in <stdlib.h>. Cygwin: sys_nerr, sys_errlist are declared in <errno.h>. */ if (errnum >= 0 && errnum < sys_nerr) { # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) # if defined __NetBSD__ nl_catd catd = catopen ("libc", NL_CAT_LOCALE); const char *errmsg = (catd != (nl_catd)-1 ? catgets (catd, 1, errnum, sys_errlist[errnum]) : sys_errlist[errnum]); # endif # if defined __hpux nl_catd catd = catopen ("perror", NL_CAT_LOCALE); const char *errmsg = (catd != (nl_catd)-1 ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum]) : sys_errlist[errnum]); # endif # else const char *errmsg = sys_errlist[errnum]; # endif if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) if (catd != (nl_catd)-1) catclose (catd); # endif } else ret = EINVAL; # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */ /* For a valid error number, the system's strerror() function returns a pointer to a not copied string, not to a buffer. */ if (errnum >= 0 && errnum < sys_nerr) { char *errmsg = strerror (errnum); if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); } else ret = EINVAL; # else gl_lock_lock (strerror_lock); { char *errmsg = strerror (errnum); /* For invalid error numbers, strerror() on - IRIX 6.5 returns NULL, - HP-UX 11 returns an empty string. */ if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); } gl_lock_unlock (strerror_lock); # endif #endif if (ret == EINVAL && !*buf) snprintf (buf, buflen, "Unknown error %d", errnum); errno = saved_errno; return ret; } }
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; }
int strerror_r (int errnum, char *buf, size_t buflen) #undef strerror_r { /* Filter this out now, so that rest of this replacement knows that there is room for a non-empty message and trailing NUL. */ if (buflen <= 1) { if (buflen) *buf = '\0'; return ERANGE; } *buf = '\0'; /* Check for gnulib overrides. */ { char const *msg = strerror_override (errnum); if (msg) return safe_copy (buf, buflen, msg); } { int ret; int saved_errno = errno; #if USE_XPG_STRERROR_R { ret = __xpg_strerror_r (errnum, buf, buflen); if (ret < 0) ret = errno; if (!*buf) { /* glibc 2.13 would not touch buf on err, so we have to fall back to GNU strerror_r which always returns a thread-safe untruncated string to (partially) copy into our buf. */ safe_copy (buf, buflen, strerror_r (errnum, buf, buflen)); } } #elif USE_SYSTEM_STRERROR_R if (buflen > INT_MAX) buflen = INT_MAX; # ifdef __hpux /* On HP-UX 11.31, strerror_r always fails when buflen < 80; it also fails to change buf on EINVAL. */ { char stackbuf[80]; if (buflen < sizeof stackbuf) { ret = strerror_r (errnum, stackbuf, sizeof stackbuf); if (ret == 0) ret = safe_copy (buf, buflen, stackbuf); } else ret = strerror_r (errnum, buf, buflen); } # else ret = strerror_r (errnum, buf, buflen); /* Some old implementations may return (-1, EINVAL) instead of EINVAL. But on Haiku, valid error numbers are negative. */ # if !defined __HAIKU__ if (ret < 0) ret = errno; # endif # endif # if defined _AIX || defined __HAIKU__ /* AIX and Haiku return 0 rather than ERANGE when truncating strings; try again until we are sure we got the entire string. */ if (!ret && strlen (buf) == buflen - 1) { char stackbuf[STACKBUF_LEN]; size_t len; strerror_r (errnum, stackbuf, sizeof stackbuf); len = strlen (stackbuf); /* STACKBUF_LEN should have been large enough. */ if (len + 1 == sizeof stackbuf) abort (); if (buflen <= len) ret = ERANGE; } # else /* Solaris 10 does not populate buf on ERANGE. OpenBSD 4.7 truncates early on ERANGE rather than return a partial integer. We prefer the maximal string. We set buf[0] earlier, and we know of no implementation that modifies buf to be an unterminated string, so this strlen should be portable in practice (rather than pulling in a safer strnlen). */ if (ret == ERANGE && strlen (buf) < buflen - 1) { char stackbuf[STACKBUF_LEN]; /* STACKBUF_LEN should have been large enough. */ if (strerror_r (errnum, stackbuf, sizeof stackbuf) == ERANGE) abort (); safe_copy (buf, buflen, stackbuf); } # endif #else /* USE_SYSTEM_STRERROR */ /* Try to do what strerror (errnum) does, but without clobbering the buffer used by strerror(). */ # if defined __NetBSD__ || defined __hpux || (defined _WIN32 && !defined __CYGWIN__) || defined __CYGWIN__ /* NetBSD, HP-UX, native Windows, Cygwin */ /* NetBSD: sys_nerr, sys_errlist are declared through _NETBSD_SOURCE and <errno.h> above. HP-UX: sys_nerr, sys_errlist are declared explicitly above. native Windows: sys_nerr, sys_errlist are declared in <stdlib.h>. Cygwin: sys_nerr, sys_errlist are declared in <errno.h>. */ if (errnum >= 0 && errnum < sys_nerr) { # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) # if defined __NetBSD__ nl_catd catd = catopen ("libc", NL_CAT_LOCALE); const char *errmsg = (catd != (nl_catd)-1 ? catgets (catd, 1, errnum, sys_errlist[errnum]) : sys_errlist[errnum]); # endif # if defined __hpux nl_catd catd = catopen ("perror", NL_CAT_LOCALE); const char *errmsg = (catd != (nl_catd)-1 ? catgets (catd, 1, 1 + errnum, sys_errlist[errnum]) : sys_errlist[errnum]); # endif # else const char *errmsg = sys_errlist[errnum]; # endif if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); # if HAVE_CATGETS && (defined __NetBSD__ || defined __hpux) if (catd != (nl_catd)-1) catclose (catd); # endif } else ret = EINVAL; # elif defined __sgi || (defined __sun && !defined _LP64) /* IRIX, Solaris <= 9 32-bit */ /* For a valid error number, the system's strerror() function returns a pointer to a not copied string, not to a buffer. */ if (errnum >= 0 && errnum < sys_nerr) { char *errmsg = strerror (errnum); if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); } else ret = EINVAL; # else gl_lock_lock (strerror_lock); { char *errmsg = strerror (errnum); /* For invalid error numbers, strerror() on - IRIX 6.5 returns NULL, - HP-UX 11 returns an empty string. */ if (errmsg == NULL || *errmsg == '\0') ret = EINVAL; else ret = safe_copy (buf, buflen, errmsg); } gl_lock_unlock (strerror_lock); # endif #endif #if defined _WIN32 && !defined __CYGWIN__ /* MSVC 14 defines names for many error codes in the range 100..140, but _sys_errlist contains strings only for the error codes < _sys_nerr = 43. */ if (ret == EINVAL) { const char *errmsg; switch (errnum) { case 100 /* EADDRINUSE */: errmsg = "Address already in use"; break; case 101 /* EADDRNOTAVAIL */: errmsg = "Cannot assign requested address"; break; case 102 /* EAFNOSUPPORT */: errmsg = "Address family not supported by protocol"; break; case 103 /* EALREADY */: errmsg = "Operation already in progress"; break; case 105 /* ECANCELED */: errmsg = "Operation canceled"; break; case 106 /* ECONNABORTED */: errmsg = "Software caused connection abort"; break; case 107 /* ECONNREFUSED */: errmsg = "Connection refused"; break; case 108 /* ECONNRESET */: errmsg = "Connection reset by peer"; break; case 109 /* EDESTADDRREQ */: errmsg = "Destination address required"; break; case 110 /* EHOSTUNREACH */: errmsg = "No route to host"; break; case 112 /* EINPROGRESS */: errmsg = "Operation now in progress"; break; case 113 /* EISCONN */: errmsg = "Transport endpoint is already connected"; break; case 114 /* ELOOP */: errmsg = "Too many levels of symbolic links"; break; case 115 /* EMSGSIZE */: errmsg = "Message too long"; break; case 116 /* ENETDOWN */: errmsg = "Network is down"; break; case 117 /* ENETRESET */: errmsg = "Network dropped connection on reset"; break; case 118 /* ENETUNREACH */: errmsg = "Network is unreachable"; break; case 119 /* ENOBUFS */: errmsg = "No buffer space available"; break; case 123 /* ENOPROTOOPT */: errmsg = "Protocol not available"; break; case 126 /* ENOTCONN */: errmsg = "Transport endpoint is not connected"; break; case 128 /* ENOTSOCK */: errmsg = "Socket operation on non-socket"; break; case 129 /* ENOTSUP */: errmsg = "Not supported"; break; case 130 /* EOPNOTSUPP */: errmsg = "Operation not supported"; break; case 132 /* EOVERFLOW */: errmsg = "Value too large for defined data type"; break; case 133 /* EOWNERDEAD */: errmsg = "Owner died"; break; case 134 /* EPROTO */: errmsg = "Protocol error"; break; case 135 /* EPROTONOSUPPORT */: errmsg = "Protocol not supported"; break; case 136 /* EPROTOTYPE */: errmsg = "Protocol wrong type for socket"; break; case 138 /* ETIMEDOUT */: errmsg = "Connection timed out"; break; case 140 /* EWOULDBLOCK */: errmsg = "Operation would block"; break; default: errmsg = NULL; break; } if (errmsg != NULL) ret = safe_copy (buf, buflen, errmsg); } #endif if (ret == EINVAL && !*buf) { #if defined __HAIKU__ /* For consistency with perror(). */ snprintf (buf, buflen, "Unknown Application Error (%d)", errnum); #else snprintf (buf, buflen, "Unknown error %d", errnum); #endif } errno = saved_errno; return ret; } }
int guestfs__umount_local (guestfs_h *g, const struct guestfs_umount_local_argv *optargs) { size_t i, tries; char *localmountpoint; char *fusermount_log = NULL; int error_fd = -1; int ret = -1; /* How many times should we try the fusermount command? */ if (optargs->bitmask & GUESTFS_UMOUNT_LOCAL_RETRY_BITMASK) tries = optargs->retry ? 5 : 1; else tries = 1; /* Make a local copy of g->localmountpoint. It could be freed from * under us by another thread, except when we are holding the lock. */ gl_lock_lock (mount_local_lock); if (g->localmountpoint) localmountpoint = safe_strdup (g, g->localmountpoint); else localmountpoint = NULL; gl_lock_unlock (mount_local_lock); if (!localmountpoint) { error (g, _("no filesystem is mounted")); goto out; } /* Send all errors from fusermount to a temporary file. Only after * all 'tries' have failed do we print the contents of this file. A * temporary failure when retry == true will not cause any error. */ fusermount_log = safe_asprintf (g, "%s/fusermount.log", g->tmpdir); error_fd = open (fusermount_log, O_RDWR|O_CREAT|O_TRUNC|O_NOCTTY /* not O_CLOEXEC */, 0600); if (error_fd == -1) { perrorf (g, _("open: %s"), fusermount_log); goto out; } for (i = 0; i < tries; ++i) { int r; r = do_fusermount (g, localmountpoint, error_fd); if (r == -1) goto out; if (r) { /* External fusermount succeeded. Note that the original thread * is responsible for setting g->localmountpoint to NULL. */ ret = 0; break; } sleep (1); } if (ret == -1) { /* fusermount failed */ char error_message[4096]; ssize_t n; /* Get the error message from the log file. */ if (lseek (error_fd, 0, SEEK_SET) >= 0 && (n = read (error_fd, error_message, sizeof error_message - 1)) > 0) { while (n > 0 && error_message[n-1] == '\n') n--; error_message[n] = '\0'; } else { snprintf (error_message, sizeof error_message, "(fusermount error could not be preserved)"); } error (g, _("fusermount failed: %s: %s"), localmountpoint, error_message); goto out; } out: if (error_fd >= 0) close (error_fd); if (fusermount_log) { unlink (fusermount_log); free (fusermount_log); } free (localmountpoint); return ret; }