vold_util.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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <dlfcn.h>
#include <rpc/auth_unix.h>
#include <rpcsvc/nfs_prot.h>
#include <regex.h>
#include "vold.h"
#include "md4.h"
extern int vol_fd;
typedef int mnr_mask;
#define MNRHOWMANY(x, y) (((x)+((y)-1))/(y))
typedef struct mnr_set {
} mnr_set;
#define MNR_SET(n, p) \
#define MNR_CLR(n, p) \
#define MNR_ISSET(n, p) \
static int minor_initted;
#define MNR_HASH_SIZE 64
static struct q mnr_q_hash[MNR_HASH_SIZE];
struct mnr_track {
struct q q; /* linked hashed list */
};
struct fentry {
char *fname;
#define FENTRY_MATCH 0x1
#define FENTRY_NO_FILE 0x2
#define FENTRY_REMOVABLE 0x4
#define FENTRY_NOT_REMOVABLE 0x8
int flag;
};
static struct dentry {
char *dirname;
} *dir_entry_cache;
/*
* Property management for volume flags.
*/
#define PROP_ACC "s-access"
#define PROP_ACC_TAPE "seq"
#define PROP_ACC_DISK "rand"
#define PROP_DIST "s-distr"
#define PROP_DIST_LOC "local"
#define PROP_DIST_GLOB "global"
#define PROP_DENS "s-density"
#define PROP_DENS_L "low"
#define PROP_DENS_M "medium"
#define PROP_DENS_H "high"
#define PROP_DENS_U "ultra"
#define PROP_PART "s-parts"
#define PROP_RMONEJECT "s-rmoneject"
#define PROP_ENXIO "s-enxio"
#define PROP_TRUE "true"
#define PROP_FALSE "false"
/*
* This is the list of properties that the owner is allowed to set.
*/
static char *owner_props[] = {
"s-stack",
"s-readlabel",
""
};
#ifdef VOLMGT_DEV_TO_TTY_WORKED
/*
* This slop is stolen from the ttyname function in the C library.
* ttyname didn't do what I wanted.
*/
typedef struct {
char *name;
int flags;
} entry_t;
#define MAX_DEV_PATH 128
#define MAX_SRCH_DEPTH 4
#define MATCH_MM 1
#define MATCH_FS 2
#define MATCH_INO 4
#define MATCH_ALL 7
#define DEV "/dev"
{ "/dev", MATCH_ALL };
{ NULL, 0 }
};
#define START_STATE 1
#define COMMENT_STATE 2
#define DIRNAME_STATE 3
#define FLAG_STATE 4
#define CHECK_STATE 5
#define COMMENT_CHAR '#'
#define EOLN_CHAR '\n'
#endif /* VOLMGT_DEV_TO_TTY_WORKED */
/*
* CRC Calculation code stolen from cp.
*/
#define CRCMAGIC 987654
static char *unsafe_list[DEFAULT_UNSAFE];
static uint_t unsafe_ind = 0;
/* length of buffer for printing numbers */
#define VOLD_NUMBUFLEN 512
/* length of buffer for printing properties */
/* length of buffer used to convert a regex to a shell regex */
/*
* insert "item" into the from of the queue pointed to by "head"
*
* this routines a.k.a. INSQUE() (see util.h)
*/
void
{
}
}
}
void
{
} else {
}
} else {
}
}
void
{
char *s;
*argc = 0;
if (setnull) {
s[-1] = NULL;
}
if (*s == '\n') {
*s = NULLC;
}
*argv++ = s;
(*argc)++;
} else if (isspace(*s)) {
}
break;
}
}
}
/*
* Allocate and free from the minor number space.
* We keep a bitmap, with each bit representing a minor number,
* there are 18 bits of minor number. This means we dedicate
* 32k to this array. Not bad, really.
*
* Bits are initialized ON. Minor number 0 is reserved as it is
* the control device for the vol driver.
*
* Bit manipulation code stolen from the select(2) stuff.
*/
static void
{
/* minor 0 is reserved */
minor_initted = 1;
}
minor_alloc(vol_t *v)
{
int i;
if (!minor_initted) {
minor_init();
}
for (i = 0; i < size; i++) {
mnr--;
/* issue ioctl to create the minor nodes for vol unit */
"failed to create minor %d!\n"), mnr);
/*NOTREACHED*/
}
sizeof (struct mnr_track));
#ifdef DEBUG_MINOR
#endif
}
}
/* should this be a fatal? */
return (0);
}
static struct mnr_track *
{
#ifdef DEBUG_MINOR
#endif
while (mt) {
#ifdef DEBUG_MINOR
#endif
return (mt);
}
}
return (NULL);
}
void
{
#ifdef DEBUG
#endif
if (!minor_initted) {
minor_init();
}
if (minr == 0) {
/*NOTREACHED*/
}
/* issue ioctl to remove the minor nodes for vol unit */
minr);
/*NOTREACHED*/
}
}
/*
* Leave the minor number allocated, but null out the pointer to
* to vol. This will give us the ability to garbage collect the
* minor numbers at some point.
*
* Probably want to create a special list to hang these guys off of
* to make collecting them easier.
*/
void
{
}
}
/*
* garbage collect the minor numbers that are still hanging around.
* wander through the list of mt's and see which minor numbers no
* longer have volumes associated with them. if they don't have
* any volume, try to unmap them. If it succeeds, go ahead and
* free up the minor number.
*
* XXX: not currently used
*/
void
minor_gc()
{
/* we should probably do something ... */
}
/*
* Return the vol structure that a minor number maps. used for
* taking messages from the driver and figuring out what volume
* they refer to.
*/
vol_t *
{
}
return (NULL);
}
void
{
return;
}
}
static int
isbadchar(int c)
{
int ret_val = 0; /* default is 'char is ok' */
switch (c) {
case '/':
case ';':
case '|':
ret_val = 1;
break;
default:
ret_val = 1;
}
}
return (ret_val);
}
char *
{
char *s = buf;
int i;
#ifdef DEBUG
#endif
if (len > MAXNAMELEN) {
#ifdef DEBUG
MAXNAMELEN, len);
#endif
len = MAXNAMELEN;
}
for (i = 0; i < len; i++) {
break; /* we've reached the end */
}
#ifdef DEBUG
name[i]);
#endif
*s++ = '_';
} else {
*s++ = name[i];
}
}
}
*s = NULLC; /* null terminate */
#ifdef DEBUG
#endif
return (s);
}
#ifdef VOLD_HANDLES_TAPE
/*
* These are various bits that we use in the minor number to
* differentiate between different types of devices. They should
* NEVER be used by anyone but this volmakedev function, because
* they are subject to change in the future.
*/
/*
* if part >= 0, create the dev_t for that partition. If it's -1,
* return the lowest dev_t that will match this volume;
*/
{
minor_t m;
int i;
if (vol_major == -1) {
}
/* make sure he's got an id */
if (v->v_id == 0) {
v->v_id = volumeid_get();
} else {
volumeid_register(v->v_id);
}
m = v->v_id;
/* XXX better error recovery! */
if (m > MINOR_MAX) {
}
/* set up the bits in the minor number for tape, etc. */
/* we are a tape */
m |= MINOR_TAPE;
if (arg != -1) {
m |= MINOR_REWIND;
}
m |= MINOR_SVR4;
}
}
} else {
/* we are a disk */
if (v->v_nparts != 0) {
if (arg == -1) {
/* find the lowest partition number */
for (i = 0; i < V_NUMPAR; i++) {
if (v->v_parts & (1<<i)) {
arg = i;
break;
}
}
}
m |= arg<<MINOR_PARTSHFT;
}
}
}
{
if (dev & MINOR_TAPE) {
if (dev & MINOR_SVR4) {
}
if (dev & MINOR_REWIND) {
}
return (retval);
}
/* we are a disk */
/* is this ok w/o V_PARTSHIFT ?? */
}
return (retval);
}
/*
* take a minor number and return what the volume id must have been.
*/
{
}
#endif /* VOLD_HANDLES_TAPE */
/*
* Return a props string that represents the vol_t.
*
* This function might be expensive, but I don't think we'll call it
* often. A more efficient way to do this would be to build the
* prop string by hand, just once, rather than calling prop_attr_put.
*/
char *
{
char *s;
char tmpstr[VOLD_PROPBUFLEN];
char partstr[VOLD_PROPBUFLEN];
uint_t i;
char *path;
char **vopp;
/* flags */
if (v->v_flags & V_RMONEJECT) {
}
}
}
}
}
} else { /* we are a disk, do we have partitions? */
for (i = 0; i < V_NUMPAR; i++) {
if (1<<i & parts) {
}
}
/* gets rid of that last comma */
}
}
}
if (v->v_flags & V_MEJECTABLE) {
}
/* see if location is in the vol obj prop field */
/* is the volume in but the location isn't ?? */
/* add in the location property */
/* the loc's there but the vol isn't -- remove loc */
}
}
/*
* Stick the other properties on the tail.
*/
ps = s;
}
return (ps);
}
/*
* given a volume, check to see if the driver needs to be notified that
* the V_ENXIO flag has been set
*
* this used to be done at "unmap" time, but that was sometimes too late
*/
static void
check_for_enxio(vol_t *v)
{
int i;
struct vioc_flags vfl;
for (i = 0; i < (int)v->v_ndev; i++) {
/*
* if someone set the enxio flag, we'll tell the driver
* about it now
*/
#ifdef DEBUG
debug(1,
"check_for_enxio: calling VOLIOCFLAGS(VFL_ENXIO), unit %d\n",
volume);
#endif
debug(1,
"check_for_enxio: VOLIOCFLAGS (%d) of \"%s\"; %m\n",
}
}
}
}
/*
* take the props out of the string and stick them into the vol
*/
void
{
char *val;
v->v_flags = 0;
}
}
}
}
/*
* acutally tell the driver about the enxio stuff *now*
* (if needed)
*/
check_for_enxio(v);
}
/*LINTED: null effect is ok*/
}
}
}
}
}
}
v->v_flags |= V_RMONEJECT;
}
/*
* Save off any props that weren't slurped up into flags
*/
}
}
/*
* This function checks three things:
* 1) permission to write attributes
* (user == owner, root, owner == nobody)
* 2) no funky characters to screw us in attr or value
* in particular ";" and "="
* 3) if it's a "system" parameter (starts with s-), make
* sure it's a writeable one (owner_props).
*/
{
char **s, *p;
/* only the owner can change any attributes */
return (FALSE);
}
/* check for "correctness"... does he use; anywhere? */
for (p = val; *p; p++) {
if ((*p == ';') || (*p == '=')) {
return (FALSE);
}
}
for (p = attr; *p; p++) {
if ((*p == ';') || (*p == '=')) {
attr);
return (FALSE);
}
}
/* If it's a "system" prop, make sure it's settable */
for (s = owner_props; **s; s++) {
return (TRUE);
}
}
return (FALSE);
}
return (TRUE);
}
void
{
char *merged;
}
/*
* Take a string like "0, 2, 7" and return a bit mask that
* has these bits turned on. Converts from a partition
* value string from the nis+ database into our local way of
* keeping track of partitions.
*/
static uint_t
{
char *p, *q;
q = val;
*npart = 0;
for (;;) {
p = strchr(q, ',');
if (p != NULL) {
*p = NULLC;
(*npart)++;
q = p+1;
} else {
(*npart)++;
break;
}
}
return (parts);
}
char *
{
extern char self[];
char *nls;
return (nls);
}
location_localdev(char *ls)
{
char *val;
extern char self[];
}
}
}
return (res);
}
#ifdef VOLMGT_DEV_TO_TTY_WORKED
/*
* This slop is stolen from the ttyname function in the C library.
* ttyname didn't do what I wanted.
*
* called (if working) by action_buildenv()
*/
char *
{
static entry_t *get_pri_dirs(void);
int found = 0;
int dirno = 0;
int is_console = 0;
/*
* search the priority directories
*/
srch_dirs = get_pri_dirs();
/*
*/
is_console = 1;
found = 1;
}
}
/*
* if /dev is one of the priority directories, only
* search its top level (set depth = MAX_SEARCH_DEPTH)
*/
dirno++;
}
/*
* search the /dev/ directory, skipping priority directories
*/
if (!found) {
}
}
}
/*
* return
*/
if (found) {
if (is_console) {
return (CONSOLE);
} else {
return (rbuf);
}
} else {
return (NULL);
}
}
/*
* srch_dir() searches directory path and all directories under it up
* to depth directories deep for a file described by a stat structure
* fsb. It puts the answer into rbuf. If a match is found on device
* number only, the file name is put into dev_rbuf and dev_flag is set.
*
* srch_dir() returns 1 if a match (on device and inode) is found,
* or 0 otherwise.
*
* called by devtotty()
*/
static int
int depth, /* current depth (/dev = 0) */
{
char file_name[MAX_DEV_PATH];
char *last_comp;
int found = 0;
int dirno = 0;
int path_len;
return (0);
}
}
/*
* do we need to search this directory? (always search /dev at depth 0)
*/
return (0);
}
}
}
/*
* open directory
*/
return (0);
}
/*
* skip two first entries ('.' and '..')
*/
return (0);
}
*last_comp++ = '/';
/*
* read thru the directory
*/
/*
* if the file name (path + "/" + d_name + NULL) would be too
* long, skip it
*/
MAX_DEV_PATH) {
continue;
}
continue;
}
/*
* if a file is a directory and we are not too deep, recurse
*/
if (depth < MAX_SRCH_DEPTH) {
} else {
continue;
}
/*
* else if it is not a directory, is it a character special
* file?
*/
found = 1;
}
}
}
return (found);
}
/*
* get_pri_dirs() - returns a pointer to an array of strings, where each string
* is a priority directory name. The end of the array is marked by a NULL
* pointer. The priority directories' names are obtained from the file
* list of directories.
*
* then parsed into strings of priority directory names, omitting comments and
* blank lines.
*
* called by devtotty()
*/
static entry_t *
{
/*
*/
return (def_srch_dirs);
}
return (def_srch_dirs);
}
/*
* ensure newline termination for buffer. Add an extra
* entry to dir_vec for null terminator
*/
*ebuf++ = '\n';
if (*buf == '\n') {
++sz;
}
}
return (def_srch_dirs);
}
state = START_STATE;
switch (state) {
case START_STATE:
if (*buf == COMMENT_CHAR) {
break;
}
/* skip leading white space */
}
break;
case COMMENT_STATE:
state = START_STATE;
}
break;
case DIRNAME_STATE:
state = CHECK_STATE;
/* skip trailing white space */
state = FLAG_STATE;
}
break;
case FLAG_STATE:
switch (*buf) {
case 'M':
break;
case 'F':
break;
case 'I':
break;
case EOLN_CHAR:
state = CHECK_STATE;
break;
}
break;
case CHECK_STATE:
if (tfd >= 0) {
char buf[256];
}
} else {
char *slash;
while (*slash == '/') {
}
}
vec++;
}
state = START_STATE;
/*
* This state does not consume a character, so
* reposition the pointer.
*/
buf--;
break;
}
}
}
#endif /* VOLMGT_DEV_TO_TTY_WORKED */
/*
* Build a table that makes the crc calculation much faster.
*
* called by calc_crc()
*/
static ulong_t *
{
register int b, i;
ulong_t v;
return (crctab);
}
for (b = 0; b < 256; b++) {
for (v = b << (24), i = 0; i < 8; i++) {
v = (v << 1) ^ poly;
} else {
v = v << 1;
}
}
crctab[b] = v;
}
return (crctab);
}
/*
* Calculate the CRC for a given record.
*/
{
while (len--) {
}
return (crc);
}
/*
* Calculate the MD4 signature for a given buffer.
*/
void
{
}
/*
* Generate a unique key, checking the database to make sure the
* triple <medtype, labtype, 0x%x> does not exist. This assumes
* the label_key function generates the key into a string as
* a standard hex number.
*
* Note that the label functions do not have to use this to generate
* a unique key, they can use the db_testkey function directly to
* perform check for unique key.
*/
{
int loopcnt = 0;
if (!initialized) {
/*
* We use the time in seconds and usecs as the
* seed. The "most interesting" bits of the
* tv_usec are 4 - 19, so we just shift over
* some and pass that time seed48.
*/
initialized = TRUE;
}
for (;;) {
return (key);
}
/*
* If we try more than 10 random numbers, we just
* give up... something is very wrong. Hopefully we
* will not be hosing things too badly.
*/
if (loopcnt++ > 10) {
return (key);
}
}
/*NOTREACHED*/
}
/*
* return a "unique" time value
*
* this is done by taking the current time, then decrementing by a random
* number which we ensure is less than the current time value, thus ensuring
* that the resulting "unique" time value is positive
*
* we ensure that the random subtactor is less than the current time value
* by dividing it in half until it is
*/
{
int loopcnt = 0;
if (!initialized) {
/*
* we use the time in seconds and usecs as the seed
*
* the "most interesting" bits of the tv_usec are 4 - 19,
* so we just shift over some and pass that time seed48
*/
initialized = TRUE;
}
/* start with current time for our "random time" value */
/*
* "uniqeify" the time by changing tloc to be between 0 and the
* "real" time using a pseudo-random number
*
* ensure that the pseudo-random subtractor is less than tloc by
* halving it until its cooperative
*/
rval >>= 1;
}
/*
* decrement tloc by the "random" key value, after which tloc
* is "uniquified"
*/
/*
* look until we either find a unique (database-wise) key or we
* decide to give up trying
*/
/* create an ascii version of our "key" */
/* see if the key already exists */
break; /* success */
}
/*
* if we try more than loopmax times we just give up since
* something is very wrong
*/
debug(1,
"unique_time: bad time 0x%x for (%s,%s,%s)\n",
break; /* failure */
}
tloc--; /* since time moves forward we go backward */
}
#ifdef DEBUG_DB
#endif
return (tloc);
}
#ifdef DEBUG_VTOC
static char
{
/*
* return an evaluation of the version number
*/
static char ret_str[80];
switch (ver) {
case 0:
break;
case V_VERSION:
break;
default:
break;
}
return (ret_str);
}
static void
{
/*
* print the vtoc info
*/
extern int debug_level;
ushort_t i;
if (debug_level < odl) {
return;
}
if (part_cnt > 0) {
for (i = 0; i < V_NUMPAR; i++) {
" %2d %02d %2d %7d %7d\n",
}
}
}
}
#endif /* DEBUG_VTOC */
/*
* Take a vtoc and return a pmask and npart that represents the
* valid partitions.
* maxoff is the maximum block offset that is valid for this media.
* In some cases it will be 0xffffffff, where there is no way to tell.
* In other cases (like the cdrom), it will be consistent for the media.
* The reason for this is that some people put junky labels on devices
* (like cdrom) and we need to be able to differentiate between a
* bogus partition and a good one.
* We also detect duplicate partitions, and remove the duplication. There
* is no point in making available the duplicate, so we don't.
* There is also code to detect for a canonical floppy partition.
* It is really stupid to put a Sun label (for example) on a floppy,
* but we do. We don't support the notion of partitions on a floppy,
* we just always return the "c" partition.
*
* NOTE: this routine handles up to 32 partitions. The original routine
* (partition_conv) only handled up to eight. It is included, after
* this routine, for compatibility
*/
void
{
int i;
int j;
#ifdef DEBUG_VTOC
#endif
*npart = 0;
*pmask = 0;
return;
}
for (i = 0; i < V_NUMPAR; i++) {
maxoff)) {
#ifdef DEBUG_VTOC
i);
#endif
*pmask |= (1<<i);
(*npart)++;
}
}
#ifdef DEBUG_VTOC
#endif
if (*npart == 0) {
/*
* No valid partitions?!?! It must be that stupid
* answerbook CD. Those guys should be shot.
* If the default base partition is valid,
* we'll just use that one.
*/
#ifdef DEBUG_VTOC
#endif
*npart = 1;
}
}
/*
* Remove duplicates. The canonical cd-rom label is captured
* here, since the driver returns the A and C partitions
* as the same (on sparc, at least).
*/
for (i = 0; i < V_NUMPAR-1; i++) {
if ((*pmask & (1 << i)) == 0) {
continue;
}
for (j = i+1; j < V_NUMPAR; j++) {
#ifdef DEBUG_VTOC
"partition_conv_2: part %d == part %d\n",
i, j);
#endif
*pmask &= ~(1<<j);
(*npart)--;
}
}
}
/* check for canonical floppy partition. */
/*
* A bit of a hack, yes, but do you want it to do the
* right thing, or do you want it elegant...
*/
if ((*npart == 3) &&
#ifdef DEBUG_VTOC
#endif
*npart = 1;
}
if ((*npart == 3) &&
#ifdef DEBUG_VTOC
#endif
*npart = 1;
}
#ifdef DEBUG_VTOC
#endif
}
/*
* Take a vtoc and return the first partition that maps the lowest
* sector, while still mapping something.
*
* Return -1 if none found.
*/
int
partition_low(struct vtoc *v)
{
int i; /* index */
return (-1);
}
/*
* algorithm: scan the partition table. If we have
* a partition of a positive size, we look at the
* starting address. If it's zero, that's great,
* just return it. If it's nonzero, remember it so
* we can return the lowest possible number if
* necessary.
* We return -1 if there are no partitions with a size,
* but this is an error in the vtoc, really.
*/
for (i = 0; i < V_NUMPAR; i++) {
return (i);
}
lowi = i;
}
}
}
return (lowi);
}
/*
* implements the "nobody" semantic, in addition to fooling around
* with the dumb nis+ network names.
*
* I do assume that DEFAULT_USER is the same (probably "nobody") in
* all domains, so I don't bother checking other domains for the
* user DEFAULT_USER or the group DEFAULT_GROUP. Seems like
* an efficient thing to do, but it may not be right in all
* (any?) cases.
*
* At one time, I was using the nis_local_principal() to represent
* as root on one machine would appear as owned by "nobody" on
* other machines. This was not the desired semantic (by me),
* so I decided to make all roots the same on the network.
*/
/*
* Return a (malloced) char * that is a valid "network" user
* name, as defined by nis+. So, given for the uid for the
* "bar" user, this function will return: "bar.foo.you.sun.com.",
* if "foo.you.sun.com." is your domain name.
*/
char *
{
char *uname;
#ifdef notdef
if (uid == 0) { /* root! */
/* assume we always run as root */
} else {
#endif
/* +2 == "." plus null */
#ifdef notdef
}
#endif
} else {
/* +2 == "." plus null */
}
return (uname);
}
/*
* Take apart a name like: "bar.foo.you.sun.com." and return the
* local uid for that user in that domain. Also just works for
* "bar".
* XXX: Note that the remote domain case is currently unimplemented.
* XXX: Also note that we don't search the remote domain for anyone
* XXX: named DEFAULT_USER. This is considered a feature.
*/
network_uid(char *uname)
{
/*
* XXX: bummer. It's a some other domain.
* XXX: Someday, we'll go ask that domain for the
* XXX: right info, for now...
* XXX: When (if) we implement this, we'll want to
* XXX: build a small cache to keep from doing this
* XXX: all the time...
* NNN: Please note that there are sometimes
* NNN: significant network delays which will
* NNN: *hang the server* if it has to wander
* NNN: off to some remote domain. This is probably
* NNN: better off done in a separate thread.
*/
"can't reach domain name %s to find user %s\n"),
return (default_uid);
}
/* FALL THROUGH... for local domain case */
}
} else {
uid = default_uid;
}
}
return (uid);
}
/*
* Return a (malloced) char * that is a valid "network" group
* name, as defined by nis+. So, given for the gid for the
* "foo" group, this function will return: "foo@bar.you.sun.com.",
* if "foo.you.sun.com." is your domain name.
*/
char *
{
char *gname;
/* +2 == "@" plus null */
} else {
}
return (gname);
}
/*
* Take apart a name like: "foo@bar.you.sun.com." and return the
* local gid for that group in that domain. Also just works for
* "foo".
* XXX: Note that the remote domain case is currently unimplemented.
* XXX: Also note that we don't search the remote domain for any
* XXX: group named DEFAULT_GROUP. This is considered a feature.
*/
network_gid(char *gname)
{
char *dirn;
/*
* XXX: bummer. It's a some other domain.
* XXX: Someday, we'll go ask that domain for the
* XXX: right info, for now...
* XXX: When (if) we implement this, we'll want to
* XXX: build a small cache to keep from doing this
* XXX: all the time...
* NNN: Please note that there are sometimes
* NNN: significant network delays which will
* NNN: *hang the server* if it has to wander
* NNN: off to some remote domain. This is probably
* NNN: better off done in a separate thread.
*/
"can't reach domain name %s to find group %s\n"),
return (default_gid);
}
/* FALL THROUGH... for local domain case */
}
} else {
gid = default_gid;
}
}
return (gid);
}
/*
* Compute a 32 bit number from a string of characters. Not great,
* but seems to work okay.
*/
hash_string(char *s)
{
int rotor;
for (rotor = 0;
*s != NULLC;
}
return (rval);
}
/*
* Load a dso named "name" into our address space, and call the
* function named "funcname"
*/
{
extern char *vold_devdir;
void *dso_handle = NULL;
/*
* Look for the name with the correct version in various places.
* Algorithm: /usr/lib/vold/name.version
* ./name.version
* ./name (warning)
*/
vold_devdir, name);
"dso_load: %s/%s.%d not found\n"),
goto dun;
}
}
"trying unversioned dso %s (want ver %d)\n"),
}
}
/*
* decided on a name, now on to the real work.
*/
} else {
namebuf);
goto dun;
}
/*
* Call the initialization function. If it returns
* FALSE, we have no interest in it, so we just dump
* it.
*/
#ifdef DEBUG
info(
gettext("dso_load: would have unloaded %s, but didn't because of a dbx bug\n"),
name);
#else
(void) dlclose(dso_handle);
#endif
goto dun;
} else {
}
} else {
namebuf);
goto dun;
}
dun:
return (res);
}
add_to_unsafe_list(char *fs)
{
if (unsafe_ind >= DEFAULT_UNSAFE) {
return (FALSE);
}
return (TRUE);
}
/*
* flush the unsafe list
*/
void
{
int i;
for (i = 0; i < unsafe_ind; i++) {
if (unsafe_list[i] != NULL) {
free(unsafe_list[i]);
unsafe_list[i] = NULL;
}
}
unsafe_ind = 0;
}
static bool_t
{
int i;
goto dun;
}
goto dun;
}
for (i = 0; i < unsafe_ind; i++) {
if (unsafe_list[i] == NULL) {
/* reached end of list */
break;
}
debug(1,
break;
}
}
dun:
}
}
return (res);
}
unsafe_check(vol_t *v)
{
char namebuf[MAXPATHLEN];
char *path;
int i;
/*
* Find the name for the block devices of this volume,
* and call unsafe_fs with them.
*/
return (FALSE);
}
continue;
}
if (v->v_ndev > 1) {
/* partitions */
for (i = 0; i < (int)v->v_ndev; i++) {
return (TRUE);
}
}
} else {
return (TRUE);
}
}
}
return (FALSE);
}
int
{
int partno;
int i;
/*
* note that we start counting devno, and partno the same
* as we count bits (i.e. bitpos 0, bitpos 1, ...)
*/
partno = 0;
for (i = 0; i < V_NUMPAR; i++) {
if (partmask & (1<<i)) {
break;
}
partno++;
}
}
return (i);
}
/*
* Convert a shell regular expression to a RE (regular expression)
* (thanks to Sam Falkner)
*/
char *
sh_to_regex(char *s)
{
char vi[VOLD_REGEXNAME_LEN];
char *c;
vi[0] = '^';
for (c = vi+1; *s; ++c, ++s) {
if (*s == '\\') {
*(c++) = *(s++);
} else if (*s == '*') {
*(c++) = '.';
} else if ((*s == '.') || (*s == '$') || (*s == '^')) {
*(c++) = '\\';
} else if (*s == '?') {
*s = '.';
}
*c = *s;
if (*s == NULLC) {
++c;
break;
}
}
*(c++) = '$';
*c = NULLC;
}
/*
* Take a path and return the character device. The getfullrawname
* function only works with dsk and rdsk names. I also do the
* irritating floppy name. Unlike getfullrawname, we return
* NULL if we can't find the right stuff.
*/
char *
rawpath(char *n)
{
extern char *getfullrawname(char *);
char *rval;
char namebuf[MAXPATHLEN];
char *s;
rval = getfullrawname(n);
return (rval);
}
}
/* ok, so we either have a bad device or a floppy. */
/* the fd# form */
s = strstr(n, "/fd");
if (s != NULL) {
s++; /* point at 'f' */
*s = NULLC;
*s = 'f';
}
/* the diskette form */
s = strstr(n, "/diskette");
if (s != NULL) {
s++; /* point at 'd' */
*s = NULLC;
*s = 'd';
}
return (strdup(""));
}
void
{
free(p);
}
}
}
/*
* given a regular expression, or a path, return a list of
* paths that match it.
*/
char **
match_path(char *p, int (*testpath)(char *))
{
static int fentrycmp(const void *a, const void *b);
char **rval;
/*
* Check to see if the path is something real.
* If so, just return it as the only one.
*/
/* the name has no RE in it: use it as is (if it passes) */
return (NULL);
}
rval[0] = vold_strdup(p);
return (rval); /* found a single match */
}
/* the filename must have a wildcard in it -- does anything match? */
/*
* separate the directory name from the path name
*/
dn = vold_strdup(p);
return (NULL); /* pathname syntax error */
}
/*
* put a null where the last slash was,
* bn will have the "tail" of the name (the basename), which should
* have the RE), and
* dn has the directory part of the name (the dirname)
*/
/* First look up the cache to see if we have the dir entry */
break;
}
/* no cache found */
return (NULL); /* no such directory? */
}
nents = 0;
continue;
}
nents++;
}
if (nents != 0) {
/*
* allocate an array of all pointers to give to qsort
*/
for (i = 0; i < nents; i++) {
}
/*
* sort the directory entries.
*/
/* re-construct the linked list */
for (i = 0; i < (nents-1); i++) {
}
}
}
/*
* directory is empty.
*/
return (NULL);
}
/*
* XXX this only deals with regular expressions in the
* XXX filename part of the path, and ignores any fancy stuff in
* XXX the rest of the path.
*/
/* compile the regular expression */
char *errmsg;
/* get the RE err msg, then print it and exit */
return (NULL); /* RE AFU */
}
/*
* First, mark the files if it does match the pattern.
*/
nents = 0;
if (ret == REG_NOMATCH)
continue;
debug(1,
"can't compare RE \"%s\" to \"%s\" (ret %s)\n",
continue;
}
nents++; /* count only match */
}
/*
* We found nents files which match the pattern. Although
* some of them may be known to be inappropriate, we allocate
* nents + 1(for NULL) array to simplify the code.
*/
nrval = 0;
/* just skip the device files which we don't want */
continue;
/* if the path is known to be inappropriate, just skip */
continue;
}
/* allocate buffer for full path */
/* if the device has not been evaluated, then do it. */
/* need to invoke ioctl against char device */
goto out;
}
goto out;
}
goto out;
}
/* see if the device has been managed */
debug(3,
"can't access device %s\n", rp);
goto out;
}
ret == 0) {
"removable device\n", rp);
goto out;
}
}
out:
}
/* see if it's the kind of device we hope it is */
} else {
}
}
return (rval);
}
/*
* used for qsort in find_paths
*/
static int
fentrycmp(const void *a, const void *b)
{
}
/*
* swiped from rmmount/rmm_util.c, which was in turn swiped from mkdir.c
* (at some time)
*
* NOTE: this routine modifies the "dir" string passed in (although
* not permanently)
*/
int
{
int err;
char *slash;
return (0); /* the mkdir succeeded */
}
return (0); /* the dir already exists */
}
return (-1); /* oh oh */
}
return (-1);
}
/* the mkdir failed with errno==ENOENT, so make it's parent(s) */
*slash++ = '/';
return (err);
}
}
void *
{
void *ptr;
extern int umount_all(char *);
(void) umount_all(vold_root);
fatal("Out of memory.");
}
return (ptr);
}
void *
{
void *rptr;
extern int umount_all(char *);
(void) umount_all(vold_root);
fatal("Out of memory.");
}
return (rptr);
}
void *
{
void *ptr;
return (ptr);
}
char *
vold_strdup(const char *s)
{
char *ptr;
return (ptr);
}