885 lines
16 KiB
C
885 lines
16 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)exportfs.c 1.1 94/10/31 SMI";
|
|
#endif
|
|
|
|
/*
|
|
* Export directories (or files) to NFS clients Copyright (c) 1987 Sun
|
|
* Microsystems, Inc.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <netdb.h>
|
|
#include <strings.h>
|
|
#include <rpc/rpc.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/file.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/stat.h>
|
|
#include <nfs/export.h>
|
|
#include <exportent.h>
|
|
#include <pwd.h>
|
|
|
|
extern char *malloc();
|
|
extern char *realloc();
|
|
extern char *strpbrk();
|
|
extern char *strdup();
|
|
extern char *sprintf();
|
|
extern int errno;
|
|
|
|
/*
|
|
* options to command
|
|
*/
|
|
#define AFLAG 0x01
|
|
#define UFLAG 0x02
|
|
#define VFLAG 0x04
|
|
#define IFLAG 0x08
|
|
|
|
#define MAXROOTS EXMAXADDRS
|
|
#define MAXWRITE EXMAXADDRS
|
|
#define MAXLINELEN 4096
|
|
#define MAXNAMELEN 256
|
|
#define NETGROUPINCR 32
|
|
|
|
#define streq(a,b) (strcmp(a, b) == 0)
|
|
|
|
char *getline();
|
|
char *accessjoin();
|
|
char *strtoken();
|
|
char *check_malloc();
|
|
char *check_realloc();
|
|
void out_of_memory();
|
|
|
|
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 secure_opt[] = SECURE_OPT;
|
|
char window_opt[] = WINDOW_OPT;
|
|
|
|
char EXPORTFILE[] = "/etc/exports";
|
|
|
|
struct options {
|
|
int anon;
|
|
int window;
|
|
int flags;
|
|
int auth;
|
|
char *hostlist[MAXROOTS];
|
|
int nhosts;
|
|
char **accesslist;
|
|
int accesslistsize;
|
|
int naccess;
|
|
char *writelist[MAXWRITE];
|
|
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 [-auv] [-o options] [dir] ...\n", argv[0]);
|
|
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
|
|
*/
|
|
printexports()
|
|
{
|
|
struct exportent *xent;
|
|
FILE *f;
|
|
int maxlen;
|
|
|
|
f = setexportent();
|
|
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
|
|
*/
|
|
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;
|
|
register int retcode = 0;
|
|
|
|
f = setexportent();
|
|
if (f == NULL) {
|
|
return (-1);
|
|
}
|
|
while (xent = getexportent(f)) {
|
|
(void) remexportent(f, xent->xent_dirname);
|
|
if (exportfs(xent->xent_dirname, (struct export *) NULL) < 0) {
|
|
(void) fprintf(stderr, "exportfs: ");
|
|
if (errno == EPERM) {
|
|
(void) fprintf(stderr,
|
|
"must be superuser to unexport\n");
|
|
endexportent(f);
|
|
return (-1);
|
|
}
|
|
perror(xent->xent_dirname);
|
|
retcode = -1;
|
|
} else {
|
|
if (verbose) {
|
|
(void) printf("unexported %s\n", xent->xent_dirname);
|
|
}
|
|
}
|
|
}
|
|
endexportent(f);
|
|
return (retcode);
|
|
}
|
|
|
|
/*
|
|
* Unexport just one directory
|
|
*/
|
|
unexport(dirname, verbose)
|
|
char *dirname;
|
|
int verbose;
|
|
{
|
|
FILE *f;
|
|
|
|
f = setexportent();
|
|
if (f == NULL) {
|
|
return (-1);
|
|
}
|
|
(void) remexportent(f, dirname);
|
|
if (exportfs(dirname, (struct export *) NULL) < 0) {
|
|
(void) fprintf(stderr, "exportfs: ");
|
|
if (errno == EPERM) {
|
|
(void) fprintf(stderr, "must be superuser to unexport\n");
|
|
} else {
|
|
perror(dirname);
|
|
}
|
|
endexportent(f);
|
|
return (-1);
|
|
}
|
|
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 line[MAXLINELEN];
|
|
char *name;
|
|
FILE *f;
|
|
char *lp;
|
|
char *dirname;
|
|
char *options;
|
|
char **grps;
|
|
int grpsize;
|
|
int ngrps;
|
|
register int i;
|
|
int exported;
|
|
|
|
f = fopen(EXPORTFILE, "r");
|
|
if (f == NULL) {
|
|
(void) fprintf(stderr, "exportfs: Can't open ");
|
|
perror(EXPORTFILE);
|
|
return (-1);
|
|
}
|
|
grps = NULL;
|
|
grpsize = 0;
|
|
exported = 0;
|
|
while ((which == NULL || !exported) &&
|
|
getline(line, sizeof(line), f)) {
|
|
lp = line;
|
|
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) {
|
|
return (-1);
|
|
}
|
|
exported++;
|
|
}
|
|
if (options != NULL) {
|
|
free(options);
|
|
}
|
|
}
|
|
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;
|
|
|
|
if (!interpret(dirname, &opt, options)) {
|
|
return (0);
|
|
}
|
|
fillex(&ex, &opt);
|
|
f = setexportent();
|
|
if (f == NULL) {
|
|
return (-1);
|
|
}
|
|
if (insane(f, dirname)) {
|
|
endexportent(f);
|
|
return (0);
|
|
}
|
|
if (xtab_test(f, dirname)) {
|
|
(void) remexportent(f, dirname);
|
|
redo = 1;
|
|
}
|
|
if (exportfs(dirname, &ex) < 0) {
|
|
(void) fprintf(stderr, "exportfs: ");
|
|
if (errno == EPERM) {
|
|
(void) fprintf(stderr, "must be superuser to export\n");
|
|
} else {
|
|
perror(dirname);
|
|
}
|
|
endexportent(f);
|
|
if (errno == EPERM) {
|
|
return (-1);
|
|
} else {
|
|
return (0);
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
|
|
#define NOBODY_UID_DEFAULT (u_short) 65534
|
|
#define NOBODY_LOGIN "nobody"
|
|
|
|
/*
|
|
* Interpret a line of options
|
|
*/
|
|
interpret(dirname, opt, line)
|
|
char *dirname;
|
|
struct options *opt;
|
|
char *line;
|
|
{
|
|
char *name;
|
|
struct passwd *pw, *getpwnam();
|
|
|
|
/*
|
|
* Initialize and set up defaults
|
|
*/
|
|
if ((pw = getpwnam(NOBODY_LOGIN)) == NULL)
|
|
opt->anon = (int) NOBODY_UID_DEFAULT;
|
|
else
|
|
opt->anon = (int) pw->pw_uid;
|
|
opt->window = 30000;
|
|
opt->flags = 0;
|
|
opt->auth = AUTH_UNIX;
|
|
opt->nhosts = 0;
|
|
opt->accesslist = NULL;
|
|
opt->accesslistsize = 0;
|
|
opt->naccess = 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 an export structure given the options selected
|
|
*/
|
|
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(EXMAXROOTADDRS * sizeof(struct sockaddr));
|
|
filladdrs(&ex->ex_writeaddrs, ops->writelist, ops->nwrites);
|
|
}
|
|
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);
|
|
break;
|
|
case AUTH_DES:
|
|
ex->ex_des.window = ops->window;
|
|
ex->ex_des.nnames = ops->nhosts;
|
|
ex->ex_des.rootnames = (char **)
|
|
check_malloc(EXMAXROOTNAMES * sizeof(char *));
|
|
fillnames(&ex->ex_des, ops);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Fill in the root addresses
|
|
*/
|
|
filladdrs(addrs, names, nnames)
|
|
struct exaddrlist *addrs;
|
|
char **names;
|
|
int nnames;
|
|
{
|
|
struct hostent *h;
|
|
struct sockaddr_in *sin;
|
|
int i;
|
|
|
|
addrs->naddrs = 0;
|
|
for (i = 0; i < nnames; i++) {
|
|
h = gethostbyname(names[i]);
|
|
if (h != NULL) {
|
|
bzero((char *) &addrs->addrvec[i],
|
|
sizeof(struct sockaddr));
|
|
addrs->addrvec[i].sa_family = h->h_addrtype;
|
|
switch (h->h_addrtype) {
|
|
case AF_INET:
|
|
sin = (struct sockaddr_in *)
|
|
(addrs->addrvec + i);
|
|
bcopy(h->h_addr, (char *) &sin->sin_addr,
|
|
h->h_length);
|
|
addrs->naddrs++;
|
|
break;
|
|
default:
|
|
(void) fprintf(stderr,
|
|
"exportfs: unknown address type: %d\n",
|
|
h->h_addrtype);
|
|
break;
|
|
}
|
|
} else {
|
|
(void) fprintf(stderr,
|
|
"exportfs: %s: unknown host\n", names[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
fillnames(dx, ops)
|
|
struct desexport *dx;
|
|
struct options *ops;
|
|
{
|
|
int i;
|
|
char netname[MAXNETNAMELEN + 1];
|
|
|
|
dx->nnames = 0;
|
|
for (i = 0; i < ops->nhosts; i++) {
|
|
if (!host2netname(netname, ops->hostlist[i], NULL)) {
|
|
(void) fprintf(stderr,
|
|
"exportfs: unknown host: %s\n",
|
|
ops->hostlist[i]);
|
|
} else {
|
|
if ((dx->rootnames[i] = strdup(netname)) == NULL)
|
|
out_of_memory();
|
|
dx->nnames++;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (!getstaticnamelist(&opstr[sizeof(rw_opt)],
|
|
&ops->nwrites, ops->writelist, MAXWRITE)){
|
|
toomany("write", dirname, MAXWRITE);
|
|
return (0);
|
|
}
|
|
} else if (streq(opstr, secure_opt)) {
|
|
ops->auth = AUTH_DES;
|
|
} else if (pstreq(opstr, anon_opt, sizeof(anon_opt) - 1)) {
|
|
ops->anon = atoi(&opstr[sizeof(anon_opt)]);
|
|
} else if (pstreq(opstr, window_opt, sizeof(window_opt) - 1)) {
|
|
ops->window = atoi(&opstr[sizeof(window_opt)]);
|
|
} else if (pstreq(opstr, root_opt, sizeof(root_opt) - 1)) {
|
|
if (!getstaticnamelist(&opstr[sizeof(root_opt)],
|
|
&ops->nhosts, ops->hostlist, MAXROOTS)) {
|
|
toomany("root", dirname, MAXROOTS);
|
|
return (0);
|
|
}
|
|
} else if (pstreq(opstr, access_opt, sizeof(access_opt) - 1)) {
|
|
if (!getdynamicnamelist(&opstr[sizeof(access_opt)],
|
|
&ops->naccess, &ops->accesslist, &ops->accesslistsize)) {
|
|
out_of_memory();
|
|
}
|
|
} else {
|
|
(void) fprintf(stderr, "exportfs: unknown option: %s\n", opstr);
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
toomany(kind, dirname, max)
|
|
char *kind;
|
|
char *dirname;
|
|
int max;
|
|
{
|
|
(void) fprintf(stderr,
|
|
"exportfs: %s allows %s access to too many hosts (max %d)\n",
|
|
kind, dirname, 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
|
|
getdynamicnamelist(list, nnames, namelist, namelistsize)
|
|
char *list;
|
|
int *nnames;
|
|
char ***namelist;
|
|
int *namelistsize;
|
|
{
|
|
char *name;
|
|
|
|
for (;;) {
|
|
name = strtoken(&list, ":");
|
|
if (name == NULL) {
|
|
return (1);
|
|
}
|
|
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 stat st1;
|
|
struct stat st2;
|
|
|
|
if (stat(dir1, &st1) < 0) {
|
|
return (0);
|
|
}
|
|
if (stat(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 iseol(c) (c == '\0' || c == '\n' || c == '#')
|
|
#define issep(c) (strchr(sep, c) != NULL)
|
|
#define isignore(c) (strchr(ignore, c) != NULL)
|
|
|
|
/*
|
|
* getline() Read a line from a file, converting backslash-newline to space.
|
|
* Returns it argument, or NULL on end-of-file.
|
|
*/
|
|
char *
|
|
getline(line, maxlinelen, f)
|
|
char *line;
|
|
int maxlinelen;
|
|
FILE *f;
|
|
{
|
|
char *p;
|
|
|
|
do {
|
|
if (!fgets(line, maxlinelen, f)) {
|
|
return (NULL);
|
|
}
|
|
} while (iseol(line[0]));
|
|
p = line;
|
|
maxlinelen -= strlen(p);
|
|
/*
|
|
* maxlinelen is always > 0 since fgets only reads maxlinelen-1
|
|
* characters (incl newline). The check for maxlinelen could be
|
|
* gotten rid of. The maximum line length restriction is still valid.
|
|
*/
|
|
for (; maxlinelen ;) {
|
|
while (!iseol(*p)) {
|
|
p++;
|
|
}
|
|
if (*p == '\n' && *(p - 1) == '\\') {
|
|
p--;
|
|
maxlinelen += 2;
|
|
if (fgets(p, maxlinelen, f) == NULL) {
|
|
*p = 0;
|
|
break;
|
|
}
|
|
else
|
|
maxlinelen -= strlen(p);
|
|
} else {
|
|
*p = 0;
|
|
break;
|
|
}
|
|
}
|
|
return (line);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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) fprintf(stderr, "exportfs: Out of memory\n");
|
|
exit(1);
|
|
}
|