Blame lib/dev-ioctl-lib.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *
Packit 8480eb
 *  ctl-dev-lib.c - module for Linux automount mount table lookup functions
Packit 8480eb
 *
Packit 8480eb
 *  Copyright 2008 Red Hat, Inc. All rights reserved.
Packit 8480eb
 *  Copyright 2008 Ian Kent <raven@themaw.net> - All Rights Reserved
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 <string.h>
Packit 8480eb
#include <errno.h>
Packit 8480eb
#include <limits.h>
Packit 8480eb
#include <sys/types.h>
Packit 8480eb
#include <sys/stat.h>
Packit 8480eb
#include <sys/ioctl.h>
Packit 8480eb
#include <fcntl.h>
Packit 8480eb
#include <sys/vfs.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
/* ioctld control function interface */
Packit 8480eb
static struct ioctl_ctl ctl = { -1, NULL };
Packit 8480eb
Packit 8480eb
#ifndef AUTOFS_SUPER_MAGIC
Packit 8480eb
#define AUTOFS_SUPER_MAGIC      0x0187
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Define functions for autofs ioctl control.
Packit 8480eb
 *
Packit 8480eb
 * We provide two interfaces. One which routes ioctls via a
Packit 8480eb
 * miscelaneous device node and can be used to obtain an ioctl
Packit 8480eb
 * file descriptor for autofs mounts that are covered by an
Packit 8480eb
 * active mount (eg. active direct or multi-mount offsets).
Packit 8480eb
 * The other provides the traditional autofs ioctl implementation.
Packit 8480eb
 *
Packit 8480eb
 * The miscielaneous device control functions are prefixed with
Packit 8480eb
 * dev_ctl_ and the traditional ones are prefixed with ioctl_.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_version(unsigned int, int, struct autofs_dev_ioctl *);
Packit 8480eb
static int dev_ioctl_protover(unsigned int, int, unsigned int *);
Packit 8480eb
static int dev_ioctl_protosubver(unsigned int, int, unsigned int *);
Packit 8480eb
static int dev_ioctl_mount_device(unsigned int, const char *, unsigned int, dev_t *);
Packit 8480eb
static int dev_ioctl_open(unsigned int, int *, dev_t, const char *);
Packit 8480eb
static int dev_ioctl_close(unsigned int, int);
Packit 8480eb
static int dev_ioctl_send_ready(unsigned int, int, unsigned int);
Packit 8480eb
static int dev_ioctl_send_fail(unsigned int, int, unsigned int, int);
Packit 8480eb
static int dev_ioctl_setpipefd(unsigned int, int, int);
Packit 8480eb
static int dev_ioctl_catatonic(unsigned int, int);
Packit 8480eb
static int dev_ioctl_timeout(unsigned int, int, time_t);
Packit 8480eb
static int dev_ioctl_requester(unsigned int, int, const char *, uid_t *, gid_t *);
Packit 8480eb
static int dev_ioctl_expire(unsigned int, int, const char *, unsigned int);
Packit 8480eb
static int dev_ioctl_askumount(unsigned int, int, unsigned int *);
Packit 8480eb
static int dev_ioctl_ismountpoint(unsigned int, int, const char *, unsigned int *);
Packit 8480eb
Packit 8480eb
static int ioctl_protover(unsigned int, int, unsigned int *);
Packit 8480eb
static int ioctl_protosubver(unsigned int, int, unsigned int *);
Packit 8480eb
static int ioctl_mount_device(unsigned int, const char *, unsigned int, dev_t *);
Packit 8480eb
static int ioctl_open(unsigned int, int *, dev_t, const char *);
Packit 8480eb
static int ioctl_close(unsigned int, int);
Packit 8480eb
static int ioctl_send_ready(unsigned int, int, unsigned int);
Packit 8480eb
static int ioctl_send_fail(unsigned int, int, unsigned int, int);
Packit 8480eb
static int ioctl_catatonic(unsigned int, int);
Packit 8480eb
static int ioctl_timeout(unsigned int, int, time_t);
Packit 8480eb
static int ioctl_expire(unsigned int, int, const char *, unsigned int);
Packit 8480eb
static int ioctl_askumount(unsigned int, int, unsigned int *);
Packit 8480eb
Packit 8480eb
static struct ioctl_ops dev_ioctl_ops = {
Packit 8480eb
	.version	= dev_ioctl_version,
Packit 8480eb
	.protover	= dev_ioctl_protover,
Packit 8480eb
	.protosubver	= dev_ioctl_protosubver,
Packit 8480eb
	.mount_device	= dev_ioctl_mount_device,
Packit 8480eb
	.open		= dev_ioctl_open,
Packit 8480eb
	.close		= dev_ioctl_close,
Packit 8480eb
	.send_ready	= dev_ioctl_send_ready,
Packit 8480eb
	.send_fail	= dev_ioctl_send_fail,
Packit 8480eb
	.setpipefd	= dev_ioctl_setpipefd,
Packit 8480eb
	.catatonic	= dev_ioctl_catatonic,
Packit 8480eb
	.timeout	= dev_ioctl_timeout,
Packit 8480eb
	.requester	= dev_ioctl_requester,
Packit 8480eb
	.expire		= dev_ioctl_expire,
Packit 8480eb
	.askumount	= dev_ioctl_askumount,
Packit 8480eb
	.ismountpoint	= dev_ioctl_ismountpoint
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
static struct ioctl_ops ioctl_ops = {
Packit 8480eb
	.version	= NULL,
Packit 8480eb
	.protover	= ioctl_protover,
Packit 8480eb
	.protosubver	= ioctl_protosubver,
Packit 8480eb
	.mount_device	= ioctl_mount_device,
Packit 8480eb
	.open		= ioctl_open,
Packit 8480eb
	.close		= ioctl_close,
Packit 8480eb
	.send_ready	= ioctl_send_ready,
Packit 8480eb
	.send_fail	= ioctl_send_fail,
Packit 8480eb
	.setpipefd	= NULL,
Packit 8480eb
	.catatonic	= ioctl_catatonic,
Packit 8480eb
	.timeout	= ioctl_timeout,
Packit 8480eb
	.requester	= NULL,
Packit 8480eb
	.expire		= ioctl_expire,
Packit 8480eb
	.askumount	= ioctl_askumount,
Packit 8480eb
	.ismountpoint	= NULL
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Allocate the control struct that holds the misc device file
Packit 8480eb
 * descriptor and operation despatcher table.
Packit 8480eb
 */
Packit 8480eb
void init_ioctl_ctl(void)
Packit 8480eb
{
Packit 8480eb
	int devfd;
Packit 8480eb
Packit 8480eb
	if (ctl.ops)
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	devfd = open_fd(CONTROL_DEVICE, O_RDONLY);
Packit 8480eb
	if (devfd == -1)
Packit 8480eb
		ctl.ops = &ioctl_ops;
Packit 8480eb
	else {
Packit 8480eb
		struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
		/*
Packit 8480eb
		 * Check compile version against kernel.
Packit 8480eb
		 * Selinux may allow us to open the device but not
Packit 8480eb
		 * actually allow us to do anything.
Packit 8480eb
		 */
Packit 8480eb
		init_autofs_dev_ioctl(¶m;;
Packit 8480eb
		if (ioctl(devfd, AUTOFS_DEV_IOCTL_VERSION, &param) == -1) {
Packit 8480eb
			close(devfd);
Packit 8480eb
			ctl.ops = &ioctl_ops;
Packit 8480eb
		} else {
Packit 8480eb
			ctl.devfd = devfd;
Packit 8480eb
			ctl.ops = &dev_ioctl_ops;
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void close_ioctl_ctl(void)
Packit 8480eb
{
Packit 8480eb
	if (ctl.devfd != -1) {
Packit 8480eb
		close(ctl.devfd);
Packit 8480eb
		ctl.devfd = -1;
Packit 8480eb
	}
Packit 8480eb
	ctl.ops = NULL;
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Return a pointer to the operations control struct */
Packit 8480eb
struct ioctl_ops *get_ioctl_ops(void)
Packit 8480eb
{
Packit 8480eb
	if (!ctl.ops)
Packit 8480eb
		init_ioctl_ctl();
Packit 8480eb
	return ctl.ops;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get kenrel version of misc device code */
Packit 8480eb
static int dev_ioctl_version(unsigned int logopt,
Packit 8480eb
			     int ioctlfd, struct autofs_dev_ioctl *param)
Packit 8480eb
{
Packit 8480eb
	param->ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_VERSION, param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get major version of autofs kernel module mount protocol */
Packit 8480eb
static int dev_ioctl_protover(unsigned int logopt,
Packit 8480eb
			      int ioctlfd, unsigned int *major)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOVER, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	*major = param.protover.version;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_protover(unsigned int logopt,
Packit 8480eb
			  int ioctlfd, unsigned int *major)
Packit 8480eb
{
Packit 8480eb
	return ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, major);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get minor version of autofs kernel module mount protocol */
Packit 8480eb
static int dev_ioctl_protosubver(unsigned int logopt,
Packit 8480eb
				 int ioctlfd, unsigned int *minor)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	*minor = param.protosubver.sub_version;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_protosubver(unsigned int logopt,
Packit 8480eb
			     int ioctlfd, unsigned int *minor)
Packit 8480eb
{
Packit 8480eb
	return ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, minor);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Allocate a parameter struct for misc device ioctl used when
Packit 8480eb
 * opening an autofs mount point. Attach the path to the end
Packit 8480eb
 * of the struct. and lookup the device number if not given.
Packit 8480eb
 * Locating the device number relies on the mount option
Packit 8480eb
 * "dev=<device number>" being present in the autofs fs mount
Packit 8480eb
 * options.
Packit 8480eb
 */
Packit 8480eb
static struct autofs_dev_ioctl *alloc_dev_ioctl_open(const char *path, dev_t devid)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *ioctl;
Packit 8480eb
	size_t size, p_len;
Packit 8480eb
	dev_t devno = devid;
Packit 8480eb
Packit 8480eb
	if (!path)
Packit 8480eb
		return NULL;
Packit 8480eb
Packit 8480eb
	p_len = strlen(path);
Packit 8480eb
	size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
Packit 8480eb
	ioctl = malloc(size);
Packit 8480eb
	if (!ioctl) {
Packit 8480eb
		errno = ENOMEM;
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(ioctl);
Packit 8480eb
	ioctl->size = size;
Packit 8480eb
	memcpy(ioctl->path, path, p_len);
Packit 8480eb
	ioctl->path[p_len] = '\0';
Packit 8480eb
	ioctl->openmount.devid = devno;
Packit 8480eb
Packit 8480eb
	return ioctl;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void free_dev_ioctl_open(struct autofs_dev_ioctl *ioctl)
Packit 8480eb
{
Packit 8480eb
	free(ioctl);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Allocate a parameter struct for misc device ioctl which includes
Packit 8480eb
 * a path. This is used when getting the last mount requester uid
Packit 8480eb
 * and gid and when checking if a path within the autofs filesystem
Packit 8480eb
 * is a mount point. We add the path to the end of the struct.
Packit 8480eb
 */
Packit 8480eb
static struct autofs_dev_ioctl *alloc_dev_ioctl_path(int ioctlfd, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *ioctl;
Packit 8480eb
	size_t size, p_len;
Packit 8480eb
Packit 8480eb
	if (!path) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	p_len = strlen(path);
Packit 8480eb
	size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
Packit 8480eb
	ioctl = malloc(size);
Packit 8480eb
	if (!ioctl) {
Packit 8480eb
		errno = ENOMEM;
Packit 8480eb
		return NULL;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(ioctl);
Packit 8480eb
	ioctl->ioctlfd = ioctlfd;
Packit 8480eb
	ioctl->size = size;
Packit 8480eb
	memcpy(ioctl->path, path, p_len);
Packit 8480eb
	ioctl->path[p_len] = '\0';
Packit 8480eb
Packit 8480eb
	return ioctl;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static void free_dev_ioctl_path(struct autofs_dev_ioctl *ioctl)
Packit 8480eb
{
Packit 8480eb
	free(ioctl);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Find the device number of an autofs mount with given path and
Packit 8480eb
 * type (eg..AUTOFS_TYPE_DIRECT). The device number is used by
Packit 8480eb
 * the kernel to identify the autofs super block when searching
Packit 8480eb
 * for the mount.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_mount_device(unsigned int logopt, const char *path, unsigned int type, dev_t *devid)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *param;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	if (!path) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*devid = -1;
Packit 8480eb
Packit 8480eb
	param = alloc_dev_ioctl_path(-1, path);
Packit 8480eb
	if (!param)
Packit 8480eb
		return -1;
Packit 8480eb
	param->ismountpoint.in.type = type;
Packit 8480eb
Packit 8480eb
	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param);
Packit 8480eb
	if (err == -1) {
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		free_dev_ioctl_path(param);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (err)
Packit 8480eb
		*devid = param->ismountpoint.out.devid;
Packit 8480eb
Packit 8480eb
	free_dev_ioctl_path(param);
Packit 8480eb
Packit 8480eb
	return err;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_mount_device(unsigned int logopt,
Packit 8480eb
			      const char *path, unsigned int type,
Packit 8480eb
			      dev_t *devid)
Packit 8480eb
{
Packit 8480eb
	return -1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get a file descriptor for control operations */
Packit 8480eb
static int dev_ioctl_open(unsigned int logopt,
Packit 8480eb
			  int *ioctlfd, dev_t devid, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *param;
Packit 8480eb
Packit 8480eb
	*ioctlfd = -1;
Packit 8480eb
Packit 8480eb
	param = alloc_dev_ioctl_open(path, devid);
Packit 8480eb
	if (!param)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) == -1) {
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		free_dev_ioctl_open(param);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*ioctlfd = param->ioctlfd;
Packit 8480eb
Packit 8480eb
	free_dev_ioctl_open(param);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_open(unsigned int logopt,
Packit 8480eb
		      int *ioctlfd, dev_t devid, const char *path)
Packit 8480eb
{
Packit 8480eb
	struct statfs sfs;
Packit 8480eb
	int save_errno, fd;
Packit 8480eb
Packit 8480eb
	*ioctlfd = -1;
Packit 8480eb
Packit 8480eb
	fd = open_fd(path, O_RDONLY);
Packit 8480eb
	if (fd == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	if (fstatfs(fd, &sfs) == -1) {
Packit 8480eb
		save_errno = errno;
Packit 8480eb
		goto err;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (sfs.f_type != AUTOFS_SUPER_MAGIC) {
Packit 8480eb
		save_errno = ENOENT;
Packit 8480eb
		goto err;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*ioctlfd = fd;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
err:
Packit 8480eb
	close(fd);
Packit 8480eb
	errno = save_errno;
Packit 8480eb
	return -1;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Close */
Packit 8480eb
static int dev_ioctl_close(unsigned int logopt, int ioctlfd)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CLOSEMOUNT, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_close(unsigned int logopt, int ioctlfd)
Packit 8480eb
{
Packit 8480eb
	return close(ioctlfd);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Send ready status for given token */
Packit 8480eb
static int dev_ioctl_send_ready(unsigned int logopt,
Packit 8480eb
				int ioctlfd, unsigned int token)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	if (token == 0) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, "token = %d", token);
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
	param.ready.token = token;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_READY, &param) == -1) {
Packit 8480eb
		char *estr, buf[MAX_ERR_BUF];
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("AUTOFS_DEV_IOCTL_READY: error %s", estr);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_send_ready(unsigned int logopt,
Packit 8480eb
			    int ioctlfd, unsigned int token)
Packit 8480eb
{
Packit 8480eb
	if (token == 0) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, "token = %d", token);
Packit 8480eb
Packit 8480eb
	if (ioctl(ioctlfd, AUTOFS_IOC_READY, token) == -1) {
Packit 8480eb
		char *estr, buf[MAX_ERR_BUF];
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("AUTOFS_IOC_READY: error %s", estr);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Send ready status for given token.
Packit 8480eb
 *
Packit 8480eb
 * The device node ioctl implementation allows for sending a status
Packit 8480eb
 * of other than ENOENT, unlike the tradional interface.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_send_fail(unsigned int logopt,
Packit 8480eb
			       int ioctlfd, unsigned int token, int status)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	if (token == 0) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, "token = %d", token);
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
	param.fail.token = token;
Packit 8480eb
	param.fail.status = status;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_FAIL, &param) == -1) {
Packit 8480eb
		char *estr, buf[MAX_ERR_BUF];
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("AUTOFS_DEV_IOCTL_FAIL: error %s", estr);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_send_fail(unsigned int logopt,
Packit 8480eb
			   int ioctlfd, unsigned int token, int status)
Packit 8480eb
{
Packit 8480eb
	if (token == 0) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	debug(logopt, "token = %d", token);
Packit 8480eb
Packit 8480eb
	if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, token) == -1) {
Packit 8480eb
		char *estr, buf[MAX_ERR_BUF];
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		estr = strerror_r(errno, buf, MAX_ERR_BUF);
Packit 8480eb
		logerr("AUTOFS_IOC_FAIL: error %s", estr);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Set the pipe fd for kernel communication.
Packit 8480eb
 *
Packit 8480eb
 * Normally this is set at mount using an option but if we
Packit 8480eb
 * are reconnecting to a busy mount then we need to use this
Packit 8480eb
 * to tell the autofs kernel module about the new pipe fd. In
Packit 8480eb
 * order to protect mounts against incorrectly setting the
Packit 8480eb
 * pipefd we also require that the autofs mount be catatonic.
Packit 8480eb
 *
Packit 8480eb
 * If successful this also sets the process group id used to
Packit 8480eb
 * identify the controlling process to the process group of
Packit 8480eb
 * the caller.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_setpipefd(unsigned int logopt, int ioctlfd, int pipefd)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	if (pipefd == -1) {
Packit 8480eb
		errno = EBADF;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
	param.setpipefd.pipefd = pipefd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_SETPIPEFD, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Make the autofs mount point catatonic, no longer responsive to
Packit 8480eb
 * mount requests. Also closes the kernel pipe file descriptor.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_catatonic(unsigned int logopt, int ioctlfd)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CATATONIC, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_catatonic(unsigned int logopt, int ioctlfd)
Packit 8480eb
{
Packit 8480eb
	return ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Set the autofs mount timeout */
Packit 8480eb
static int dev_ioctl_timeout(unsigned int logopt, int ioctlfd, time_t timeout)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
	param.timeout.timeout = timeout;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_timeout(unsigned int logopt, int ioctlfd, time_t timeout)
Packit 8480eb
{
Packit 8480eb
	time_t tout = timeout;
Packit 8480eb
	return ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Get the uid and gid of the last request for the mountpoint, path.
Packit 8480eb
 *
Packit 8480eb
 * When reconstructing an autofs mount tree with active mounts
Packit 8480eb
 * we need to re-connect to mounts that may have used the original
Packit 8480eb
 * process uid and gid (or string variations of them) for mount
Packit 8480eb
 * lookups within the map entry.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_requester(unsigned int logopt,
Packit 8480eb
			       int ioctlfd, const char *path,
Packit 8480eb
			       uid_t *uid, gid_t *gid)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *param;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	if (!path)
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
Packit 8480eb
	*uid = -1;
Packit 8480eb
	*gid = -1;
Packit 8480eb
Packit 8480eb
Packit 8480eb
	param = alloc_dev_ioctl_path(ioctlfd, path);
Packit 8480eb
	if (!param)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_REQUESTER, param);
Packit 8480eb
	if (err == -1) {
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		free_dev_ioctl_open(param);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	*uid = param->requester.uid;
Packit 8480eb
	*gid = param->requester.gid;
Packit 8480eb
Packit 8480eb
	free_dev_ioctl_path(param);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Call repeatedly until it returns EAGAIN, meaning there's nothing
Packit 8480eb
 * more that can be done.
Packit 8480eb
 */
Packit 8480eb
static int expire(unsigned int logopt,
Packit 8480eb
		  int cmd, int fd, int ioctlfd, const char *path, void *arg)
Packit 8480eb
{
Packit 8480eb
	int ret, retries = EXPIRE_RETRIES;
Packit 8480eb
	unsigned int may_umount;
Packit 8480eb
Packit 8480eb
	while (retries--) {
Packit 8480eb
		struct timespec tm = {0, 100000000};
Packit 8480eb
Packit 8480eb
		/* Ggenerate expire message for the mount. */
Packit 8480eb
		ret = ioctl(fd, cmd, arg);
Packit 8480eb
		if (ret == -1) {
Packit 8480eb
			/* Mount has gone away */
Packit 8480eb
			if (errno == EBADF || errno == EINVAL)
Packit 8480eb
				return 0;
Packit 8480eb
Packit 8480eb
			/*
Packit 8480eb
			 * Other than EAGAIN is an expire error so continue.
Packit 8480eb
			 * Kernel will try the next mount for indirect maps
Packit 8480eb
			 * and the same mount again for direct maps, limited
Packit 8480eb
			 * by retries.
Packit 8480eb
			 */
Packit 8480eb
			if (errno == EAGAIN)
Packit 8480eb
				break;
Packit 8480eb
		}
Packit 8480eb
		nanosleep(&tm, NULL);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	may_umount = 0;
Packit 8480eb
	if (ctl.ops->askumount(logopt, ioctlfd, &may_umount))
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	if (!may_umount)
Packit 8480eb
		return 1;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int dev_ioctl_expire(unsigned int logopt,
Packit 8480eb
			    int ioctlfd, const char *path, unsigned int when)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
	param.expire.how = when;
Packit 8480eb
Packit 8480eb
	return expire(logopt, AUTOFS_DEV_IOCTL_EXPIRE,
Packit 8480eb
		      ctl.devfd, ioctlfd, path, (void *) ¶m;;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_expire(unsigned int logopt,
Packit 8480eb
		        int ioctlfd, const char *path, unsigned int when)
Packit 8480eb
{
Packit 8480eb
	return expire(logopt, AUTOFS_IOC_EXPIRE_MULTI,
Packit 8480eb
		      ioctlfd, ioctlfd, path, (void *) &when);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Check if autofs mount point is in use */
Packit 8480eb
static int dev_ioctl_askumount(unsigned int logopt,
Packit 8480eb
			       int ioctlfd, unsigned int *busy)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl param;
Packit 8480eb
Packit 8480eb
	init_autofs_dev_ioctl(¶m;;
Packit 8480eb
	param.ioctlfd = ioctlfd;
Packit 8480eb
Packit 8480eb
	if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ASKUMOUNT, &param) == -1)
Packit 8480eb
		return -1;
Packit 8480eb
Packit 8480eb
	*busy = param.askumount.may_umount;
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
static int ioctl_askumount(unsigned int logopt,
Packit 8480eb
			   int ioctlfd, unsigned int *busy)
Packit 8480eb
{
Packit 8480eb
	return ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, busy);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/*
Packit 8480eb
 * Check if the given path is a mountpoint.
Packit 8480eb
 *
Packit 8480eb
 * The path is considered a mountpoint if it is itself a mountpoint
Packit 8480eb
 * or contains a mount, such as a multi-mount without a root mount.
Packit 8480eb
 * In addition, if the path is itself a mountpoint we return whether
Packit 8480eb
 * the mounted file system is an autofs filesystem or other file
Packit 8480eb
 * system.
Packit 8480eb
 */
Packit 8480eb
static int dev_ioctl_ismountpoint(unsigned int logopt,
Packit 8480eb
				  int ioctlfd, const char *path,
Packit 8480eb
				  unsigned int *mountpoint)
Packit 8480eb
{
Packit 8480eb
	struct autofs_dev_ioctl *param;
Packit 8480eb
	int err;
Packit 8480eb
Packit 8480eb
	*mountpoint = 0;
Packit 8480eb
Packit 8480eb
	if (!path) {
Packit 8480eb
		errno = EINVAL;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	param = alloc_dev_ioctl_path(ioctlfd, path);
Packit 8480eb
	if (!param)
Packit 8480eb
		return -1;
Packit 8480eb
	set_autofs_type_any(&param->ismountpoint.in.type);
Packit 8480eb
Packit 8480eb
	err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param);
Packit 8480eb
	if (err == -1) {
Packit 8480eb
		int save_errno = errno;
Packit 8480eb
		free_dev_ioctl_path(param);
Packit 8480eb
		errno = save_errno;
Packit 8480eb
		return -1;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (err) {
Packit 8480eb
		*mountpoint = DEV_IOCTL_IS_MOUNTED;
Packit 8480eb
Packit 8480eb
		if (param->ismountpoint.out.magic == AUTOFS_SUPER_MAGIC)
Packit 8480eb
			*mountpoint |= DEV_IOCTL_IS_AUTOFS;
Packit 8480eb
		else
Packit 8480eb
			*mountpoint |= DEV_IOCTL_IS_OTHER;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	free_dev_ioctl_path(param);
Packit 8480eb
Packit 8480eb
	return 0;
Packit 8480eb
}