root/usr/src/cmd/rmmount/rmmount.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <libgen.h>
#include <libintl.h>
#include <errno.h>
#include <sys/syscall.h>

#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <libhal.h>

#include <rmm_common.h>

char    *progname;

static boolean_t d_opt, l_opt, o_opt, u_opt, eject_opt,
    closetray_opt, query_opt;

static void usage();
static void nomem();

static void
usage()
{
        if (!u_opt) {
                (void) fprintf(stderr,
                    "%s: [-dlu] [-o options] [nickname | device] "
                    "[mount_point]\n", progname);
        } else {
                (void) fprintf(stderr,
                    "%s: [-dl] [nickname | device]\n", progname);
        }
}

static int
rmmount(int argc, char **argv)
{
        int             c;
        action_t        action;
        LibHalContext   *hal_ctx;
        DBusError       error;
        rmm_error_t     rmm_error;
        LibHalDrive     *d;
        GSList          *volumes;
        const char      *default_name;
        char            **opts = NULL;
        int             num_opts = 0;
        char            *mountpoint = NULL;
        char            **p;
        int             print_mask;
        int             ret = 0;

        progname = basename(argv[0]);

        if (strcmp(progname, "rmumount") == 0) {
                u_opt = B_TRUE;
        }

        if (getenv("RMMOUNT_DEBUG") != NULL) {
                rmm_debug = 1;
        }

        while ((c = getopt(argc, argv, "?dlo:u")) != -1) {
                switch (c) {
                case 'd':
                        d_opt = B_TRUE;
                        break;
                case 'l':
                        l_opt = B_TRUE;
                        break;
                case 'o':
                        o_opt = B_TRUE;
                        if ((opts = g_strsplit(optarg, ",", 10)) == NULL) {
                                nomem();
                        }
                        for (num_opts = 0, p = &opts[0]; *p != NULL; p++) {
                                num_opts++;
                        }
                        break;
                case 'u':
                        u_opt = B_TRUE;
                        break;
                case '?':
                        usage();
                        return (0);
                default:
                        usage();
                        return (1);
                }
        }

        if (u_opt) {
                action = UNMOUNT;
        } else if (closetray_opt) {
                action = CLOSETRAY;
        } else if (eject_opt) {
                action = EJECT;
        } else {
                action = INSERT;
        }

        if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
                (void) fprintf(stderr, gettext("warning: %s\n"),
                    rmm_strerror(&error, rmm_error));
                rmm_dbus_error_free(&error);
                if ((rmm_error == RMM_EDBUS_CONNECT) ||
                    (rmm_error == RMM_EHAL_CONNECT)) {
                        return (99);
                } else {
                        return (1);
                }
        }

        if (d_opt) {
                /* -d: print default name and exit */
                if ((d = rmm_hal_volume_find_default(hal_ctx, &error,
                    &default_name, &volumes)) == NULL) {
                        default_name = "nothing inserted";
                } else {
                        rmm_volumes_free(volumes);
                        libhal_drive_free(d);
                }
                (void) printf(gettext("Default device is: %s\n"), default_name);
        } else if (l_opt) {
                /* -l: list volumes and exit */
                print_mask = RMM_PRINT_MOUNTABLE;
                if (eject_opt) {
                        print_mask |= RMM_PRINT_EJECTABLE;
                }
                rmm_print_volume_nicknames(hal_ctx, &error, print_mask);
        } else if (optind == argc) {
                /* no name provided, use default */
                if ((d = rmm_hal_volume_find_default(hal_ctx, &error,
                    &default_name, &volumes)) == NULL) {
                        (void) fprintf(stderr,
                            gettext("No default media available\n"));
                        ret = 1;
                } else {
                        rmm_volumes_free(volumes);
                        libhal_drive_free(d);

                        if (query_opt) {
                                ret = rmm_rescan(hal_ctx, default_name,
                                    B_TRUE) ? 0 : 1;
                        } else {
                                ret = rmm_action(hal_ctx, default_name, action,
                                    0, 0, 0, 0) ? 0 : 1;
                        }
                }
        } else {
                if (argc - optind > 1) {
                        mountpoint = argv[optind + 1];
                }
                if (query_opt) {
                        ret = rmm_rescan(hal_ctx, argv[optind],
                            B_TRUE) ? 0 : 1;
                } else {
                        ret = rmm_action(hal_ctx, argv[optind], action,
                            0, opts, num_opts, mountpoint) ? 0 : 1;
                }
        }

        rmm_dbus_error_free(&error);
        rmm_hal_fini(hal_ctx);

        return (ret);
}

static int
rmumount(int argc, char **argv)
{
        return (rmmount(argc, argv));
}

static int
eject(int argc, char **argv)
{
        if (getenv("EJECT_CLOSETRAY") != NULL) {
                closetray_opt = B_TRUE;
        } else if (getenv("EJECT_QUERY") != NULL) {
                query_opt = B_TRUE;
        } else {
                eject_opt = B_TRUE;
        }
        return (rmmount(argc, argv));
}

static void
nomem(void)
{
        (void) fprintf(stderr, gettext("%s: Out of memory\n"), progname);
        exit(1);
}


/*
 * get the name by which this program was called
 */
static char *
get_progname(char *path)
{
        char    *s;
        char    *p;

        if ((s = strdup(path)) == NULL) {
                perror(path);
                exit(1);
        }

        p = strrchr(s, '/');
        if (p != NULL) {
                strcpy(s, p + 1);
        }

        return (s);
}

int
main(int argc, char **argv)
{
        int ret = 1;

        vold_init(argc, argv);

        progname = get_progname(argv[0]);

        if (strcmp(progname, "rmmount") == 0) {
                if ((getenv("VOLUME_ACTION") != NULL) &&
                    (getenv("VOLUME_PATH") != NULL)) {
                        ret = vold_rmmount(argc, argv);
                } else {
                        ret = rmmount(argc, argv);
                }
        } else if (strcmp(progname, "rmumount") == 0) {
                ret = rmumount(argc, argv);
        } else if (strcmp(progname, "eject") == 0) {
                ret = eject(argc, argv);
        } else {
                (void) fprintf(stderr, "rmmount: invalid program name\n");
                ret = 1;
        }

        return (ret);
}