|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* mount_autofs.c - Module for recursive autofs mounts.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 1997 Transmeta Corporation - All Rights Reserved
|
|
Packit |
8480eb |
* Copyright 2006 Ian Kent <raven@themaw.net>
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8480eb |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8480eb |
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
|
Packit |
8480eb |
* USA; either version 2 of the License, or (at your option) any later
|
|
Packit |
8480eb |
* version; incorporated herein by reference.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
#include <stdlib.h>
|
|
Packit |
8480eb |
#include <malloc.h>
|
|
Packit |
8480eb |
#include <string.h>
|
|
Packit |
8480eb |
#include <signal.h>
|
|
Packit |
8480eb |
#include <sys/param.h>
|
|
Packit |
8480eb |
#include <sys/types.h>
|
|
Packit |
8480eb |
#include <sys/stat.h>
|
|
Packit |
8480eb |
#include <sys/wait.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define MODULE_MOUNT
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define MODPREFIX "mount(autofs): "
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Attribute to create detached thread */
|
|
Packit |
8480eb |
extern pthread_attr_t th_attr_detached;
|
|
Packit |
8480eb |
extern struct startup_cond suc;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_init(void **context)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_reinit(void **context)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_mount(struct autofs_point *ap, const char *root, const char *name,
|
|
Packit |
8480eb |
int name_len, const char *what, const char *fstype,
|
|
Packit |
8480eb |
const char *c_options, void *context)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct startup_cond suc;
|
|
Packit |
8480eb |
pthread_t thid;
|
|
Packit |
8480eb |
char realpath[PATH_MAX];
|
|
Packit |
8480eb |
char mountpoint[PATH_MAX];
|
|
Packit |
8480eb |
const char **argv;
|
|
Packit |
8480eb |
int argc, status;
|
|
Packit |
8480eb |
int nobind = ap->flags & MOUNT_FLAG_NOBIND;
|
|
Packit |
8480eb |
int ghost = ap->flags & MOUNT_FLAG_GHOST;
|
|
Packit |
8480eb |
int symlnk = ap->flags & MOUNT_FLAG_SYMLINK;
|
|
Packit Service |
870bb4 |
int strictexpire = ap->flags & MOUNT_FLAG_STRICTEXPIRE;
|
|
Packit |
8480eb |
time_t timeout = get_exp_timeout(ap, ap->entry->maps);
|
|
Packit |
8480eb |
unsigned logopt = ap->logopt;
|
|
Packit |
8480eb |
struct map_type_info *info;
|
|
Packit |
8480eb |
struct master *master;
|
|
Packit |
8480eb |
struct master_mapent *entry;
|
|
Packit |
8480eb |
struct map_source *source;
|
|
Packit |
8480eb |
struct autofs_point *nap;
|
|
Packit Service |
31f869 |
struct mnt_list *mnt;
|
|
Packit |
8480eb |
char buf[MAX_ERR_BUF];
|
|
Packit |
8480eb |
char *options, *p;
|
|
Packit |
8480eb |
int len, ret;
|
|
Packit |
8480eb |
int hosts = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Root offset of multi-mount */
|
|
Packit |
8480eb |
len = strlen(root);
|
|
Packit |
8480eb |
if (root[len - 1] == '/') {
|
|
Packit |
8480eb |
strcpy(realpath, ap->path);
|
|
Packit |
8480eb |
strcat(realpath, "/");
|
|
Packit |
8480eb |
strcat(realpath, name);
|
|
Packit |
8480eb |
len--;
|
|
Packit |
8480eb |
strncpy(mountpoint, root, len);
|
|
Packit |
8480eb |
mountpoint[len] = '\0';
|
|
Packit |
8480eb |
} else if (*name == '/') {
|
|
Packit |
8480eb |
if (ap->flags & MOUNT_FLAG_REMOUNT) {
|
|
Packit |
8480eb |
strcpy(mountpoint, name);
|
|
Packit |
8480eb |
strcpy(realpath, name);
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
strcpy(mountpoint, root);
|
|
Packit |
8480eb |
strcpy(realpath, name);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
strcpy(mountpoint, root);
|
|
Packit |
8480eb |
strcat(mountpoint, "/");
|
|
Packit |
8480eb |
strcpy(realpath, mountpoint);
|
|
Packit |
8480eb |
strcat(mountpoint, name);
|
|
Packit |
8480eb |
strcat(realpath, name);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
options = NULL;
|
|
Packit |
8480eb |
if (c_options) {
|
|
Packit |
8480eb |
char *noptions;
|
|
Packit |
8480eb |
const char *comma;
|
|
Packit |
8480eb |
char *np;
|
|
Packit |
8480eb |
int len = strlen(c_options) + 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
noptions = np = alloca(len);
|
|
Packit |
8480eb |
if (!np) {
|
|
Packit |
8480eb |
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
|
Packit |
8480eb |
error(ap->logopt, MODPREFIX "alloca: %s", estr);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
memset(np, 0, len);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Grab the autofs specific options */
|
|
Packit |
8480eb |
for (comma = c_options; *comma != '\0';) {
|
|
Packit |
8480eb |
const char *cp;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (*comma == ',')
|
|
Packit |
8480eb |
comma++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
cp = comma;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (*comma != '\0' && *comma != ',')
|
|
Packit |
8480eb |
comma++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (_strncmp("nobrowse", cp, 8) == 0 ||
|
|
Packit |
8480eb |
_strncmp("nobrowsable", cp, 11) == 0)
|
|
Packit |
8480eb |
ghost = 0;
|
|
Packit |
8480eb |
else if (_strncmp("nobind", cp, 6) == 0)
|
|
Packit |
8480eb |
nobind = 1;
|
|
Packit |
8480eb |
else if (_strncmp("browse", cp, 6) == 0 ||
|
|
Packit |
8480eb |
_strncmp("browsable", cp, 9) == 0)
|
|
Packit |
8480eb |
ghost = 1;
|
|
Packit |
8480eb |
else if (_strncmp("symlink", cp, 7) == 0)
|
|
Packit |
8480eb |
symlnk = 1;
|
|
Packit Service |
870bb4 |
else if (_strncmp("strictexpire", cp, 12) == 0)
|
|
Packit Service |
870bb4 |
strictexpire = 1;
|
|
Packit |
8480eb |
else if (_strncmp("hosts", cp, 5) == 0)
|
|
Packit |
8480eb |
hosts = 1;
|
|
Packit |
8480eb |
else if (_strncmp("timeout=", cp, 8) == 0) {
|
|
Packit |
8480eb |
char *val = strchr(cp, '=');
|
|
Packit |
8480eb |
unsigned tout;
|
|
Packit |
8480eb |
if (val) {
|
|
Packit |
8480eb |
int ret = sscanf(cp, "timeout=%u", &tout);
|
|
Packit |
8480eb |
if (ret)
|
|
Packit |
8480eb |
timeout = tout;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
memcpy(np, cp, comma - cp + 1);
|
|
Packit |
8480eb |
np += comma - cp + 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
options = noptions;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
debug(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "mountpoint=%s what=%s options=%s",
|
|
Packit |
8480eb |
mountpoint, what, options);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
master = ap->entry->master;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
entry = master_new_mapent(master, realpath, ap->entry->age);
|
|
Packit |
8480eb |
if (!entry) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "failed to malloc master_mapent struct");
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = master_add_autofs_point(entry, logopt, nobind, ghost, 1);
|
|
Packit |
8480eb |
if (!ret) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "failed to add autofs_point to entry");
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
nap = entry->ap;
|
|
Packit |
8480eb |
nap->parent = ap;
|
|
Packit |
8480eb |
if (symlnk)
|
|
Packit |
8480eb |
nap->flags |= MOUNT_FLAG_SYMLINK;
|
|
Packit Service |
870bb4 |
if (strictexpire)
|
|
Packit Service |
870bb4 |
nap->flags |= MOUNT_FLAG_STRICTEXPIRE;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (hosts)
|
|
Packit |
8480eb |
argc = 0;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
argc = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (options) {
|
|
Packit |
8480eb |
char *t = options;
|
|
Packit |
8480eb |
do {
|
|
Packit |
8480eb |
argc++;
|
|
Packit |
8480eb |
if (*t == ',')
|
|
Packit |
8480eb |
t++;
|
|
Packit |
8480eb |
} while ((t = strchr(t, ',')) != NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
argv = (const char **) alloca((argc + 1) * sizeof(char *));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (hosts)
|
|
Packit |
8480eb |
argc = 0;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
argc = 1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If a mount of a hosts map is being requested it will come
|
|
Packit |
8480eb |
* ro us via the options. Catch that below when processing the
|
|
Packit |
8480eb |
* option and create type info struct then.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (hosts)
|
|
Packit |
8480eb |
info = parse_map_type_info("hosts:");
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
info = parse_map_type_info(what);
|
|
Packit |
8480eb |
if (!info) {
|
|
Packit |
8480eb |
error(ap->logopt, MODPREFIX "failed to parse map info");
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (info->map)
|
|
Packit |
8480eb |
argv[0] = info->map;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (options) {
|
|
Packit |
8480eb |
p = options;
|
|
Packit |
8480eb |
do {
|
|
Packit |
8480eb |
if (*p == ',') {
|
|
Packit |
8480eb |
*p = '\0';
|
|
Packit |
8480eb |
p++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
argv[argc++] = p;
|
|
Packit |
8480eb |
} while ((p = strchr(p, ',')) != NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
argv[argc] = NULL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For amd type "auto" the map is often re-used so check
|
|
Packit |
8480eb |
* if the the parent map can be used and use it if it
|
|
Packit |
8480eb |
* matches.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Also if the parent map format is amd and the format
|
|
Packit |
8480eb |
* isn't specified in the map entry set it from the parent
|
|
Packit |
8480eb |
* map source.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
source = NULL;
|
|
Packit |
8480eb |
if (ap->entry->maps && ap->entry->maps->flags & MAP_FLAG_FORMAT_AMD) {
|
|
Packit |
8480eb |
struct map_source *s = ap->entry->maps;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For amd maps, if the format and source type aren't
|
|
Packit |
8480eb |
* specified try and set them from the parent.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!info->format) {
|
|
Packit |
8480eb |
info->format = strdup("amd");
|
|
Packit |
8480eb |
if (!info->format)
|
|
Packit |
8480eb |
warn(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"failed to set amd map format");
|
|
Packit |
8480eb |
if (!info->type && s->type) {
|
|
Packit |
8480eb |
info->type = strdup(s->type);
|
|
Packit |
8480eb |
if (!info->type)
|
|
Packit |
8480eb |
warn(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"failed to set amd map type");
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
source = master_get_map_source(ap->entry,
|
|
Packit |
8480eb |
info->type, info->format,
|
|
Packit |
8480eb |
argc, argv);
|
|
Packit |
8480eb |
if (source)
|
|
Packit |
8480eb |
entry->maps = source;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!source)
|
|
Packit |
8480eb |
source = master_add_map_source(entry,
|
|
Packit |
8480eb |
info->type, info->format,
|
|
Packit |
8480eb |
monotonic_time(NULL),
|
|
Packit |
8480eb |
argc, argv);
|
|
Packit |
8480eb |
if (!source) {
|
|
Packit |
8480eb |
error(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "failed to add map source to entry");
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
free_map_type_info(info);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
free_map_type_info(info);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
set_exp_timeout(nap, NULL, timeout);
|
|
Packit |
8480eb |
nap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
mounts_mutex_lock(ap);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (source->flags & MAP_FLAG_FORMAT_AMD) {
|
|
Packit Service |
6539ae |
struct mnt_list *mnt;
|
|
Packit |
8480eb |
|
|
Packit Service |
6539ae |
mnt = mnts_find_amdmount(entry->path);
|
|
Packit Service |
6539ae |
if (mnt) {
|
|
Packit Service |
6539ae |
if (mnt->amd_pref) {
|
|
Packit Service |
6539ae |
nap->pref = mnt->amd_pref;
|
|
Packit Service |
6539ae |
mnt->amd_pref = NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
6539ae |
if (mnt->amd_cache_opts & AMD_CACHE_OPTION_ALL)
|
|
Packit |
8480eb |
nap->flags |= MOUNT_FLAG_AMD_CACHE_ALL;
|
|
Packit Service |
6539ae |
|
|
Packit Service |
6539ae |
mnts_put_mount(mnt);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (handle_mounts_startup_cond_init(&suc)) {
|
|
Packit |
8480eb |
crit(ap->logopt, MODPREFIX
|
|
Packit |
8480eb |
"failed to init startup cond for mount %s", entry->path);
|
|
Packit |
8480eb |
mounts_mutex_unlock(ap);
|
|
Packit |
8480eb |
master_free_map_source(source, 1);
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
31f869 |
mnt = mnts_add_submount(nap);
|
|
Packit Service |
31f869 |
if (!mnt) {
|
|
Packit Service |
31f869 |
crit(ap->logopt,
|
|
Packit Service |
31f869 |
MODPREFIX "failed to allocate mount %s", realpath);
|
|
Packit Service |
31f869 |
handle_mounts_startup_cond_destroy(&suc);
|
|
Packit Service |
31f869 |
mounts_mutex_unlock(ap);
|
|
Packit Service |
31f869 |
master_free_map_source(source, 1);
|
|
Packit Service |
31f869 |
master_free_mapent(entry);
|
|
Packit Service |
31f869 |
return 1;
|
|
Packit Service |
31f869 |
}
|
|
Packit Service |
31f869 |
|
|
Packit Service |
31f869 |
|
|
Packit |
8480eb |
suc.ap = nap;
|
|
Packit |
8480eb |
suc.root = mountpoint;
|
|
Packit |
8480eb |
suc.done = 0;
|
|
Packit |
8480eb |
suc.status = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (pthread_create(&thid, &th_attr_detached, handle_mounts, &suc)) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX
|
|
Packit |
8480eb |
"failed to create mount handler thread for %s",
|
|
Packit |
8480eb |
realpath);
|
|
Packit |
8480eb |
handle_mounts_startup_cond_destroy(&suc);
|
|
Packit Service |
31f869 |
mnts_remove_submount(nap->path);
|
|
Packit |
8480eb |
mounts_mutex_unlock(ap);
|
|
Packit |
8480eb |
master_free_map_source(source, 1);
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (!suc.done) {
|
|
Packit |
8480eb |
status = pthread_cond_wait(&suc.cond, &suc.mutex);
|
|
Packit |
8480eb |
if (status) {
|
|
Packit |
8480eb |
handle_mounts_startup_cond_destroy(&suc);
|
|
Packit Service |
31f869 |
mnts_remove_submount(nap->path);
|
|
Packit |
8480eb |
mounts_mutex_unlock(ap);
|
|
Packit |
8480eb |
master_free_map_source(source, 1);
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (suc.status) {
|
|
Packit |
8480eb |
crit(ap->logopt,
|
|
Packit |
8480eb |
MODPREFIX "failed to create submount for %s", realpath);
|
|
Packit |
8480eb |
handle_mounts_startup_cond_destroy(&suc);
|
|
Packit Service |
31f869 |
mnts_remove_submount(nap->path);
|
|
Packit |
8480eb |
mounts_mutex_unlock(ap);
|
|
Packit |
8480eb |
master_free_map_source(source, 1);
|
|
Packit |
8480eb |
master_free_mapent(entry);
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
nap->thid = thid;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ap->submnt_count++;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
handle_mounts_startup_cond_destroy(&suc);
|
|
Packit |
8480eb |
mounts_mutex_unlock(ap);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int mount_done(void *context)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|