Blame modules/mount_autofs.c

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 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 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 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 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 8480eb
		struct amd_entry *am_entry = __master_find_amdmount(ap, entry->path);
Packit 8480eb
Packit 8480eb
		if (am_entry) {
Packit 8480eb
			if (am_entry->pref) {
Packit 8480eb
				nap->pref = am_entry->pref;
Packit 8480eb
				am_entry->pref = NULL;
Packit 8480eb
			}
Packit 8480eb
Packit 8480eb
			if (am_entry->cache_opts & AMD_CACHE_OPTION_ALL)
Packit 8480eb
				nap->flags |= MOUNT_FLAG_AMD_CACHE_ALL;
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 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 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 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 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
	list_add(&nap->mounts, &ap->submounts);
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
}