volrmmount.c revision 18c2aff776a775d34a4c9893a4c72e0434d68e36
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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 1995, 2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Program to to allow non-root users to call rmmount
*
* XXX: much of this program is copied from eject.c. It would be nice
* to combine the common code in these two programs (in libvolgmt)
*/
/*
* System include files
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libintl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <volmgt.h>
/*
* Local include files
*/
#include "vold.h"
/*
* ON-private libvolmgt routines
*/
extern char *_media_oldaliases(char *);
/*
* Private attribute types and attributes
*/
typedef enum {
}
static const char *action_strings[] = {
"clear_mounts",
"unmount"
};
/*
* volmgt name for floppy and cdrom types of media
*/
#define FLOPPY_MEDIA_TYPE "floppy"
#define CDROM_MEDIA_TYPE "cdrom"
/*
* for environment variables
* (room for a pathname and some padding)
*/
/*
* path for the rmmount program
*/
#define RMMOUNT_PATH "/usr/sbin/rmmount"
#define RMMOUNT_PROG "rmmount"
/*
* maximum number of arguments that can be passed to rmmount
*/
#define RMM_MAX_ARGS 25
#ifdef DEBUG
#endif /* DEBUG */
/*
* Declarations of private functions.
*/
static char *getdefault(void);
static char *get_raw_partition_path(char *pathp);
static char *get_symname(char *, char *);
static int my_putenv(char *);
static char *my_strdup(char *);
static char *name_deref(char *, char **);
static char *symname_to_mt(char *);
static void usage(char *);
static char *vol_basename(char *);
static char *vol_dirname(char *);
static char *volrmm_getfullblkname(char *);
int
{
int c; /* for getopt() */
#ifdef DEBUG
#else
#endif /* DEBUG */
char *prog_name;
int ret_val;
char *vol;
do_pdefault = FALSE;
ret_val = 0;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'i':
break;
case 'e':
break;
case 'd':
do_pdefault = TRUE;
break;
case 'D':
break;
#ifdef DEBUG
case 'c':
rmm_config = (char *)optarg;
break;
#endif /* DEBUG */
default:
return (1);
}
}
if (!volmgt_running()) {
gettext("error: Volume Management must be running\n"));
return (1);
}
if (do_pdefault) {
gettext("Default device is: nothing inserted\n"));
} else {
}
return (0);
}
gettext("error: must specify an action\n"));
return (1);
}
/*
* If no symbolic name or path name was passed in,
* use the default symbolic name.
*/
gettext("No default media available\n"));
return (1);
}
ret_val = 1;
}
} else {
/*
* At least one symbolic name or path name was
* passed in.
*/
ret_val = 1;
}
}
}
return (ret_val);
}
static bool_t
{
/*
* Since volrmmount is a suid root program, we must make sure
* that the user running us is allowed to access the media.
* All a user has to do to request an action is open
* the file for reading, so that's as restrictive as we'll be.
*/
gettext("error: can't access \"%s\": %s\n"),
}
return (result);
}
static bool_t
{
int arg_ind = 0;
int exit_val;
gettext("error: can't fork to call \"%s\": %s\n"),
return (FALSE);
}
/* get name of program */
if (fork_pid == 0) {
/* the child */
/* set up the arg list */
if (do_debug) {
}
#ifdef DEBUG
if (rmm_config != NULL) {
}
#endif /* DEBUG */
gettext("error: can't exec \"%s\": %s\n"),
_exit(1);
}
/* the parent -- wait for that darned child */
/* signal ?? */
#ifdef WE_SHOULD_BE_VERBOSE
/*
* XXX: should user really get an error message for
* interrupting rmmount ??
*/
gettext("error: \"%s\" was interrupted\n"),
} else {
gettext("error: running \"%s\": %s\n"),
}
#endif
return (FALSE);
}
/* evaluate return status */
if (WEXITSTATUS(exit_val) == 0) {
return (TRUE); /* success */
}
} else if (WIFSIGNALED(exit_val)) {
gettext("error: \"%s\" terminated by signal %d\n"),
}
return (FALSE);
}
static char *
getdefault(void)
{
/*
* The assumption is that someone typed volrmmount to handle
* some medium that's currently in a drive. So, what we do is
* check for floppy then cdrom. If there's nothing in either,
* we just return NULL.
*/
char *s = NULL;
/* look for floppy, then CD-ROM, using new naming */
if (query(s)) {
goto dun;
}
}
if (query(s)) {
goto dun;
}
}
/* look for floppy, then CD-ROM, using old naming */
if (query(s)) {
goto dun;
}
}
if (query(s)) {
goto dun;
}
}
s = NULL; /* no match */
dun:
return (s);
}
static char *
get_raw_partition_path(char *pathp)
{
/*
* Given a path, check to see if it's a path to a raw
* partition. If so, simply return a copy of it.
* If it's a directory path, read the directory and
* return a copy of the first raw partition pathname
* found there. Don't read subdirectories. Assume
* that there's at least one raw partition file in
* the directory.
*/
DIR * directoryp;
char *filenamep;
char pathname_bufferp[MAXPATHLEN];
char *raw_partition_pathnamep;
struct stat stat_buffer;
int stat_result;
if (stat_result != 0) {
gettext("volrmmount: error: can't stat %s: %s\n"),
if (directoryp == NULL)
return (NULL);
while ((stat_result == 0) &&
errno = 0;
if (directory_entryp == NULL) {
if (errno != 0) {
"volrmmount: error: can't read %s: %s\n"),
}
break;
}
continue;
}
if (snprintf(pathname_bufferp,
sizeof (pathname_bufferp),
>= sizeof (pathname_bufferp)) {
continue;
}
if (stat_result != 0) {
"volrmmount: error: can't stat %s: %s\n"),
}
}
}
return (raw_partition_pathnamep);
}
/*
* Also, pathname which represents media will be returned via media_path.
* It is typically a path name to a directory which contains devices for
* each partitions in the media.
*/
static char *
{
const char *vm_root = volmgt_root();
char vol_symdir[MAXPATHLEN];
char *basen;
char lpath[MAXPATHLEN];
char link_buf[MAXPATHLEN];
int lb_len;
/* get path of alias directory */
/* scan for aliases that might match */
"error: can't open volmgt symlink directory \"%s\"; %s\n"),
goto dun;
}
goto dun;
continue;
/* this is *probably* a link, so proceed as if it is */
continue;
}
continue; /* not a link ?? */
}
/* path does not exist */
continue;
}
/*
* If not a directory, just check the device id see if
* it's the one.
*/
/* found a match! */
break;
}
continue;
}
/*
* If given pathname is a directory, we only check directory
* name.
*/
/* found a match! */
break;
}
continue;
}
/*
* symbol name in aliases points to directory. go through the
* directory contents see if there is a device match.
*/
continue;
continue;
/* pathname goes too long */
continue;
}
continue;
continue;
/* found a match! */
goto dun;
}
}
}
dun:
}
return (res);
}
static int
my_putenv(char *e)
{
int res;
char *env;
return (1);
}
gettext("error: can't allocate memory for environment: %s\n"),
}
return (res);
}
static char *
my_strdup(char *s)
{
register char *cp;
gettext("error: can't allocate memory: %s\n"),
}
return (cp);
}
static char *
{
/*
* dereference (if needed) the user-supplied name
*/
char *name1;
char *res;
char media_path[MAXPATHLEN];
/*
* Check to see if name is an old alias (e.g. "fd" or "cd").
*/
/*
* name isn't an old alias. Duplicate it as is.
*/
}
/*
*/
/*
* name isn't an old alias, an absolute path, or a name
* parameter.
*/
}
}
}
return (res);
}
static bool_t
{
/*
* In my experience with removable media drivers so far... the
* most reliable way to tell if a piece of media is in a drive
* is simply to open it. If the open works, there's something
* there, if it fails, there's not. We check for two errnos
* which we want to interpret for the user, ENOENT and EPERM.
* All other errors are considered to be "media isn't there".
* (halt, 1993)
*
* return TRUE if media found, else FALSE
*/
int fd = -1;
int rval; /* FDGETCHANGE return value */
enum dkio_state state;
/* open the specifed path */
goto dun;
}
rval = 0;
/* hey, it worked, what a deal, it must be a floppy */
if (!(rval & FDGC_CURRENT)) {
}
goto dun;
}
/* great, the fancy ioctl is supported. */
if (state == DKIO_INSERTED) {
goto dun;
}
if (state == DKIO_EJECTED) {
goto dun;
}
/* state must be DKIO_NONE: do a silly retry loop */
(void) sleep(1);
goto again; /* how many times? */
}
/*
* Ok, we've tried the non-blocking/ioctl route. The
* device doesn't support any of our nice ioctls, so
* we'll just say that if it opens it's there, if it
* doesn't, it's not.
*/
goto dun;
}
dun:
if (fd >= 0) {
}
return (res);
}
static bool_t
remount_medium(char *raw_pathp)
{
/*
* Remount the file systems on a medium that
* has been repartitioned.
*/
int file_descriptor;
char *raw_partition_pathp;
file_descriptor = -1;
if (raw_partition_pathp == NULL) {
gettext("volrmmount: error: no raw path for %s\n"),
} else {
if (file_descriptor < 0) {
"volrmmount: error: can't open %s: %s\n"),
"volrmmount: error: VOLIOCREMOUNT ioctl failed on %s: %s\n"),
}
}
if (raw_partition_pathp != NULL) {
}
if (file_descriptor >= 0) {
}
return (result);
}
static bool_t
{
/*
* Set up the following environment variables for rmmount:
*
* VOLUME_NAME - the volume's name
* VOLUME_ACTION - "clear_mounts" or "unmount"
* VOLUME_MEDIATYPE - medium type (e.g. "floppy", "cdrom")
* VOLUME_SYMDEV - the symname (e.g. "floppy0", "cdrom1")
*
* Return FALSE if a fatal error occurs.
*/
char *blk;
/*
* Set VOLUME_FDISK to the null string
* to avoid leaving it uninitialized.
*/
}
/*
* The calls to rmmount that this function sets
* up only unmount file systems, so the mount
* mode is irrelevant here. Set it to "rw".
*/
}
}
}
}
/*
* Pass the block /vol pathname.
*/
}
}
}
/*
* Pass the bare volume name without the path
*/
}
}
/*
* Pass the symbolic device name, e.g. "floppy0", "cdrom2".
*/
if (symbolic_namep == NULL) {
} else {
}
}
}
/*
* Pass the medium type.
*/
}
}
/*
* Pass the /vol pathname of the raw device directory.
*/
}
}
}
/*
* Always prevent forced ejection of the medium,
* since volrmmount only unmounts a medium's file
* systems or rereads the medium and reconstructs
* and remounts its file systems.
*/
}
}
return (result);
}
static char *
symname_to_mt(char *sn)
{
/*
* return media type given symname (by removing number at end)
*/
static char mt[MAXNAMELEN];
char *cpi;
char *cpo;
break;
}
}
*cpo = '\0';
/*
* Now check this against KNOWN media types volmgt
* supports. If it does not match one of the following
* 'floppy, cdrom, pcmem, rmdisk' set it to rmdisk. This
* is because what mt contains is the synname with numeric
* values removed and can have such names as 'zip', 'jaz'
* and items that belong to rmdisk that we do not know about
*/
return (mt);
}
/*
* we don't know the type, set it to rmidsk
*/
return (mt);
}
static void
{
"\nusage: %s [-D] [-i | -e] [NAME | NICKNAME]\n"),
gettext("options:\t-D call rmmount in debug mode\n"));
#ifdef DEBUG
gettext("options:\t-c CONFIG call rmmount in debug mode\n"));
#endif /* DEBUG */
gettext("options:\t-d show default device\n"));
gettext("\nmight tell %s to unmount the floppy (if mounted))\n\n"),
}
static char *
vol_basename(char *path)
{
register char *cp;
/* check for the degenerate case */
return (path);
}
/* look for the last slash in the name */
/* no slash */
return (path);
}
/* ensure something is after the slash */
if (*++cp != '\0') {
return (cp);
}
/* a name that ends in slash -- back up until previous slash */
if (*--cp == '/') {
return (--cp);
}
}
/* the only slash is the end of the name */
return (path);
}
/*
* returns a malloced string
*/
static char *
vol_dirname(char *path)
{
register char *cp;
char *new;
/* check for degenerates */
return (my_strdup("/"));
}
if (*path == '\0') {
return (my_strdup("."));
}
/* find the last seperator in the path */
/* must be just a local name -- use the local dir */
return (my_strdup("."));
}
/* allocate room for the new dirname string */
/*LINTED*/
gettext("error: can't allocate memory: %s\n"),
return (NULL);
}
/* copy the string in */
/* return all but the last component */
return (new);
}
static char *
volrmm_getfullblkname(char *path)
{
/*
* This routine will return the volmgt block name given the volmgt
* raw (char spcl) name, i.e. names starting with "/vol/r" will
* be changed to start with "/vol/", and names starting with
*
* If anything but a volmgt raw pathname is supplied that
* pathname will be returned.
*
* NOTE: non-null return value will point to static data,
* overwritten with each call
*
*/
char vm_raw_root[MAXPATHLEN];
const char *vm_root = volmgt_root();
static char res_buf[MAXPATHLEN];
/* get first volmgt root dev directory (and its length) */
/* see if we have a raw volmgt pathname (e.g. "/vol/r*") */
return (NULL);
}
goto dun;
}
/* get second volmgt root dev directory (and its length) */
return (NULL);
}
goto dun;
}
/* no match -- return what we got */
return (NULL);
dun:
return (res_buf);
}
static bool_t
{
char *raw_pathp;
char *symbolic_namep = NULL;
/*
* If necessary, convert path from a symbolic pathname
* or device alias to an actual raw path name.
*/
/*
* Make sure that the process has the right to access
* the volume.
*/
} else {
}
/*
* Set the environment variables for rmmount.
*/
}
}
}
}
return (result);
}