Blame modules/mount_autofs.c

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