1
0
Files
irix-657m-src/eoe/cmd/sun/exportfs.c
2022-09-29 17:59:04 +03:00

1287 lines
25 KiB
C

#ifndef lint
static char sccsid[] = "@(#)exportfs.c 1.2 88/06/15 4.0NFSSRC Copyr 1988 Sun Micro";
#endif
/*
* Export directories (or files) to NFS clients Copyright (c) 1987 Sun
* Microsystems, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <exportent.h>
#include <netdb.h>
#include <strings.h>
#include <rpc/rpc.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/fs/export.h>
#include <sys/capability.h>
/*
* options to command
*/
#define AFLAG 0x01
#define UFLAG 0x02
#define VFLAG 0x04
#define IFLAG 0x08
#define BUFINCRSZ 128
#define MAXNAMELEN 256
#define NETGROUPINCR 32
#define streq(a,b) (strcmp(a, b) == 0)
char *getline(FILE *);
char *accessjoin(char *, int ngrps, char **);
char *strtoken(char **, char *);
char *check_malloc(unsigned int);
char *check_realloc(char *, unsigned int);
void out_of_memory(void);
void cannot_open(int, char *);
void printexports(void);
void printexport(struct exportent *, int);
void fillex(struct export *, struct options *);
void export_full(char *, int);
int map_user(char *, int *);
char anon_opt[] = ANON_OPT;
char ro_opt[] = RO_OPT;
char rw_opt[] = RW_OPT;
char root_opt[] = ROOT_OPT;
char access_opt[] = ACCESS_OPT;
char nohide_opt[] = NOHIDE_OPT;
char wsync_opt[] = WSYNC_OPT;
char b32clnt_opt[] = B32CLNT_OPT;
char noxattr_opt[] = NOXATTR_OPT;
char EXPORTFILE[] = "/etc/exports";
static const cap_value_t cap_mount_read[] = {CAP_MOUNT_MGT, CAP_MAC_READ};
struct options {
int anon;
int flags;
int auth;
char **hostlist;
int hostlistsize;
int nhosts;
char **accesslist;
int accesslistsize;
int naccess;
char **writelist;
int writelistsize;
int nwrites;
};
main(argc, argv)
int argc;
char *argv[];
{
int i;
char *options = NULL;
int Argc;
char **Argv;
int flags;
int retstatus = 0;
if (!parseargs(argc, argv, &flags, &options, &Argc, &Argv)) {
(void) fprintf(stderr,
"usage: %s [-aiuv] [-o options] [dir] ...\n", argv[0]);
exit(1);
}
if ((Argc || (flags & AFLAG)) && geteuid() != 0) {
fprintf(stderr, "must be superuser to %sexport\n",
(flags & UFLAG) ? "un" : "");
exit(1);
}
if (Argc == 0) {
if (flags & AFLAG) {
if (flags & UFLAG) {
retstatus = (unexportall(flags & VFLAG) < 0);
} else {
retstatus = (exportall(flags & VFLAG, NULL)
< 0);
}
} else {
printexports();
}
} else if (flags & UFLAG) {
if (options) {
(void) fprintf(stderr,
"exportfs: options ignored for unexport\n");
}
for (i = 0; i < Argc; i++) {
retstatus |= (unexport(Argv[i], flags & VFLAG) < 0);
}
} else {
for (i = 0; i < Argc; i++) {
if (flags & IFLAG) {
retstatus |= (export(Argv[i], options,
flags & VFLAG) < 0);
} else {
retstatus |= (exportall(flags & VFLAG, Argv[i])
< 0);
}
}
}
exit(retstatus);
/* NOTREACHED */
}
/*
* Print all exported pathnames
*/
void
printexports(void)
{
struct exportent *xent;
FILE *f;
int maxlen;
f = fopen(TABFILE, "r");
if (f == NULL) {
(void) printf("nothing exported\n");
return;
}
maxlen = 0;
while (xent = getexportent(f)) {
if (strlen(xent->xent_dirname) > maxlen) {
maxlen = strlen(xent->xent_dirname);
}
}
rewind(f);
while (xent = getexportent(f)) {
printexport(xent, maxlen + 1);
}
if (maxlen == 0) {
(void) printf("nothing exported\n");
}
endexportent(f);
}
/*
* Print just one exported pathname
*/
void
printexport(xent, col)
struct exportent *xent;
int col;
{
int i;
(void) printf("%s", xent->xent_dirname);
if (xent->xent_options) {
for (i = strlen(xent->xent_dirname); i < col; i++) {
(void) putchar(' ');
}
(void) printf("-%s", xent->xent_options);
}
(void) printf("\n");
}
/*
* Unexport everything in the export tab file
*/
unexportall(verbose)
int verbose;
{
struct exportent *xent;
FILE *f;
cap_t ocap;
register int retcode = 0;
f = setexportent();
if (f == NULL) {
cannot_open(0, TABFILE);
return -1;
}
while (xent = getexportent(f)) {
(void) remexportent(f, xent->xent_dirname);
ocap = cap_acquire (2, cap_mount_read);
if (exportfs(xent->xent_dirname, (struct export *) NULL) < 0) {
(void) fprintf(stderr, "exportfs: %s: %s\n",
xent->xent_dirname, strerror(errno));
retcode = -1;
} else {
if (verbose) {
(void) printf("unexported %s\n", xent->xent_dirname);
}
}
cap_surrender(ocap);
}
endexportent(f);
return retcode;
}
/*
* Unexport just one directory
*/
unexport(dirname, verbose)
char *dirname;
int verbose;
{
FILE *f;
cap_t ocap;
f = setexportent();
if (f == NULL) {
cannot_open(0, TABFILE);
return -1;
}
(void) remexportent(f, dirname);
ocap = cap_acquire (2, cap_mount_read);
if (exportfs(dirname, (struct export *) NULL) < 0) {
cap_surrender(ocap);
(void) fprintf(stderr, "exportfs: %s: %s\n",
dirname, strerror(errno));
endexportent(f);
return -1;
}
cap_surrender(ocap);
endexportent(f);
if (verbose) {
(void) printf("unexported %s\n", dirname);
}
return 0;
}
/*
* Export everything in /etc/exports
*/
exportall(verbose, which)
int verbose;
char *which;
{
char *name;
FILE *f;
char *lp;
char *dirname;
char *options;
char **grps;
int grpsize;
int ngrps;
register int i;
int exported, failed;
f = fopen(EXPORTFILE, "r");
if (f == NULL) {
cannot_open(errno, EXPORTFILE);
return -1;
}
grps = NULL;
grpsize = 0;
exported = failed = 0;
while (
(which == NULL || !exported)
&& ( (lp = getline(f)) != NULL )
) {
dirname = NULL;
options = NULL;
ngrps = 0;
while ((name = strtoken(&lp, " \t")) != NULL) {
if (dirname == NULL) {
dirname = name;
} else if (options == NULL && name[0] == '-') {
if ((options = strdup(name + 1)) == NULL)
out_of_memory();
} else {
grpsize = addtogrouplist(&grps, grpsize,
ngrps, name);
ngrps++;
}
}
if (ngrps > 0) {
options = accessjoin(options, ngrps, grps);
for (i = 0; i < ngrps; i++)
free(grps[i]);
}
if (dirname != NULL && (which == NULL ||
strcmp(dirname, which) == 0)) {
if (export(dirname, options, verbose) < 0)
failed = 1;
else
exported++;
}
if (options != NULL) {
free(options);
}
}
if (failed) {
return -1;
}
if (which != NULL && !exported) {
fprintf(stderr, "%s not found in %s\n", which, EXPORTFILE);
return -1;
}
return 0;
}
int
addtogrouplist(grplistp, grplistsize, index, group)
char ***grplistp;
int grplistsize;
int index;
char *group;
{
if (index == grplistsize) {
grplistsize += NETGROUPINCR;
if (*grplistp == NULL)
*grplistp =
(char **) check_malloc(((unsigned) grplistsize * sizeof(char *)));
else
*grplistp = (char **) check_realloc((char *) *grplistp,
(unsigned) (grplistsize * sizeof(char *)));
}
(*grplistp)[index] = group;
return grplistsize;
}
/*
* Export just one directory
*/
export(dirname, options, verbose)
char *dirname;
char *options;
int verbose;
{
struct export ex;
struct options opt;
FILE *f;
int redo = 0;
cap_t ocap;
if (!interpret(dirname, &opt, options)) {
return -1;
}
fillex(&ex, &opt);
f = setexportent();
if (f == NULL) {
cannot_open(0, TABFILE);
return -1;
}
if (insane(f, dirname)) {
endexportent(f);
return -1;
}
if (xtab_test(f, dirname)) {
(void) remexportent(f, dirname);
redo = 1;
}
ocap = cap_acquire (2, cap_mount_read);
if (exportfs(dirname, &ex) < 0) {
cap_surrender(ocap);
(void) fprintf(stderr, "exportfs: %s: %s\n",
dirname, strerror(errno));
endexportent(f);
return -1;
}
cap_surrender(ocap);
addexportent(f, dirname, options);
endexportent(f);
if (verbose) {
if (redo) {
(void) printf("re-exported %s\n", dirname);
} else {
(void) printf("exported %s\n", dirname);
}
}
return 0;
}
/*
* Interpret a line of options
*/
interpret(dirname, opt, line)
char *dirname;
struct options *opt;
char *line;
{
char *name;
/*
* Initialize and set up defaults
*/
opt->anon = -2;
opt->flags = 0;
opt->auth = AUTH_UNIX;
opt->hostlist = NULL;
opt->hostlistsize = 0;
opt->nhosts = 0;
opt->accesslist = NULL;
opt->accesslistsize = 0;
opt->naccess = 0;
opt->writelist = NULL;
opt->writelistsize = 0;
opt->nwrites = 0;
if (line == NULL) {
return 1;
}
for (;;) {
name = strtoken(&line, ",");
if (name == NULL) {
return 1;
}
if (!dooption(dirname, name, opt)) {
return 0;
}
}
}
/*
* Fill in the root addresses
*/
static void
filladdrs(struct exaddrlist *addrs, char **names, int nnames, char *errstr, int max)
{
struct hostent *h;
struct sockaddr *sa;
int i, n;
char *machine, *user, *domain;
addrs->naddrs = 0;
sa = &addrs->addrvec[0];
for (i = 0; i < nnames; i++) {
/* check for netgroup */
n = innetgr(names[i], (char *) 0, (char *) 0, (char *) 0);
if (n) {
setnetgrent(names[i]);
while (getnetgrent(&machine, &user, &domain)) {
if (machine) {
if ((h = gethostbyname(machine)) == NULL)
fprintf(stderr,"exportfs: unknown host %s in netgroup %s\n",
machine, names[i]);
else {
if (addrs->naddrs >= max) {
export_full(errstr, max);
endnetgrent();
return;
}
if (fillone(h, sa) == 0) {
addrs->naddrs++;
sa++;
}
}
} else {
sethostent(0);
while (h = gethostent()) {
if (addrs->naddrs >= max) {
export_full(errstr, max);
endnetgrent();
return;
}
if (fillone(h, sa) == 0) {
addrs->naddrs++;
sa++;
}
}
}
} /* while */
endnetgrent();
continue;
}
h = gethostbyname(names[i]);
if (h == NULL) {
fprintf(stderr, "exportfs: bad host '%s' in %s: %s\n",
names[i], errstr, hstrerror(h_errno));
continue;
}
if (addrs->naddrs >= max) {
export_full(errstr, max);
return;
}
if (fillone(h, sa) == 0 ) {
addrs->naddrs++;
sa++;
}
}
}
/* fill an export struct for the given host */
fillone(h, sa)
struct hostent *h;
struct sockaddr *sa;
{
bzero((char *) sa, sizeof *sa);
sa->sa_family = h->h_addrtype;
switch (h->h_addrtype) {
case AF_INET:
bcopy(h->h_addr,
(char *) &((struct sockaddr_in *)sa)->sin_addr,
h->h_length);
break;
default:
(void) fprintf(stderr,
"exportfs: %d: unknown address type for %s\n",
h->h_addrtype, h->h_name);
return(-1);
}
return(0);
}
/*
* Fill an export structure given the options selected
*/
void
fillex(ex, ops)
struct export *ex;
struct options *ops;
{
ex->ex_flags = ops->flags;
if (ex->ex_flags & EX_RDMOSTLY) {
ex->ex_writeaddrs.addrvec = (struct sockaddr *)
check_malloc(EXMAXADDRS * sizeof(struct sockaddr));
filladdrs(&ex->ex_writeaddrs, ops->writelist, ops->nwrites,
"rw option", EXMAXADDRS);
}
ex->ex_anon = ops->anon;
ex->ex_auth = ops->auth;
switch (ops->auth) {
case AUTH_UNIX:
ex->ex_unix.rootaddrs.naddrs = ops->nhosts;
ex->ex_unix.rootaddrs.addrvec = (struct sockaddr *)
check_malloc(EXMAXROOTADDRS * sizeof(struct sockaddr));
filladdrs(&ex->ex_unix.rootaddrs, ops->hostlist, ops->nhosts,
"root option", EXMAXROOTADDRS);
ex->ex_accessaddrs.addrvec = (struct sockaddr *)
check_malloc(EXMAXADDRS * sizeof(struct sockaddr));
filladdrs(&ex->ex_accessaddrs, ops->accesslist, ops->naccess,
"access option", EXMAXADDRS);
break;
}
}
dooption(dirname, opstr, ops)
char *dirname;
char *opstr;
struct options *ops;
{
# define pstreq(a, b, blen) \
((strncmp(a, b, blen) == 0) && (a[blen] == '='))
if (streq(opstr, ro_opt)) {
ops->flags |= EX_RDONLY;
} else if (pstreq(opstr, rw_opt, sizeof(rw_opt) - 1)) {
ops->flags |= EX_RDMOSTLY;
if (!getacclist(&opstr[sizeof(rw_opt)],
&ops->nwrites, &ops->writelist,
&ops->writelistsize)) {
out_of_memory();
}
} else if (pstreq(opstr, anon_opt, sizeof(anon_opt) - 1)) {
if (!map_user(&opstr[sizeof(anon_opt)], &ops->anon))
return 0;
} else if (streq(opstr, nohide_opt)) {
ops->flags |= EX_NOHIDE;
} else if (streq(opstr, wsync_opt)) {
ops->flags |= EX_WSYNC;
} else if (streq(opstr, rw_opt)) { /* read-write export */
/* nothing to do */
} else if (pstreq(opstr, root_opt, sizeof(root_opt) - 1)) {
if (!getacclist(&opstr[sizeof(root_opt)],
&ops->nhosts, &ops->hostlist,
&ops->hostlistsize)) {
out_of_memory();
}
} else if (pstreq(opstr, access_opt, sizeof(access_opt) - 1)) {
ops->flags |= EX_ACCESS;
if (!getacclist(&opstr[sizeof(access_opt)],
&ops->naccess, &ops->accesslist, &ops->accesslistsize)) {
out_of_memory();
}
} else if (streq(opstr, b32clnt_opt)) {
ops->flags |= EX_B32CLNT;
} else if (streq(opstr, noxattr_opt)) {
ops->flags |= EX_NOXATTR;
} else {
(void) fprintf(stderr, "exportfs: unknown option: %s\n", opstr);
return 0;
}
return 1;
}
void
export_full(msg, max)
char *msg;
int max;
{
(void) fprintf(stderr,
"exportfs: export address list for %s is full (max %d).\n",
msg, max);
}
int
getstaticnamelist(list, nnames, namelist, max)
char *list;
int *nnames;
char *namelist[];
int max;
{
char *name;
for (;;) {
name = strtoken(&list, ":");
if (name == NULL) {
return 1;
}
if (*nnames == max) {
return 0;
}
namelist[*nnames] = name;
(*nnames)++;
}
}
int
getacclist(list, nnames, namelist, namelistsize)
char *list;
int *nnames;
char ***namelist;
int *namelistsize;
{
char *name;
for (;;) {
name = strtoken(&list, ":");
if (name == NULL) {
return 1;
}
if (!innetgr(name, (char *) 0, (char *) 0, (char *) 0) &&
(gethostbyname(name) == 0)) {
fprintf(stderr,
"exportfs: unknown host or netgroup in access list: %s\n",
name);
} else {
if ((*namelistsize = addtogrouplist(namelist,
*namelistsize, *nnames, name)) == 0)
return 0;
(*nnames)++;
}
}
}
char *
accessjoin(options, ngrps, grps)
char *options;
int ngrps;
char **grps;
{
register char *str;
register int i;
register unsigned int len;
register char *p;
if (options != NULL) {
len = strlen(options); /* <options> */
if (len != 0)
len++; /* , */
} else
len = 0;
len += (sizeof(access_opt) - 1) + 1; /* <access_opt>= */
for (i = 0; i < ngrps; i++) {
len += strlen(grps[i]) + 1; /* group: or group\0 */
}
str = check_malloc(len);
if (options == NULL || *options == '\0') {
(void) sprintf(str, "%s=%s", access_opt, grps[0]);
} else {
(void) sprintf(str, "%s,%s=%s", options, access_opt, grps[0]);
}
p = str;
for (i = 1; i < ngrps; i++) {
p += strlen(p);
(void) sprintf(p, ":%s", grps[i]);
}
if (options != NULL)
free(options);
return str;
}
parseargs(argc, argv, flags, options, nargc, nargv)
int argc;
char *argv[];
int *flags;
char **options;
int *nargc;
char ***nargv;
{
int i;
int j;
*flags = 0;
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
if (argv[i][1] == 0) {
return 0;
}
for (j = 1; argv[i][j] != 0; j++) {
switch (argv[i][j]) {
case 'a':
*flags |= AFLAG;
break;
case 'u':
*flags |= UFLAG;
break;
case 'v':
*flags |= VFLAG;
break;
case 'i':
*flags |= IFLAG;
break;
case 'o':
if (j != 1 || argv[i][2] != 0) {
return 0;
}
if (i + 1 >= argc) {
return 0;
}
*options = argv[++i];
goto breakout;
default:
return 0;
}
}
breakout:
;
}
*nargc = argc - i;
*nargv = argv + i;
return 1;
}
xtab_test(f, dirname)
FILE *f;
char *dirname;
{
struct exportent *xent;
rewind(f);
while (xent = getexportent(f)) {
if (streq(xent->xent_dirname, dirname)) {
return 1;
}
}
return 0;
}
direq(dir1, dir2)
char *dir1;
char *dir2;
{
struct stat64 st1;
struct stat64 st2;
if (stat64(dir1, &st1) < 0) {
return 0;
}
if (stat64(dir2, &st2) < 0) {
return 0;
}
return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
}
insane(f, dir)
FILE *f;
char *dir;
{
struct exportent *xent;
rewind(f);
while (xent = getexportent(f)) {
if (direq(xent->xent_dirname, dir)) {
continue;
}
if (issubdir(xent->xent_dirname, dir)) {
(void) fprintf(stderr,
"exportfs: %s: sub-directory (%s) already exported\n",
dir, xent->xent_dirname);
return 1;
}
if (issubdir(dir, xent->xent_dirname)) {
(void) fprintf(stderr,
"exportfs: %s: parent-directory (%s) already exported\n",
dir, xent->xent_dirname);
return 1;
}
}
return 0;
}
#define buf_append(c, bp, buf, bufsz) \
( \
( bp == (bufsz) ) ? ( \
(buf) = check_realloc((buf), (bufsz)+BUFINCRSZ), \
(bufsz) += BUFINCRSZ, \
(buf)[bp++] = (c) \
) : ( \
(buf)[bp++] = (c) \
) \
)
/*
* getline() Read a line from a file, digesting backslash-newline.
* Returns a pointer to the read string, or NULL on EOF.
* Backslash-newline counts as whitespace except when:
* we are processing the options section
* and the preceeding char is ':', '=', or ','
*/
char *
getline(f)
FILE *f;
{
static char *buf = NULL;
static size_t bufsz = 0;
size_t bp = 0;
int cc;
enum getline_states {
init_state, /* start here, eat blank lines, comments, etc */
bsi_state, /* backslash newline that counts as init */
comment_state, /* comment #..*$ */
dir_state, /* name of exported directory */
bs1_state, /* backslash newline that counts as ws1 */
ws1_state, /* whitespace between dir and options */
opt_state, /* options section */
bs2_state, /* backslash newline conditionally eaten */
ws2_state, /* whitespace after options section */
grp_state, /* hosts and netgroups */
bs3_state, /* backslash newline that counts as ws2 */
done_state /* we're done */
} state, return_state;
/* initialize buffer if needed */
if ( buf == NULL ) {
buf = check_malloc(BUFINCRSZ);
bufsz = BUFINCRSZ;
}
state = init_state;
return_state = done_state;
do {
cc = getc(f);
if ( cc == EOF ) {
/*
* if there is any data in the buffer, return it
*/
if ( bp > 0 ) {
state = done_state;
} else {
return NULL;
}
}
/* another simplification */
if ( cc == '\t' ) {
cc = ' ';
}
switch ( state ) {
case init_state:
switch ( cc ) {
/*
* We haven't gotten any data yet. Chew up blank
* lines, continued lines, and comments until we
* hit something of interest.
*/
case ' ':
break;
case '\\':
state = bsi_state;
break;
case '#':
return_state = init_state;
state = comment_state;
break;
case '\n':
break;
default:
buf_append(cc, bp, buf, bufsz);
state = dir_state;
break;
}
break;
case bsi_state:
/*
* We've hit a backslash. If it turns out to be a
* backslash-newline, continue on processing in
* the init state. Otherwise, we have the first
* char of our exported directory.
*
* Can the first char of the directory ever be
* anything but '/'?
*
* Right now, the directory name does not have to
* start in column 0.
*
* Allow backslash to quote '\\' and '#'.
*/
switch ( cc ) {
case ' ':
state = init_state;
break;
case '\n':
state = init_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
state = dir_state;
break;
}
break;
case comment_state:
/*
* We've hit a comment. After consuming it we
* either will be done or we will continue init
* processing depending on the value of
* return_state.
*/
switch ( cc ) {
case '\n':
state = return_state;
break;
default:
break;
}
break;
case dir_state:
/*
* We are now processing the exported directory
* portion of the line.
* Line continuation terminates this section.
* We are guaranteed to have at least one char
* of the directory name already.
*
* Question, shouldn't directory names ALWAYS
* begin with a '/'? Can I enforce this?
*/
switch ( cc ) {
case ' ':
buf_append(cc, bp, buf, bufsz);
state = ws1_state;
break;
case '\\':
state = bs1_state;
break;
case '#':
return_state = done_state;
state = comment_state;
break;
case '\n':
state = done_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
break;
}
break;
case bs1_state:
/*
* We ran into a backslash while processing the
* exported directory name. If it is a line
* continuation, move on to the options
* processing. If it is just escaping a char, go
* back to dir_state.
*/
switch ( cc ) {
case ' ':
buf_append(' ', bp, buf, bufsz);
state = ws1_state;
break;
case '\n':
buf_append(' ', bp, buf, bufsz);
state = ws1_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
state = dir_state;
break;
}
break;
case ws1_state:
/*
* White space between the directory and the
* options or host/grouplist.
* We are guaranteed that there is already a
* space in the buffer after the directory.
*/
switch ( cc ) {
case ' ':
break;
case '\\':
state = bs2_state;
break;
case '#':
return_state = done_state;
state = comment_state;
break;
case '\n':
state = done_state;
break;
case '-':
buf_append(cc, bp, buf, bufsz);
state = opt_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
state = grp_state;
break;
}
break;
case opt_state:
/*
* We're now processing the options part of the
* line.
*/
switch ( cc ) {
case ' ':
buf_append(cc, bp, buf, bufsz);
state = ws2_state;
break;
case '\\':
state = bs2_state;
break;
case '#':
return_state = done_state;
state = comment_state;
break;
case '\n':
state = done_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
break;
}
break;
case bs2_state:
/*
* We ran into a backslash while processing the
* options. This is the only place where a
* line continuation cannot always be counted as
* a whitespace since it mucks up option
* processing.
*
* There is a slight bug here as
* "/dir \foo..."
* will process foo as an option and use the wrong
* line continuation rules.
*/
switch ( cc ) {
case ' ':
buf_append(' ', bp, buf, bufsz);
state = ws2_state;
break;
case '\n':
switch ( buf[bp-1] ) {
case '-':
case '=':
case ':':
case ',':
state = opt_state;
break;
case ' ':
state = ws2_state;
break;
default:
buf_append(' ', bp, buf, bufsz);
state = ws2_state;
break;
}
break;
default:
buf_append(cc, bp, buf, bufsz);
state = opt_state;
break;
}
break;
case ws2_state:
/*
* This is the whitespace before a hostname or
* netgroup. There is already a space in the
* buffer.
*/
switch ( cc ) {
case ' ':
break;
case '\\':
state = bs3_state;
break;
case '#':
return_state = done_state;
state = comment_state;
break;
case '\n':
state = done_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
state = grp_state;
break;
}
break;
case grp_state:
switch ( cc ) {
case ' ':
buf_append(cc, bp, buf, bufsz);
state = ws2_state;
break;
case '\\':
state = bs3_state;
break;
case '#':
return_state = done_state;
state = comment_state;
break;
case '\n':
state = done_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
break;
}
break;
case bs3_state:
/*
* We ran into a backslash while processing the
* hosts/grouplists.
*/
switch ( cc ) {
case ' ':
buf_append(' ', bp, buf, bufsz);
state = ws2_state;
break;
case '\n':
buf_append(' ', bp, buf, bufsz);
state = ws2_state;
break;
default:
buf_append(cc, bp, buf, bufsz);
state = grp_state;
break;
}
break;
case done_state:
/* do nothing */
break;
default:
/* should never be here - punt */
state = done_state;
break;
}
} while ( state != done_state );
buf_append('\0', bp, buf, bufsz);
return buf;
} /* getline() */
/*
* Like strtok(), but no static data
*/
char *
strtoken(string, sepset)
char **string;
char *sepset;
{
char *p;
char *q;
char *r;
char *res;
p = *string;
if (p == 0) {
return NULL;
}
q = p + strspn(p, sepset);
if (*q == 0) {
return NULL;
}
r = strpbrk(q, sepset);
if (r == NULL) {
*string = 0;
if ((res = strdup(q)) == NULL)
out_of_memory();
} else {
res = check_malloc((unsigned) (r - q + 1));
(void) strncpy(res, q, r - q);
res[r - q] = 0;
*string = ++r;
}
return res;
}
char *
check_malloc(size)
unsigned int size;
{
register char *memoryp;
if ((memoryp = malloc(size)) == NULL)
out_of_memory();
return memoryp;
}
char *
check_realloc(memoryp, size)
char *memoryp;
unsigned int size;
{
if ((memoryp = realloc(memoryp, size)) == NULL)
out_of_memory();
return memoryp;
}
void
out_of_memory(void)
{
(void) fprintf(stderr, "exportfs: Out of memory\n");
exit(1);
}
void
cannot_open(error, filename)
int error;
char *filename;
{
fprintf(stderr, "exportfs: cannot open %s", filename);
if (error)
fprintf(stderr, ": %s", strerror(error));
fputc('\n', stderr);
}
#include <ctype.h>
#include <pwd.h>
int
map_user(name, uidp)
char *name;
int *uidp;
{
struct passwd *pw;
if (isdigit(*name) || (name[0] == '-' && isdigit(name[1]))) {
*uidp = atoi(name);
return 1;
}
pw = getpwnam(name);
if (pw) {
*uidp = pw->pw_uid;
return 1;
}
fprintf(stderr, "exportfs: unknown user: %s\n", name);
return 0;
}