static bool do_format(const std::string &mountpoint)
{
    if (mountpoint == SYSTEM || mountpoint == CACHE) {
        // Need to mount the partition if we're using an image file and it
        // hasn't been mounted
        int needs_mount = (mountpoint == SYSTEM)
                && (access("/mb/system.img", F_OK) == 0)
                && (access(STAMP_FILE, F_OK) != 0);

        if (needs_mount && !do_mount(mountpoint)) {
            LOGE(TAG "Failed to mount {}", mountpoint);
            return false;
        }

        if (!wipe_directory(mountpoint, true)) {
            LOGE(TAG "Failed to wipe {}", mountpoint);
            return false;
        }

        if (needs_mount && !do_unmount(mountpoint)) {
            LOGE(TAG "Failed to unmount {}", mountpoint);
            return false;
        }
    } else if (mountpoint == DATA) {
        if (!wipe_directory(mountpoint, false)) {
            LOGE(TAG "Failed to wipe {}", mountpoint);
            return false;
        }
    }

    LOGD(TAG "Formatted {}", mountpoint);

    return true;
}
Esempio n. 2
0
static int prepare_buffer(int argc, char * argv[]) 
{

	if (argc<2) {
		usage();
		return -1;
	}
	if (strncmp(argv[1],"mount",5)==0) {
		return do_mount(argc,argv);
	} else if (strncmp(argv[1],"resume",6)==0) {
		return do_resume(argc,argv);
	} else if (strncmp(argv[1],"suspend",7)==0) {
		return do_suspend(argc,argv);

	} else if (strncmp(argv[1],"status",6)==0) {
		return do_status(argc,argv);

	} else if (strncmp(argv[1],"unmount",7)==0) {
		return do_unmount(argc,argv);
	} else if (strncmp(argv[1],"exit",4)==0) {
		return do_exit(argc,argv);

	} else {
		usage();
		return -1;
	}

	return 0;
}
static bool do_format(const char *mountpoint)
{
    if (!get_paths(mountpoint, nullptr, nullptr)) {
        LOGE(TAG "%s: Invalid mountpoint", mountpoint);
        return false;
    }

    bool needs_mount = !util::is_mounted(mountpoint);

    if (needs_mount && !do_mount(mountpoint)) {
        LOGE(TAG "%s: Failed to mount path", mountpoint);
        return false;
    }

    std::vector<std::string> exclusions;
    if (strcmp(mountpoint, DATA) == 0) {
        exclusions.push_back("media");
    }

    if (!wipe_directory(mountpoint, exclusions)) {
        LOGE(TAG "%s: Failed to wipe directory", mountpoint);
        return false;
    }

    if (needs_mount && !do_unmount(mountpoint)) {
        LOGE(TAG "%s: Failed to unmount path", mountpoint);
        return false;
    }

    LOGD(TAG "Successfully formatted %s", mountpoint);

    return true;
}
Esempio n. 4
0
/*
 * Unmount a single filesystem.
 */
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
	int error;

	error = do_unmount(mountpoint, flags);
	if (error != 0) {
		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
		    mountpoint));
	}

	return (0);
}
Esempio n. 5
0
int do_eject() {
	if (rip_status == STATUS_MOUNTED)
	  do_unmount();

	printf("Ejecting iPod at %s\n", RIP_MOUNTDEVICE);
#ifdef IPOD
	/* This is a poor hack to deal with busybox's eject not working for SCSI devices */
	if (vfork() == 0) { execl("/bin/rmmod", "/bin/rmmod", "sbp2", NULL); _exit(0); }
    pz_dialog("iPod Eject", "Please physically disconnect the iPods before pressing [OK]", 1, 0, "OK");
	if (vfork() == 0) { execl("/bin/modprobe", "/bin/modprobe", "sbp2", NULL); _exit(0); }
#else
	if (vfork() == 0) { execl("/usr/bin/eject", "/usr/bin/eject", RIP_MOUNTDEVICE, NULL); _exit(0); }
#endif

	ipod_status_ejected();
	return 1;
}
static void
autorun_dialog_response (GtkDialog *dialog, gint response, AutorunDialogData *data)
{
	switch (response) {
	case AUTORUN_DIALOG_RESPONSE_EJECT:
		do_unmount (data->mount, data->should_eject, GTK_WINDOW (dialog));
		break;

	case GTK_RESPONSE_NONE:
		/* window was closed */
		break;
	case GTK_RESPONSE_CANCEL:
		break;
	case GTK_RESPONSE_OK:
		/* do the selected action */

		if (data->remember) {
			/* make sure we don't ask again */
			csd_autorun_set_preferences (data->x_content_type, TRUE, data->selected_ignore, data->selected_open_folder);
			if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) {
				g_app_info_set_as_default_for_type (data->selected_app,
								    data->x_content_type,
								    NULL);
			}
		} else {
			/* make sure we do ask again */
			csd_autorun_set_preferences (data->x_content_type, FALSE, FALSE, FALSE);
		}

		if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) {
			csd_autorun_launch_for_mount (data->mount, data->selected_app);
		} else if (!data->selected_ignore && data->selected_open_folder) {
			if (data->open_window_func != NULL)
				data->open_window_func (data->mount, data->user_data);
		}
		break;
	}

	autorun_dialog_destroy (data);
}
/*
 * Class:     org_catacombae_jfuse_FUSE
 * Method:    unmountNative
 * Signature: (Ljava/lang/String;Z)Z
 */
JNIEXPORT jboolean JNICALL Java_org_catacombae_jfuse_FUSE_unmountNative
  (JNIEnv *env, jclass clazz, jstring mountPoint, jboolean force) {
#define _FNAME_ "Java_org_catacombae_jfuse_FUSE_unmountNative"
    CSLogTraceEnter("%s (%p, %p, %p, %d)", _FNAME_, env, clazz, mountPoint,
            force);

    jboolean res = JNI_FALSE;

    const char *mountPointChars = env->GetStringUTFChars(mountPoint, NULL);

    if(do_unmount(mountPointChars, (force == JNI_TRUE ? UNMOUNT_FORCE : 0)) == 0)
        res = JNI_TRUE;
    else
        CSLogError("Could not unmount \"%s\". errno=%d (%s)", mountPointChars,
                errno, strerror(errno));

    env->ReleaseStringUTFChars(mountPoint, mountPointChars);

    CSLogTraceLeave("%s (%p, %p, %p, %d): %d", _FNAME_, env, clazz, mountPoint,
            force, res);
    return res;
#undef _FNAME_
}
Esempio n. 8
0
// The erase parameter in this routine is to control nested mount points.
// We want to descend into a mount point to unmount anything that is
// mounted under it, but we do not want to delete any files while doing
// this traversal.  In other words, we erase files until we cross the
// first mount point, and after that point we only scan and unmount.
static
void
cleanup_aux(const atf::fs::path& p, dev_t parent_device, bool erase)
{
    try {
        atf::fs::file_info fi(p);

        if (fi.get_type() == atf::fs::file_info::dir_type)
            cleanup_aux_dir(p, fi, fi.get_device() == parent_device);

        if (fi.get_device() != parent_device)
            do_unmount(p);

        if (erase) {
            if (fi.get_type() == atf::fs::file_info::dir_type)
                atf::fs::rmdir(p);
            else
                atf::fs::remove(p);
        }
    } catch (const atf::system_error& e) {
        if (e.code() != ENOENT && e.code() != ENOTDIR)
            throw e;
    }
}
int update_binary_tool_main(int argc, char *argv[])
{
    int opt;

    static struct option long_options[] = {
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };

    int long_index = 0;

    while ((opt = getopt_long(argc, argv, "h", long_options, &long_index)) != -1) {
        switch (opt) {
        case 'h':
            update_binary_tool_usage(0);
            return EXIT_SUCCESS;

        default:
            update_binary_tool_usage(1);
            return EXIT_FAILURE;
        }
    }

    if (argc - optind != 2) {
        update_binary_tool_usage(1);
        return EXIT_FAILURE;
    }

    // Log to stderr, so the output is ordered correctly in /tmp/recovery.log
    util::log_set_logger(std::make_shared<util::StdioLogger>(stderr));

    std::string action = argv[optind];
    std::string mountpoint = argv[optind + 1];

    if (action != ACTION_MOUNT
            && action != ACTION_UNMOUNT
            && action != ACTION_FORMAT) {
        update_binary_tool_usage(1);
        return EXIT_FAILURE;
    }

    if (mountpoint != SYSTEM
            && mountpoint != CACHE
            && mountpoint != DATA) {
        update_binary_tool_usage(1);
        return EXIT_FAILURE;
    }

    if (access("/.chroot", F_OK) < 0) {
        fprintf(stderr, "update-binary-tool must be run inside the chroot\n");
        return EXIT_FAILURE;
    }

    bool ret = false;

    if (action == ACTION_MOUNT) {
        ret = do_mount(mountpoint);
    } else if (action == ACTION_UNMOUNT) {
        ret = do_unmount(mountpoint);
    } else if (action == ACTION_FORMAT) {
        ret = do_format(mountpoint);
    }

    return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}
Esempio n. 10
0
PzWindow *new_dounmount_window() {
	do_unmount();
	return TTK_MENU_DONOTHING;
}
Esempio n. 11
0
static int unmount_fuse(const char *mnt, int quiet, int lazy)
{
    return do_unmount(mnt, quiet, lazy);
}
Esempio n. 12
0
static int unmount_fuse(const char *mnt, int quiet, int lazy)
{
    int res;
    struct mntent *entp;
    FILE *fp;
    FILE *newfp = NULL;
    const char *user = NULL;
    char uidstr[32];
    unsigned uidlen = 0;
    int found;
    int issymlink = 0;
    struct stat stbuf;
    const char *mtab = _PATH_MOUNTED;
    const char *mtab_new = _PATH_MOUNTED "~fuse~";

    if (lstat(mtab, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
        issymlink = 1;

    fp = setmntent(mtab, "r");
    if (fp == NULL) {
	fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
		strerror(errno));
	return -1;
    }

    if (!issymlink) {
        newfp = setmntent(mtab_new, "w");
        if (newfp == NULL) {
            fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new,
                    strerror(errno));
            endmntent(fp);
            return -1;
        }
    }

    if (getuid() != 0) {
        user = get_user_name();
        if (user == NULL)
            goto err_endmntent;

        uidlen = sprintf(uidstr, "%u", getuid());
    }

    found = 0;
    while ((entp = getmntent(fp)) != NULL) {
        int removed = 0;
        if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
            (strcmp(entp->mnt_type, "fuse") == 0 ||
             strcmp(entp->mnt_type, "fuseblk") == 0)) {
            if (user == NULL)
                removed = 1;
            else {
                char *p = strstr(entp->mnt_opts, "user="******"user_id=")) &&
                         (p == entp->mnt_opts || *(p-1) == ',') &&
                         strncmp(p + 8, uidstr, uidlen) == 0 &&
                         (*(p+8+uidlen) == ',' || *(p+8+uidlen) == '\0'))
                    removed = 1;
            }
        }
        if (removed)
            found = 1;
        else if (!issymlink) {
            res = addmntent(newfp, entp);
            if (res != 0) {
                fprintf(stderr, "%s: failed to add entry to %s: %s\n",
                        progname, mtab_new, strerror(errno));
            }
        }
    }

    endmntent(fp);
    if (!issymlink)
        endmntent(newfp);

    if (!found) {
        if (!quiet)
            fprintf(stderr, "%s: entry for %s not found in %s\n", progname,
                    mnt, mtab);
        goto err;
    }

    drop_privs();
    res = do_unmount(mnt, quiet, lazy);
    restore_privs();
    if (res == -1)
        goto err;

    if (!issymlink) {
        res = unmount_rename(mtab, mtab_new);
        if (res == -1)
            goto err;
    }
    return 0;

 err_endmntent:
    if (!issymlink)
        endmntent(newfp);
    endmntent(fp);
 err:
    if (!issymlink)
        unlink(mtab_new);
    return -1;
}
Esempio n. 13
0
int main(int argc, char *argv[])
{
    int ch;
    int fd;
    int res;
    char *origmnt;
    char *mnt;
    static int unmount = 0;
    static int lazy = 0;
    static int quiet = 0;
    char *commfd;
    int cfd;
    const char *opts = "";

    static const struct option long_opts[] = {
        {"unmount", no_argument, NULL, 'u'},
        {"lazy",    no_argument, NULL, 'z'},
        {"quiet",   no_argument, NULL, 'q'},
        {"help",    no_argument, NULL, 'h'},
        {"version", no_argument, NULL, 'V'},
        {0, 0, 0, 0}};

    progname = strdup(argv[0]);
    if (progname == NULL) {
        fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
        exit(1);
    }

    while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts, NULL)) != -1) {
        switch (ch) {
        case 'h':
            usage();
            break;

        case 'V':
            show_version();
            break;

        case 'o':
            opts = optarg;
            break;

        case 'u':
            unmount = 1;
            break;

        case 'z':
            lazy = 1;
            break;

        case 'q':
            quiet = 1;
            break;

        default:
            exit(1);
        }
    }

    if (lazy && !unmount) {
        fprintf(stderr, "%s: -z can only be used with -u\n", progname);
        exit(1);
    }

    if (optind >= argc) {
        fprintf(stderr, "%s: missing mountpoint argument\n", progname);
        exit(1);
    }

    origmnt = argv[optind];

    drop_privs();
    mnt = resolve_path(origmnt);
    restore_privs();
    if (mnt == NULL)
        exit(1);

    umask(033);
    if (unmount) {
        if (geteuid() == 0) {
            int mtablock = lock_mtab();
            res = unmount_fuse(mnt, quiet, lazy);
            unlock_mtab(mtablock);
        } else
            res = do_unmount(mnt, quiet, lazy);
        if (res == -1)
            exit(1);
        return 0;
    }

    commfd = getenv(FUSE_COMMFD_ENV);
    if (commfd == NULL) {
        fprintf(stderr, "%s: old style mounting not supported\n", progname);
        exit(1);
    }

    fd = mount_fuse(mnt, opts);
    if (fd == -1)
        exit(1);

    cfd = atoi(commfd);
    res = send_fd(cfd, fd);
    if (res == -1)
        exit(1);

    return 0;
}
Esempio n. 14
0
/*
 * Mount the given filesystem.
 *
 * 'flags' appears pretty much always 0 here.
 */
int
zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
{
	struct stat buf;
	char mountpoint[ZFS_MAXPROPLEN];
	char mntopts[MNT_LINE_MAX];
	libzfs_handle_t *hdl = zhp->zfs_hdl;
	int remount;

	if (options == NULL) {
		mntopts[0] = '\0';
	} else {
		(void) strlcpy(mntopts, options, sizeof (mntopts));
	}

	if (strstr(mntopts, MNTOPT_REMOUNT) != NULL)
		remount = 1;

	/*
	 * If the pool is imported read-only then all mounts must be read-only
	 */
#ifdef __LINUX__
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		(void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
#else
	if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
		flags |= MS_RDONLY;
#endif /* __LINUX__ */

	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
		return (0);

#ifdef __LINUX__

	/*
	 * Append default mount options which apply to the mount point.
	 * This is done because under Linux (unlike Solaris) multiple mount
	 * points may reference a single super block.  This means that just
	 * given a super block there is no back reference to update the per
	 * mount point options.
	 */
	rc = zfs_add_options(zhp, &flags);
	if (rc) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "default options unavailable"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    mountpoint));
	}

	/*
	 * Append zfsutil option so the mount helper allow the mount
	 */
	strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
#endif /* __LINUX__ */

	/* Create the directory if it doesn't already exist */
#ifdef __APPLE__
	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT &&
	    lstat(mountpoint, &buf) != 0) {
#else
	if (lstat(mountpoint, &buf) != 0) {
#endif
		if (mkdirp(mountpoint, 0755) != 0) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "failed to create mountpoint"));
			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
			    mountpoint));
		}

	}

	/*
	 * Determine if the mountpoint is empty.  If so, refuse to perform the
	 * mount.  We don't perform this check if 'remount' is
	 * specified or if overlay option(-O) is given
	 */
	if ((flags & MS_OVERLAY) == 0 && !remount &&
	    !dir_is_empty(mountpoint)) {
		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
		    "directory is not empty"));
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
	}

	/* perform the mount */
#ifdef __LINUX__
	rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
#elif defined(__APPLE__) || defined (__FREEBSD__)
	if (zmount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#elif defined(__illumos__)
	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
#endif /* __LINUX__*/
		/*
		 * Generic errors are nasty, but there are just way too many
		 * from mount(), and they're well-understood.  We pick a few
		 * common ones to improve upon.
		 */
		if (errno == EBUSY) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "mountpoint or dataset is busy"));
		} else if (errno == EPERM) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "Insufficient privileges"));
		} else if (errno == ENOTSUP) {
			char buf[256];
			int spa_version;

			VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
			(void) snprintf(buf, sizeof (buf),
			    dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
			    "file system on a version %d pool. Pool must be"
			    " upgraded to mount this file system."),
			    (u_longlong_t)zfs_prop_get_int(zhp,
			    ZFS_PROP_VERSION), spa_version);
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
#ifdef __APPLE__
		} else if (((errno == ESRCH) || (errno == EINVAL) ||
		    (errno == ENOENT && lstat(mountpoint, &buf) != 0)) &&
		    zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
			    "The parent file system must be mounted first."));
#endif
		} else {
			zfs_error_aux(hdl, strerror(errno));
		}
		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
		    zhp->zfs_name));
	}

#ifdef __APPLE__
	if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
		fprintf(stderr, "ZFS: snapshot mountpoint '%s'\n", mountpoint);

	if (!(flags & MS_RDONLY))
		zfs_mount_seticon(mountpoint);
#endif

	/* remove the mounted entry before re-adding on remount */
	if (remount)
		libzfs_mnttab_remove(hdl, zhp->zfs_name);

	/* add the mounted entry into our cache */
	libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts);
	return (0);
}

/*
 * Unmount a single filesystem.
 */
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
    int error;
#if 0
    error = unmount(mountpoint, flags);
    if (unmount(mountpoint, flags) != 0) {
		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
		    mountpoint));
	}
#else
    error = do_unmount(mountpoint, flags);
    if (error != 0) {
        return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                              dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
                    mountpoint));
    }
#endif

	return (0);
}

/*
 * Unmount the given filesystem.
 */
int
zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
{
	libzfs_handle_t *hdl = zhp->zfs_hdl;
#ifdef __LINUX__
	struct mnttab search = { 0 }, entry;
#else
	struct mnttab entry;
#endif /* __LINUX__ */
	char *mntpt = NULL;

	/* check to see if need to unmount the filesystem */
	if (mountpoint != NULL ||
	    (((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) ||
	    (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)) &&
	    libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {

		/*
		 * mountpoint may have come from a call to
		 * getmnt/getmntany if it isn't NULL. If it is NULL,
		 * we know it comes from getmntany which can then get
		 * overwritten later. We strdup it to play it safe.
		 */
		if (mountpoint == NULL)
			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
		else
			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);

		/*
		 * Unshare and unmount the filesystem
		 */
#ifdef __illumos__
		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
#else
		if (zfs_unshare_nfs(zhp, mntpt) != 0)
#endif
		return (-1);

		if (unmount_one(hdl, mntpt, flags) != 0) {
			free(mntpt);
#ifdef __illumos__
			(void) zfs_shareall(zhp);
#else
			(void) zfs_share_nfs(zhp);
#endif
			return (-1);
		}
		libzfs_mnttab_remove(hdl, zhp->zfs_name);
		free(mntpt);

	}

	return (0);
}
int update_binary_tool_main(int argc, char *argv[])
{
    int opt;

    static const char *short_options = "h";

    static struct option long_options[] = {
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
    };

    int long_index = 0;

    while ((opt = getopt_long(argc, argv, short_options,
                              long_options, &long_index)) != -1) {
        switch (opt) {
        case 'h':
            update_binary_tool_usage(stdout);
            return EXIT_SUCCESS;

        default:
            update_binary_tool_usage(stderr);
            return EXIT_FAILURE;
        }
    }

    if (argc - optind != 2) {
        update_binary_tool_usage(stderr);
        return EXIT_FAILURE;
    }

    // Log to stderr, so the output is ordered correctly in /tmp/recovery.log
    log::log_set_logger(std::make_shared<log::StdioLogger>(stderr, false));

    const char *action = argv[optind];
    const char *mountpoint = argv[optind + 1];

    bool is_valid_action = strcmp(action, ACTION_MOUNT) == 0
            || strcmp(action, ACTION_UNMOUNT) == 0
            || strcmp(action, ACTION_FORMAT) == 0;
    bool is_valid_mountpoint = strcmp(mountpoint, SYSTEM) == 0
            || strcmp(mountpoint, CACHE) == 0
            || strcmp(mountpoint, DATA) == 0;

    if (!is_valid_action || !is_valid_mountpoint) {
        update_binary_tool_usage(stderr);
        return EXIT_FAILURE;
    }

    if (access("/.chroot", F_OK) < 0) {
        fprintf(stderr, "update-binary-tool must be run inside the chroot\n");
        return EXIT_FAILURE;
    }

    bool ret = false;

    if (strcmp(action, ACTION_MOUNT) == 0) {
        ret = do_mount(mountpoint);
    } else if (strcmp(action, ACTION_UNMOUNT) == 0) {
        ret = do_unmount(mountpoint);
    } else if (strcmp(action, ACTION_FORMAT) == 0) {
        ret = do_format(mountpoint);
    }

    return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}