rmm.c revision 18c2aff776a775d34a4c9893a4c72e0434d68e36
/*
* 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
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <rmmount.h>
#include <locale.h>
#include <libintl.h>
#include <unistd.h>
#include <string.h>
#include <regex.h>
#include <ctype.h>
#include <zone.h>
#include <libcontract.h>
#include <pwd.h>
#include "rmm_int.h"
extern int audio_only(struct action_arg *);
extern char *rawpath(char *);
#define UMOUNT_CMD "/etc/umount"
#define MAX_PARTITIONS 50
#define IDENT_VERS 1
#define ACT_VERS 1
#define AUDIO_CD_STRLEN 8
int system_labeled = 0;
char mnt_zoneroot[MAXPATHLEN];
char mnt_userdir[MAXPATHLEN];
#define DEFAULT_CONFIG "/etc/rmmount.conf"
#define DEFAULT_DSODIR "/usr/lib/rmmount"
char *rmm_dsodir = DEFAULT_DSODIR;
char *rmm_config = DEFAULT_CONFIG;
#define UNSHARE_CMD "/usr/sbin/unshare"
/*
* length of the option string for a mount
*/
#define RMM_OPTSTRLEN 128
/*
* Declarations of methods visible to the action() methods
* in the "action" DSOs.
*/
char *not_mountable(char *);
/*
* Names of the slices in a Solaris or HSFS VTOC
*/
static const char *slice_names[] = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15"
};
/*
* Declarations of private methods.
*/
static struct action_arg ** build_actargs(char *);
struct mount_args *ma);
static void exec_actions(struct action_arg **,
bool_t);
static int exec_mounts(struct action_arg **);
static int exec_umounts(struct action_arg **);
static void find_fstypes(struct action_arg **);
struct mount_args *ma,
static int read_directory(char *,
int *,
struct action_arg **);
static void share_mount(struct action_arg *,
struct mount_args *,
bool_t);
static bool_t umount_fork(char *);
struct mount_args *ma);
static void usage(void);
/*
* global - required to maintain the definition of the public interface
* to the "action" DSOs; refers to music CDs played by action_workman.so
*/
/*
* Definition of the main() function.
*/
/*
* Production (i.e. non-DEBUG) mode is very, very, quiet. The
* -D flag will turn on dprintf()s.
*/
int
{
int ai;
int c;
int exval;
struct action_arg **aa;
char *reason;
char *volume_action;
char *volume_mediatype;
char *volume_mount_mode;
char *volume_name;
char *volume_path;
char *volume_pcfs_id;
char *volume_symdev;
char *volume_zonename;
char *volume_user;
/*
* Make sure core files appear in a volmgt directory.
*/
(void) chdir(rmm_dsodir);
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
#ifdef VOLD_DEBUG
sleep(30);
#endif
if (geteuid() != 0) {
gettext("%s(%ld) error: must be root to execute\n"),
return (-1);
}
mnt_zoneroot[0] = '\0';
mnt_userdir[0] = '\0';
switch (c) {
case 'D':
break;
case 'd':
rmm_dsodir = (char *)optarg;
break;
case 'c':
rmm_config = (char *)optarg;
break;
default:
usage();
/*NOTREACHED*/
}
}
exval = 0;
if (system_labeled) {
}
if (volume_action == NULL) {
dprintf("%s(%ld): VOLUME_ACTION was null!!\n",
return (-1);
}
if (volume_mediatype == NULL) {
dprintf("%s(%ld): VOLUME_MEDIATYPE was null!!\n",
return (-1);
}
if (volume_mount_mode == NULL) {
volume_mount_mode = "rw";
}
if (volume_name == NULL) {
dprintf("%s(%ld): VOLUME_NAME was null!!\n",
return (-1);
}
if (volume_path == NULL) {
dprintf("%s(%ld): VOLUME_PATH was null!!\n",
return (-1);
}
if (volume_pcfs_id == NULL) {
volume_pcfs_id = "";
}
if (volume_symdev == NULL) {
dprintf("%s(%ld): VOLUME_SYMDEV was null!!\n",
return (-1);
}
if (system_labeled) {
if (volume_zonename != NULL &&
if ((mnt_zoneid =
dprintf("%s(%ld): NO ZONEPATH!!\n",
return (-1);
}
}
} else {
mnt_zoneroot[0] = '\0';
}
if (volume_user != NULL) {
": VOLUME_USER was not a valid user!");
return (-1);
}
sizeof (mnt_userdir))
return (-1);
} else {
mnt_uid = 0;
mnt_userdir[0] = '\0';
}
}
if (system_labeled) {
}
/*
* Read in the configuration file to build
* the action_list data structure used by
* exec_actions() and the ident_list data
* structure used by find_fstypes().
*/
config_read();
return (0);
}
}
/*
* If the value of reason is NULL, the
* medium's partitions are mountable.
* Otherwise reason points to a string
* that explains why the medium's partitions
* aren't mountable.
*/
} else {
/*
* Set aa_type to the reason a
* medium or partition can't be mounted,
* e.g. "password_protected" or
* "unformatted_media" (sic).
*/
ai = 0;
ai++;
}
}
} else {
/*
* Since rmmount is unmounting the file systems,
* it doesn't need to know their file system types.
* If the medium is read password protected, trying
* to read it to determine the file system types of
* its partitions will generate SCSI and ident_fs()
* errors.
*/
}
ai = 0;
if (system_labeled &&
else
ai++;
}
}
/*
* The following is a hack. When time permits
* the code needs to be changed to use the action_arg
* array correctly. The current code creates a
* two-element array called send_aa, with an empty
* second element, so the action() method in
* action_filemgr.c only handles one element
* of the action_arg array at a time. That's
* not necessary now, since the action() method
* in action_filemgr.c has been changed to handle
* an array of action_arg elements instead of
* just one. When changing this code, change
* the exec_actions(), exec_mounts(), and
* exec_umounts() methods to handle the
* action_args array correctly as well.
*/
sizeof (struct action_arg));
dprintf("%s[%d]: executing action %s\n",
ai = 0;
dprintf("%s[%d]: aa[%d]->aa_path = %s\n",
dprintf("%s[%d]: aa[%d]->aa_rawpath = %s\n",
dprintf("%s[%d]: aa[%d]->aa_type = %s\n",
dprintf("%s[%d]: aa[%d]->aa_media = %s\n",
dprintf("%s[%d]: aa[%d]->aa_clean = %s\n",
if (action_list != NULL) {
/*
* Execute the premount actions.
*/
}
/*
* If the value of reason is NULL and
* the file system type is known, the
* medium or partition is mountable.
*/
!= 0)) {
} else {
exval = 0;
}
}
/*
* The actions are executed even if the mount fails
* so that the removable media manager will indicate
* the presence of the media, allowing for it to be
* ejected, formatted, etc.
*/
if (action_list != NULL) {
}
ai++;
}
ai = 0;
dprintf("%s[%d]: aa[%d]->aa_path = %s\n",
dprintf("%s[%d]: aa[%d]->aa_rawpath = %s\n",
dprintf("%s[%d]: aa[%d]->aa_type = %s\n",
dprintf("%s[%d]: aa[%d]->aa_media = %s\n",
if (action_list != NULL) {
/*
* Execute the preunmount actions.
*/
}
/*
* try to unmount the file system
*/
} else {
exval = 0;
}
/*
* If the unmounts were successful
* execute the postunmount actions.
*/
}
ai++;
}
} else {
dprintf("%s(%ld): unknown action type %s\n",
exval = 0;
}
return (exval);
}
/*
* Definitions of methods visible to the action() methods
* in the "action" DSOs.
*/
char *
not_mountable(char *vol_name)
{
/*
* Returns NULL if a medium or partition is mountable
* and a string stating the reason the medium or partition
* can't be mounted if the medium or partition isn't mountable.
*
* If the volume_name of the medium or partition is one of the
* following, the medium or partition isn't mountable.
*
* unlabeled_<media_type>
* unknown_format
* password_protected
*
* If the value of the global variable audio_cd is TRUE, the
* medium isn't mountable.
*/
char *reason;
return (reason);
}
return (reason);
}
return (reason);
}
/*
* When later versions of the software can mount
* file systems located on CDs that also contain
* audio data, the conditional operation below
* will have to change.
*/
return (reason);
}
/*
* The medium contains DVD video data.
* It has been mounted, but shouldn't
* be accessed by the filemgr application.
*
* "vedio" is misspelled, but needs to be left
* that way until we can correct it everywhere
* it's used.
*/
return (reason);
}
return (NULL);
}
/*
* Definitions of private methods
*/
static struct action_arg **
build_actargs(char *path)
{
struct action_arg **aa_tab;
int aaidx;
int result;
char *volume_namep;
/*
* lets get a hunk... we can have 40 special files
* so lets make sure we enough. 40 is an assumption
* that with fdisk it is possible to have c-z, and
* also have a vtoc with 16. So I'm alloc'ing 50
*/
aa_tab = (struct action_arg **)
/*
* need to allocate at least one... this will cover
* if there are no special files to mount. The
* find_fstypes stops when it finds aa_path NULL
*/
aaidx = 0;
/*
* allocate another action_arg structure with
* aa_path == NULL to signal the end of the
* action_arg array.
*/
aaidx++;
result = 1;
} else {
result = 0;
}
} else {
}
} else {
result = 0;
}
if (result != 0) {
return (aa_tab);
} else {
return (NULL);
}
}
static void
{
int rval;
dprintf("%s(%ld): %s; %m\n",
return;
}
/*
* Here, we assume that the owners permissions are the
* most permissive. If no "write" permission on
* device, it should be mounted readonly.
*/
dprintf("%s(%ld): %s is dirty but read-only (no fsck)\n",
return;
}
"cleaning (please wait)\n"),
} else {
"requested (please wait)\n"),
}
int fd;
/* get rid of those nasty err messages */
if (fd > 2)
}
} else {
}
gettext("%s(%ld) error: exec of %s failed; %s\n"),
_exit(-1);
}
/* wait for the fsck command to exit */
gettext("%s(%ld) warning: can't wait for pid %d (%s)\n"),
return;
}
if (WEXITSTATUS(rval) != 0) {
"%s(%ld) warning: fsck of \"%s\" failed, returning %d\n"),
} else {
}
}
static void
{
int i;
int retval;
i = 0;
while (action_list[i] != NULL) {
/*
* If the medium type of the partition matches
* the medium type of the action in action_list,
* and the premount flag matches the premount
* flag in the action, load the "action" shared
* object and execute its action() method.
*/
int, char **))
"action", ACT_VERS);
}
int status;
int ifx;
int tmpl_fd;
int err = 0;
O_RDWR);
if (tmpl_fd == -1)
break;
/*
* Deliver no events, don't inherit,
* and allow it to be orphaned.
*/
break;
}
case 0:
(void) ct_tmpl_clear(tmpl_fd);
_exit(0);
action_list[i]->a_argc,
action_list[i]->a_argv);
_exit(0);
case -1:
dprintf("fork1 failed \n ");
break;
default :
(void) ct_tmpl_clear(tmpl_fd);
dprintf("%s(%ld): waitpid() "
"failed (errno %d) \n",
break;
}
}
} else {
dprintf("%s[%d]: executing action() "
"in %s\n",
action_list[i]->a_dsoname);
action_list[i]->a_argc,
action_list[i]->a_argv);
dprintf("%s[%d]: action() returns %d\n",
/*
* If action returns 0, no further
* actions will be executed.
* (see rmmount.conf(4))
*/
if (retval == 0)
break;
}
}
}
i++;
}
}
static int
{
/*
* Return 0 if all goes well.
* Otherwise return the number of problems.
*/
int ai;
int mnt_ai = -1;
char symcontents[MAXNAMELEN];
#ifdef OLD_SLICE_HANDLING_CODE
char *mountname;
char *s;
#endif
/*
* The "mount arguments" are stored in an array
* indexed by the actual command they are
* applied to: "fsck", "mount", and "share"
*/
int i, j;
int ret_val = 0;
char *mntpt;
char *volume_mount_mode;
if ((volume_mount_mode != NULL) &&
dprintf("%s(%d): mount mode '%s', mounting read only\n",
} else {
}
/*
* If a premount action indicated that the partition
* isn't to be mounted, don't mount it.
*/
dprintf("%s(%ld): not supposed to mount %s\n",
continue;
}
/* if audio don't mount it */
if (audio_cd) {
dprintf("%s(%d): don't mount audio\n",
/*
* for now rather than 'continue'
* we will use 'break' because
* the ident_hsfs is broken
*
* When it is fixed, change back to
* 'continue'
*/
break;
}
/* already mounted on! */
dprintf("DEBUG: "
"%s already mounted on (%s dirty)\n",
ret_val++;
continue;
}
dprintf("DEBUG: %s NOT already mounted\n",
/*
* find the right mount arguments for this device
*/
for (j = 0; j < 3; j++) {
/* try to match name against RE */
dprintf("exec_mounts (%d,%d): "
"regexec(\"%s\", \"%s\") ...\n",
name);
cmd_args[j][i])) {
dprintf("exec_mounts: "
"found a NAME match!\n");
break;
}
/* try to match symname against RE */
dprintf("exec_mounts (%d,%d): "
"regexec(\"%s\", \"%s\") ...\n",
symdev);
cmd_args[j][i])) {
dprintf("exec_mounts: "
"found a SYMNAME match!\n");
break;
}
}
}
}
dprintf("exec_mounts: no mount args!\n");
}
/*
* If the file system is not read-only and not
* clean, or if it's not read-only and there's
* an explicit fsck option for this file system,
* run fsck.
*/
}
== FALSE) {
ret_val++;
}
/* remember if we mount one of these guys */
if (mnt_ai == -1) {
}
/*
* export the file system.
*/
}
}
}
if (mnt_ai != -1) {
#ifdef OLD_SLICE_HANDLING_CODE
/*
* XXX: did we used to do something here having to do with
* the slices mounted for a volume??? (lduncan)
*/
symdev);
if (aa[0]->aa_partname) {
*s = NULLC;
}
} else {
}
#else /* !OLD_SLICE_HANDLING_CODE */
if (system_labeled) {
} else {
"./%s", name);
}
#endif /* !OLD_SLICE_HANDLING_CODE */
}
return (ret_val);
}
static int
{
/*
* Unmount all umountable file systems described in as
* and return failure if any filesystem described in aa
* can't be unmounted.
*/
int ai;
char *dos_partition_letterp;
int i;
char mnt_path[MAXPATHLEN];
char *mountpoint;
char *oldmountpoint; /* saved previous mount point */
char *symdev;
char *s;
char *volume_name;
/*
* If it's not in the mount table, assume it's
* not mounted.
*/
>= sizeof (mnt_path)) {
continue;
}
dprintf("%s[%d]: mount path = %s\n",
continue;
/*
* find the right mount arguments for this device
*/
/* try to match volume_name against RE */
dprintf("exec_mounts: "
"regexec(\"%s\", \"%s\") ...\n",
volume_name, 0L, NULL, 0) == 0) {
dprintf("exec_umounts: "
"found a NAME match!\n");
break;
}
/* try to match symname against RE */
dprintf("exec_mounts: "
"regexec(\"%s\", \"%s\") ...\n",
dprintf("exec_umounts: "
"found a SYMNAME match!\n");
break;
}
}
}
/* unshare the mount before umounting */
}
/*
* do the actual umount
*/
}
/* remove the mountpoint, if it's a partition */
(void) rmdir(mountpoint);
}
/* save a good mountpoint */
if (oldmountpoint == NULL)
mountpoint = NULL;
}
/*
* clean up our directories and such if all went well
*/
if (success) {
char rmm_mountpoint[MAXPATHLEN];
/*
* if we have partitions, we'll need to remove the last
* component of the path
*/
if ((oldmountpoint != NULL) &&
*s = NULLC;
}
}
/*
* we only want to remove the directory (and symlink)
* if we're dealing with the directory we probably created
* when we were called to mount the media
* try to remove the symlink
*/
if (system_labeled) {
/* Prefix with zoneroot and userdir */
volume_name) >= MAXPATHLEN)
} else {
>= sizeof (rmm_mountpoint))
}
if ((system_labeled && success) ||
char symname[MAXNAMELEN];
/* remove volmgt mount point */
if (oldmountpoint)
(void) rmdir(oldmountpoint);
char *p = NULL;
/*
* We may also need to remove the
* user's private directory which
* we created during mount.
*/
(void) rmdir(rmm_mountpoint);
*p = '\0';
(void) rmdir(rmm_mountpoint);
}
}
/* remove symlink (what harm if it does not exist?) */
if (system_labeled) {
/* Prefix with zoneroot */
"%s/%s/%s",
>= sizeof (symname))
} else {
"/%s/%s",
>= sizeof (symname))
}
if (success)
}
}
if (oldmountpoint != NULL) {
}
return (success ? 0 : 1);
}
static void
{
int ai;
int fd;
int i, j;
int clean, hsfs_clean;
int first_partition = 0;
int is_pcfs;
if (ident_list == NULL) {
dprintf("%s[%d]: find_fstypes(): no ident list\n",
return;
}
/*
* If it's a cdrom and it only has audio on it,
* the cd may have a file system also, so set
* global flag (ugh)
*/
dprintf("%s[%d]: find_fstypes(): audio CD\n",
return;
}
}
/*
* We leave the file descriptor open on purpose so that
* the blocks that we've read in don't get invalidated
* on close, thus wasting i/o. The mount (or attempted mount)
* command later on will have access to the blocks we have
* read as part of identification through the buffer cache.
* The only *real* difficulty here is that reading from the
* block device means that we always read 8k, even if we
* really don't need to.
*/
/*
* if we're not supposed to mount it, just move along.
*/
/*
* It could be a backup slice.
* If so, read_directory() has
* has already written "backup_slice"
* to aa[ai]->aa_type.
*/
}
continue;
}
/*
* If the filesystem was known to be PCFS, then
* we don't nead to set aa_partname or anything.
* Those have been set by read_directory().
*/
if (is_pcfs) {
dprintf("%s[%d]: find_fstypes(): fdisk partition: %s\n",
continue;
}
dprintf("%s[%d]: find_fstypes(): "
"checking the file system type of %s\n",
dprintf("%s[%d]: find_fstypes(): %s; %m\n",
continue;
}
for (i = 0; ident_list[i]; i++) {
/*
* Check for each file system type in the
* list of file system types that the medium
* can contain. If the ident_fs() function
* for a file system type returns TRUE, set
* aa[ai]->aa_type to the name of that file
* system type break out of the for loop.
*/
foundmedium = FALSE;
for (j = 0; ident_list[i]->i_media[j]; j++) {
ident_list[i]->i_media[j]) == 0) {
foundmedium = TRUE;
dprintf("%s[%d]: find_fstypes():found medium type: %s\n",
break;
}
}
if ((foundmedium == TRUE) &&
/*
* Get the id function and call it.
*/
ident_list[i]->i_ident =
(bool_t (*)(int, char *, int *, int))
"ident_fs", IDENT_VERS);
}
dprintf("%s[%d]: find_fstypes() calling ident_fs() in %s\n",
&clean, 0);
}
/*
* If we have identified this as a hsfs
* there could be a chance that this
* actualy is a udfs. We flag if hsfs
* then continue testing.
*/
"hsfs") == 0) {
hsfs_clean = clean;
continue;
}
break;
}
}
if (foundfs) {
} else if (ishsfs) {
} else {
}
dprintf("%s[%d]: find_fstypes() %s: fstype = %s; clean = %s\n",
}
}
static bool_t
{
/*
* Mount a filesystem.
*/
char *targ_dir;
char mountpoint[MAXPATHLEN];
char *zonemountpoint;
int mountpoint_bufcount = 0;
char *volume_mount_mode;
char dev_path[MAXPATHLEN];
char *av[12];
volume_mount_mode = "ro";
} else {
volume_mount_mode = "rw";
}
dprintf("%s(%d): entering hard_mount(): volume_mount_mode = %s\n",
return (FALSE);
}
/*
* Here, we assume that the owners permissions are the
* most permissive and that if he can't "write" to the
* device it should be mounted readonly.
*/
/*
* If he wants it mounted readonly, give it to him. The
* default is that if the device can be written, we mount
*/
/* user has requested RO for this fs type */
volume_mount_mode = "ro";
dprintf("%s(%d): hard_mount(), MA_READONLY: mount_mode = %s\n",
}
} else {
volume_mount_mode = "ro";
dprintf("%s(%d): hard_mount(), not owner: mount_mode = %s\n",
}
/*
* "hsfs" file systems must be mounted readonly
*/
volume_mount_mode = "ro";
}
dprintf("%s(%d): hard_mount(), fstype checked: mount_mode = %s\n",
/*
* If the file system isn't clean, we attempt a ro mount.
* We already tried the fsck.
*/
volume_mount_mode = "ro";
}
dprintf("%s(%d): hard_mount(), clean bit checked: mount_mode = %s\n",
gettext("%s(%ld) error: VOLUME_NAME not set for %s\n"),
return (FALSE);
}
return (FALSE);
}
/*
* set the top level directory bits to 0755 so user
* can access it.
*/
}
if (aa->aa_partname) {
gettext("%s(%ld) error: path too long\n"),
return (FALSE);
}
} else {
targ_dir) > MAXPATHLEN) {
gettext("%s(%ld) error: malloc failed\n"),
return (FALSE);
}
}
/* make our mountpoint */
} else {
}
/* add in readonly option if necessary */
if (*rdonly) {
else
}
>= sizeof (dev_path)) {
return (FALSE);
}
if ((pcfs_part_id != NULL) &&
(isalpha(pcfs_part_id[0]))) {
/* have pcfs with fdisk, append aa_partname */
>= sizeof (dev_path)) {
return (FALSE);
}
/*
* PCFS with a single partition.
* Use the partition letter provided by
* vold.
*/
sizeof (dev_path))
>= sizeof (dev_path)) {
return (FALSE);
}
} else {
/*
* multiple pcfs partitions, use
* 'letters' hung by vold
*/
sizeof (dev_path))
>= sizeof (dev_path)) {
return (FALSE);
}
}
dprintf("the device path being mounted is: '%s'\n",
dev_path);
}
}
case 0:
cnt = 0;
}
gettext("%s(%ld) error: exec of %s failed; %s\n"),
_exit(-1);
case -1:
dprintf("fork1 failed \n ");
return (FALSE);
default :
dprintf("%s(%ld): waitpid() failed (errno %d) \n",
return (FALSE);
}
}
if (status == 0) {
dprintf("%s(%ld): \"%s\" mounted\n",
} else {
dprintf("%s(%ld): \"%s\" mounted (%s)\n",
}
"\nDEBUG: Setting u.g of \"%s\" to %d.%d (me=%d.%d)\n\n",
/*
* set owner and modes.
*/
/* read implies execute */
}
}
}
dprintf("DEBUG: Setting mode of \"%s\" to %05o\n\n",
mountpoint, mpmode);
} else {
/* if there was an error, print out the mount message */
dprintf("%s(%ld) mount error: %s -F %s %s\n",
}
return (ret_val);
}
static bool_t
is_backup_slice(char *raw_path)
{
int file_descriptor;
char *slice_namep;
int slice_number;
file_descriptor = -1;
slice_number = 0;
while ((slice_number < V_NUMPAR) &&
slice_number++;
}
if (slice_number < V_NUMPAR) {
if (file_descriptor >= 0) {
}
(void) close(file_descriptor);
}
}
return (result);
}
static int
read_directory(char *dirname,
int *aaidx,
struct action_arg **aa_tab)
{
char *filename;
char *medium_type;
char *pathname;
int result;
result = 1;
result = 1;
dprintf("%s[%d]: couldn't calloc pathname\n",
result = 0;
}
dprintf("%s[%d]: read_directory() too many partitions\n",
result = 0;
}
result = 0;
}
/*
* The path passed in as dirname is a
* a block special file. Load its
* attributes into the action_arg.
*/
dprintf("%s[%d]: %s is a block special file\n",
(*aaidx)++;
/*
* Allocate another action_arg
* to end the aa_tab array with
* an action_arg with aa_path == NULL;
*/
dprintf("%s[%d]: couldn't calloc an action arg\n",
result = 0;
}
dprintf("%s[%d]: couldn't open %s as a directory\n",
result = 0;
}
}
continue;
continue;
dprintf("%s[%]: %s does not exist\n",
exit(1);
}
aa_tab);
if (is_backup_slice(
TRUE) {
} else {
"backup_slice";
}
(*aaidx)++;
/*
* Allocate another action_arg
* to end the aa_tab array with
* an action_arg with aa_path == NULL;
*/
"%s[%d]: couldn't calloc an action arg\n",
result = 0;
}
}
}
}
}
}
dprintf("%s[%d]: leaving read_directory, result = %d\n",
return (result);
}
static void
{
/*
* export the filesystem
*/
extern void share_readonly(struct mount_args *);
extern void quote_clean(int, char **);
extern void makeargv(int *, char **, char *);
int pfd[2];
int rval;
int ac;
int n, buf_count = 0;
return;
}
/* if it's a readonly thing, make sure the share args are right */
}
/* 3 - 2 spaces and a NULL terminator */
gettext("%s(%ld) error: malloc failed\n"),
return;
}
/* build our command line into buf */
aa->aa_mountpoint);
gettext("%s(%ld) error: exec of %s failed; %s\n"),
_exit(-1);
}
/* wait for the share command to exit */
dprintf("%s(%ld): waitpid() failed (errno %d)\n",
return;
}
if (WEXITSTATUS(rval) != 0) {
/* if there was an error, print out the mount message */
}
} else {
aa->aa_mountpoint);
}
}
static bool_t
umount_fork(char *path)
{
int rval;
int fd;
/* get rid of those nasty err messages */
}
gettext("%s(%ld) error: exec of %s failed; %s\n"),
_exit(-1);
/*NOTREACHED*/
}
/* wait for the umount command to exit */
if (WEXITSTATUS(rval) != 0) {
"%s(%ld) error: \"umount\" of \"%s\" failed, returning %d\n"),
return (FALSE);
}
return (TRUE);
}
/*ARGSUSED*/
static void
{
/*
* unexport the filesystem.
*/
extern void makeargv(int *, char **, char *);
int pfd[2];
int rval;
int ac;
int n, buf_count = 0;
int mountpoint_bufcount = 0;
char *mountpoint = NULL;
/*
* reconstruct the mount point and hope the media's still
* mounted there. :-(
*/
/* 1 - for NULL terminator, 3 - for "/"s */
if (mountpoint == NULL) {
gettext("%s(%ld) error: malloc failed\n"),
return;
}
} else {
/* 1 - for NULL terminator, 2 - for "/"s */
if (mountpoint == NULL) {
gettext("%s(%ld) error: malloc failed\n"),
return;
}
}
/* build our command line into buf */
gettext("%s(%ld) error: malloc failed\n"),
return;
}
gettext("%s(%ld) error: exec of %s failed; %s\n"),
_exit(-1);
}
/* wait for the share command to exit */
dprintf("%s(%ld): waitpid() failed (errno %d)\n",
return;
}
if (WEXITSTATUS(rval) != 0) {
/* if there was an error, print out the message */
}
}
}
static void
usage(void)
{
"%s(%ld) usage: %s [-D] [-c config_file] [-d filesystem_dev]\n"),
exit(-1);
}