#pragma ident "@(#)autod_autofs.c 1.27 05/06/08 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/param.h>
#include <mntopts.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "automount.h"
static int process_opts(char *options, uint32_t *directp);
static const struct mntopt mopts_autofs[] = {
MOPT_STDOPTS,
{ MNTOPT_RESTRICT, 0, AUTOFS_MNT_RESTRICT, 1 },
{ "browse", 1, AUTOFS_MNT_NOBROWSE, 1 },
{ MNTOPT_HIDEFROMFINDER, 0, AUTOFS_MNT_HIDEFROMFINDER, 1 },
{ NULL, 0, 0, 0 }
};
int
mount_autofs(
const char *mapname,
struct mapent *me,
const char *mntpnt,
fsid_t mntpnt_fsid,
action_list **alpp,
const char *rootp,
const char *subdir,
const char *key,
fsid_t *fsidp,
uint32_t *retflags
)
{
action_list *alp;
char rel_mntpnt[MAXPATHLEN];
const char *trig_mntpnt;
mntoptparse_t mp;
int error;
if (trace > 1)
trace_prt(1, " mount_autofs %s on %s\n",
me->map_fs->mfs_dir, mntpnt);
if (strcmp(mntpnt, "/-") == 0) {
syslog(LOG_ERR, "invalid mountpoint: /-");
*alpp = NULL;
return (ENOENT);
}
if (snprintf(rel_mntpnt, sizeof (rel_mntpnt), ".%s",
mntpnt+strlen(rootp)) >= (int)sizeof (rel_mntpnt)) {
syslog(LOG_ERR, "mountpoint too long: %s", mntpnt);
*alpp = NULL;
return (ENOENT);
}
if (trace > 2)
trace_prt(1, "rel_mntpnt = %s\n", rel_mntpnt);
trig_mntpnt = me->map_mntpnt;
while (*trig_mntpnt == '/')
trig_mntpnt++;
alp = (action_list *)malloc(sizeof (action_list));
if (alp == NULL) {
syslog(LOG_ERR, "malloc of alp failed");
*alpp = NULL;
return (ENOMEM);
}
memset(alp, 0, sizeof (action_list));
if ((alp->mounta.opts = malloc(AUTOFS_MAXOPTSLEN)) == NULL)
goto free_mem;
if (strlcpy(alp->mounta.opts, me->map_mntopts, AUTOFS_MAXOPTSLEN)
>= AUTOFS_MAXOPTSLEN) {
syslog(LOG_ERR, "options \"%s\" for %s are too long",
me->map_mntopts, mntpnt);
free(alp->mounta.opts);
free(alp);
*alpp = NULL;
return (ENOENT);
}
if (process_opts(alp->mounta.opts, &alp->mounta.isdirect) != 0)
goto free_mem;
if ((alp->mounta.path = strdup(mntpnt)) == NULL)
goto free_mem;
if ((alp->mounta.map = strdup(me->map_fs->mfs_dir)) == NULL)
goto free_mem;
if ((alp->mounta.subdir = strdup(subdir)) == NULL)
goto free_mem;
if (alp->mounta.isdirect) {
if (me->map_modified == TRUE || me->map_faked == TRUE) {
if ((alp->mounta.key = strdup(key)) == NULL)
goto free_mem;
} else {
if ((alp->mounta.key = strdup(alp->mounta.path)) == NULL)
goto free_mem;
}
} else {
alp->mounta.key = NULL;
}
if ((alp->mounta.dir = strdup(rel_mntpnt)) == NULL)
goto free_mem;
if ((alp->mounta.trig_mntpnt = strdup(trig_mntpnt)) == NULL)
goto free_mem;
alp->mounta.flags = alp->mounta.mntflags = 0;
getmnt_silent = 1;
mp = getmntopts(alp->mounta.opts, mopts_autofs, &alp->mounta.flags,
&alp->mounta.mntflags);
if (mp == NULL)
goto free_mem;
freemntopts(mp);
if (!me->map_modified && !me->map_faked) {
if (me->map_mntlevel == 0) {
struct autofs_args mnt_args;
mnt_args.version = AUTOFS_ARGSVERSION;
mnt_args.path = alp->mounta.path;
mnt_args.opts = alp->mounta.opts;
mnt_args.map = alp->mounta.map;
mnt_args.subdir = "";
mnt_args.key = alp->mounta.key == NULL ? "" : alp->mounta.key;
mnt_args.mntflags = alp->mounta.mntflags;
mnt_args.direct = alp->mounta.isdirect;
mnt_args.mount_type = MOUNT_TYPE_TRIGGERED_MAP;
if (alp->mounta.isdirect)
mnt_args.node_type = NT_TRIGGER;
else
mnt_args.node_type = 0;
if (mount(MNTTYPE_AUTOFS, mntpnt,
alp->mounta.flags|MNT_AUTOMOUNTED|MNT_DONTBROWSE,
&mnt_args) == -1)
error = errno;
else {
error = get_triggered_mount_info(mntpnt,
mntpnt_fsid, fsidp, retflags);
}
free_action_list_fields(alp);
free(alp);
*alpp = NULL;
return (error);
} else {
if (!alp->mounta.isdirect) {
free(alp->mounta.map);
if ((alp->mounta.map = strdup(mapname)) == NULL)
goto free_mem;
if ((alp->mounta.key = strdup(key)) == NULL)
goto free_mem;
}
}
}
if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0 ||
strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0)
alp->mounta.needs_subtrigger = 0;
else
alp->mounta.needs_subtrigger = 1;
*alpp = alp;
return (0);
free_mem:
syslog(LOG_ERR, "mount_autofs: memory allocation failure");
free_action_list_fields(alp);
free(alp);
*alpp = NULL;
return (ENOMEM);
}
static int
process_opts(char *options, uint32_t *directp)
{
char *opt, *opts, *lasts;
char buf[AUTOFS_MAXOPTSLEN];
CHECK_STRCPY(buf, options, sizeof buf);
opts = buf;
options[0] = '\0';
*directp = 0;
while ((opt = strtok_r(opts, ",", &lasts)) != NULL) {
opts = NULL;
while (isspace(*opt)) {
opt++;
}
if (strcmp(opt, "direct") == 0) {
*directp = 1;
} else if (strcmp(opt, "indirect") == 0) {
*directp = 0;
} else if (strcmp(opt, "ignore") != 0) {
if (options[0] != '\0') {
CHECK_STRCAT(options, ",", AUTOFS_MAXOPTSLEN);
}
CHECK_STRCAT(options, opt, AUTOFS_MAXOPTSLEN);
}
};
return (0);
}
void
free_action_list_fields(action_list *alp)
{
if (alp == NULL)
return;
if (alp->mounta.dir)
free(alp->mounta.dir);
if (alp->mounta.opts)
free(alp->mounta.opts);
if (alp->mounta.path)
free(alp->mounta.path);
if (alp->mounta.map)
free(alp->mounta.map);
if (alp->mounta.subdir)
free(alp->mounta.subdir);
if (alp->mounta.trig_mntpnt)
free(alp->mounta.trig_mntpnt);
if (alp->mounta.key)
free(alp->mounta.key);
}