diff -up autofs-5.0.3/daemon/indirect.c.device-node-control autofs-5.0.3/daemon/indirect.c
--- autofs-5.0.3/daemon/indirect.c.device-node-control 2008-02-25 08:58:46.000000000 +0900
+++ autofs-5.0.3/daemon/indirect.c 2008-02-25 09:03:12.000000000 +0900
@@ -43,6 +43,8 @@ extern pthread_attr_t thread_attr;
static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
+static const unsigned int indirect = AUTOFS_TYPE_INDIRECT;
+
static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
{
struct mnt_list *this;
@@ -88,19 +90,20 @@ static int unlink_mount_tree(struct auto
static int do_mount_autofs_indirect(struct autofs_point *ap)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
time_t timeout = ap->exp_timeout;
char *options = NULL;
const char *type, *map_name = NULL;
struct stat st;
struct mnt_list *mnts;
- int cl_flags, ret;
+ int ret;
mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
if (mnts) {
ret = unlink_mount_tree(ap, mnts);
free_mnt_list(mnts);
if (!ret) {
- debug(ap->logopt,
+ error(ap->logopt,
"already mounted as other than autofs "
"or failed to unlink entry in tree");
goto out_err;
@@ -108,8 +111,10 @@ static int do_mount_autofs_indirect(stru
}
options = make_options_string(ap->path, ap->kpipefd, NULL);
- if (!options)
+ if (!options) {
+ error(ap->logopt, "options string error");
goto out_err;
+ }
/* In case the directory doesn't exist, try to mkdir it */
if (mkdir_path(ap->path, 0555) < 0) {
@@ -147,22 +152,15 @@ static int do_mount_autofs_indirect(stru
options = NULL;
- /* Root directory for ioctl()'s */
- ap->ioctlfd = open(ap->path, O_RDONLY);
- if (ap->ioctlfd < 0) {
+ if (ops->open(ap->logopt, &ap->ioctlfd, -1, ap->path, indirect)) {
crit(ap->logopt,
"failed to create ioctl fd for autofs path %s", ap->path);
goto out_umount;
}
- if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ap->ioctlfd, F_SETFD, cl_flags);
- }
-
ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
- ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+ ops->timeout(ap->logopt, ap->ioctlfd, &timeout);
if (ap->exp_timeout)
info(ap->logopt,
@@ -235,8 +233,10 @@ int mount_autofs_indirect(struct autofs_
int umount_autofs_indirect(struct autofs_point *ap)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
char buf[MAX_ERR_BUF];
- int ret, rv, retries;
+ int rv, retries;
+ unsigned int ret;
/*
* Since submounts look after themselves the parent never knows
@@ -248,7 +248,7 @@ int umount_autofs_indirect(struct autofs
lookup_source_close_ioctlfd(ap->parent, ap->path);
/* If we are trying to shutdown make sure we can umount */
- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
+ rv = ops->askumount(ap->logopt, ap->ioctlfd, &ret);
if (rv == -1) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
logerr("ioctl failed: %s", estr);
@@ -258,8 +258,8 @@ int umount_autofs_indirect(struct autofs
return 1;
}
- ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
- close(ap->ioctlfd);
+ ops->catatonic(ap->logopt, ap->ioctlfd);
+ ops->close(ap->logopt, ap->ioctlfd);
ap->ioctlfd = -1;
close(ap->state_pipe[0]);
close(ap->state_pipe[1]);
@@ -320,48 +320,6 @@ force_umount:
return rv;
}
-static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when)
-{
- char buf[MAX_ERR_BUF];
- int ret, retries;
- struct stat st;
-
- if (fstat(ioctlfd, &st) == -1) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- debug(ap->logopt, "fstat failed: %s", estr);
- return 0;
- }
-
- retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
-
- while (retries--) {
- struct timespec tm = {0, 100000000};
-
- /* Ggenerate expire message for the mount. */
- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
- if (ret == -1) {
- /* Mount has gone away */
- if (errno == EBADF || errno == EINVAL)
- return 1;
-
- /*
- * Other than EAGAIN is an expire error so continue.
- * Kernel will try the next mount.
- */
- if (errno == EAGAIN)
- break;
- }
- nanosleep(&tm, NULL);
- }
-
- if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
- if (!ret)
- return 0;
- }
-
- return 1;
-}
-
static void mnts_cleanup(void *arg)
{
struct mnt_list *mnts = (struct mnt_list *) arg;
@@ -371,6 +329,7 @@ static void mnts_cleanup(void *arg)
void *expire_proc_indirect(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct autofs_point *ap;
struct mapent *me = NULL;
struct mnt_list *mnts = NULL, *next;
@@ -458,8 +417,8 @@ void *expire_proc_indirect(void *arg)
debug(ap->logopt, "expire %s", next->path);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
- ret = expire_indirect(ap, ioctlfd, next->path, now);
- if (!ret)
+ ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+ if (ret)
left++;
pthread_setcancelstate(cur_state, NULL);
}
@@ -472,8 +431,8 @@ void *expire_proc_indirect(void *arg)
*/
if (mnts) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
- ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
- if (!ret)
+ ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, now);
+ if (ret)
left++;
pthread_setcancelstate(cur_state, NULL);
}
@@ -495,8 +454,8 @@ void *expire_proc_indirect(void *arg)
pthread_cleanup_pop(1);
if (submnts)
- debug(ap->logopt,
- "%d submounts remaining in %s", submnts, ap->path);
+ info(ap->logopt,
+ "%d submounts remaining in %s", submnts, ap->path);
/*
* EXPIRE_MULTI is synchronous, so we can be sure (famous last
@@ -527,8 +486,11 @@ static void pending_cond_destroy(void *a
static void expire_send_fail(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt = arg;
- send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+ struct autofs_point *ap = mt->ap;
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token, -ENOENT);
}
static void free_pending_args(void *arg)
@@ -546,6 +508,7 @@ static void expire_mutex_unlock(void *ar
static void *do_expire_indirect(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt;
struct autofs_point *ap;
int status, state;
@@ -572,9 +535,11 @@ static void *do_expire_indirect(void *ar
status = do_expire(mt->ap, mt->name, mt->len);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
if (status)
- send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token, -status);
else
- send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ ops->send_ready(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token);
pthread_setcancelstate(state, NULL);
pthread_cleanup_pop(0);
@@ -586,6 +551,7 @@ static void *do_expire_indirect(void *ar
int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_indirect_t *pkt)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt;
char buf[MAX_ERR_BUF];
pthread_t thid;
@@ -600,7 +566,8 @@ int handle_packet_expire_indirect(struct
if (!mt) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
logerr("malloc: %s", estr);
- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
pthread_setcancelstate(state, NULL);
return 1;
}
@@ -622,7 +589,8 @@ int handle_packet_expire_indirect(struct
status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, pkt->wait_queue_token, -status);
expire_mutex_unlock(NULL);
pending_cond_destroy(mt);
free_pending_args(mt);
@@ -647,8 +615,11 @@ int handle_packet_expire_indirect(struct
static void mount_send_fail(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt = arg;
- send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
+ struct autofs_point *ap = mt->ap;
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token, -ENOENT);
}
static void mount_mutex_unlock(void *arg)
@@ -660,6 +631,7 @@ static void mount_mutex_unlock(void *arg
static void *do_mount_indirect(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt;
struct autofs_point *ap;
char buf[PATH_MAX + 1];
@@ -837,10 +809,13 @@ cont:
status = lookup_nss_mount(ap, NULL, mt->name, mt->len);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
if (status) {
- send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ ops->send_ready(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token);
info(ap->logopt, "mounted %s", buf);
} else {
- send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+ /* TODO: get mount return status from lookup_nss_mount */
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, mt->wait_queue_token, -ENOENT);
info(ap->logopt, "failed to mount %s", buf);
}
pthread_setcancelstate(state, NULL);
@@ -854,6 +829,7 @@ cont:
int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
pthread_t thid;
char buf[MAX_ERR_BUF];
struct pending_args *mt;
@@ -868,7 +844,8 @@ int handle_packet_missing_indirect(struc
if (ap->shutdown ||
ap->state == ST_SHUTDOWN_FORCE ||
ap->state == ST_SHUTDOWN) {
- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, pkt->wait_queue_token, -ENOENT);
pthread_setcancelstate(state, NULL);
return 0;
}
@@ -877,7 +854,8 @@ int handle_packet_missing_indirect(struc
if (!mt) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
logerr("malloc: %s", estr);
- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
pthread_setcancelstate(state, NULL);
return 1;
}
@@ -903,7 +881,8 @@ int handle_packet_missing_indirect(struc
status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ ap->ioctlfd, pkt->wait_queue_token, -status);
mount_mutex_unlock(NULL);
pending_cond_destroy(mt);
free_pending_args(mt);
diff -up autofs-5.0.3/daemon/state.c.device-node-control autofs-5.0.3/daemon/state.c
--- autofs-5.0.3/daemon/state.c.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/daemon/state.c 2008-02-25 09:03:12.000000000 +0900
@@ -93,6 +93,7 @@ void nextstate(int statefd, enum states
*/
void expire_cleanup(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
pthread_t thid = pthread_self();
struct expire_args *ec;
struct autofs_point *ap;
@@ -113,7 +114,8 @@ void expire_cleanup(void *arg)
/* Check to see if expire process finished */
if (thid == ap->exp_thread) {
- int rv, idle;
+ unsigned int idle;
+ int rv;
ap->exp_thread = 0;
@@ -135,7 +137,7 @@ void expire_cleanup(void *arg)
* allowing it to shutdown.
*/
if (ap->submount && !success) {
- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle);
+ rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
if (!rv && idle && ap->submount > 1) {
next = ST_SHUTDOWN_PENDING;
break;
@@ -160,7 +162,7 @@ void expire_cleanup(void *arg)
* shutdown return to ready state unless we have
* been signaled to shutdown.
*/
- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle);
+ rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
if (!idle && !ap->shutdown) {
next = ST_READY;
if (!ap->submount)
diff -up autofs-5.0.3/daemon/lookup.c.device-node-control autofs-5.0.3/daemon/lookup.c
--- autofs-5.0.3/daemon/lookup.c.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/daemon/lookup.c 2008-02-25 09:03:12.000000000 +0900
@@ -1148,7 +1148,8 @@ int lookup_source_close_ioctlfd(struct a
me = cache_lookup_distinct(mc, key);
if (me) {
if (me->ioctlfd != -1) {
- close(me->ioctlfd);
+ struct ioctl_ops *ops = get_ioctl_ops();
+ ops->close(ap->logopt, me->ioctlfd);
me->ioctlfd = -1;
}
cache_unlock(mc);
diff -up autofs-5.0.3/daemon/direct.c.device-node-control autofs-5.0.3/daemon/direct.c
--- autofs-5.0.3/daemon/direct.c.device-node-control 2008-02-25 08:58:46.000000000 +0900
+++ autofs-5.0.3/daemon/direct.c 2008-02-25 09:03:12.000000000 +0900
@@ -42,6 +42,9 @@
extern pthread_attr_t thread_attr;
+static const unsigned int direct = AUTOFS_TYPE_DIRECT;
+static const unsigned int offset = AUTOFS_TYPE_OFFSET;
+
struct mnt_params {
char *options;
};
@@ -88,6 +91,7 @@ static void mnts_cleanup(void *arg)
int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
char buf[MAX_ERR_BUF];
int ioctlfd, rv, left, retries;
@@ -106,23 +110,13 @@ int do_umount_autofs_direct(struct autof
return 1;
}
ioctlfd = me->ioctlfd;
- } else {
- int cl_flags;
-
- ioctlfd = open(me->key, O_RDONLY);
- if (ioctlfd != -1) {
- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
- }
- }
-
+ } else
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct);
if (ioctlfd >= 0) {
- int status = 1;
+ unsigned int status = 1;
- rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+ rv = ops->askumount(ap->logopt, ioctlfd, &status);
if (rv) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
error(ap->logopt, "ioctl failed: %s", estr);
@@ -135,19 +129,17 @@ int do_umount_autofs_direct(struct autof
return 1;
} else {
me->ioctlfd = -1;
- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
- close(ioctlfd);
+ ops->catatonic(ap->logopt, ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
goto force_umount;
}
}
me->ioctlfd = -1;
- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
- close(ioctlfd);
+ ops->catatonic(ap->logopt, ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
} else {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
error(ap->logopt,
"couldn't get ioctl fd for direct mount %s", me->key);
- debug(ap->logopt, "open: %s", estr);
return 1;
}
@@ -297,10 +289,11 @@ static int unlink_mount_tree(struct auto
int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct mnt_params *mp;
time_t timeout = ap->exp_timeout;
struct stat st;
- int status, ret, ioctlfd, cl_flags;
+ int status, ret, ioctlfd;
struct list_head list;
const char *map_name;
@@ -313,16 +306,8 @@ int do_mount_autofs_direct(struct autofs
save_ioctlfd = ioctlfd = me->ioctlfd;
- if (ioctlfd == -1) {
- ioctlfd = open(me->key, O_RDONLY);
- if (ioctlfd != -1) {
- cl_flags = fcntl(ioctlfd, F_GETFD, 0);
- if (cl_flags != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
- }
- }
+ if (ioctlfd == -1)
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct);
if (ioctlfd < 0) {
error(ap->logopt,
@@ -331,13 +316,14 @@ int do_mount_autofs_direct(struct autofs
return 0;
}
- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
+ ops->timeout(ap->logopt, ioctlfd, &tout);
if (save_ioctlfd == -1)
- close(ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
return 0;
}
+
if (!unlink_mount_tree(ap, &list)) {
debug(ap->logopt,
"already mounted as other than autofs "
@@ -402,22 +388,16 @@ int do_mount_autofs_direct(struct autofs
goto out_err;
}
- /* Root directory for ioctl()'s */
- ioctlfd = open(me->key, O_RDONLY);
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct);
if (ioctlfd < 0) {
crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
goto out_umount;
}
- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
-
/* Calculate the timeouts */
ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+ ops->timeout(ap->logopt, ioctlfd, &timeout);
if (ap->exp_timeout)
info(ap->logopt,
@@ -438,14 +418,14 @@ int do_mount_autofs_direct(struct autofs
}
cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
- close(ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
debug(ap->logopt, "mounted trigger %s", me->key);
return 0;
out_close:
- close(ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
out_umount:
/* TODO: maybe force umount (-l) */
umount(me->key);
@@ -537,8 +517,9 @@ int mount_autofs_direct(struct autofs_po
int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
char buf[MAX_ERR_BUF];
- int ioctlfd, cl_flags, rv = 1, retries;
+ int ioctlfd, rv = 1, retries;
if (me->ioctlfd != -1) {
if (is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) {
@@ -555,20 +536,13 @@ int umount_autofs_offset(struct autofs_p
me->key);
return 0;
}
-
- ioctlfd = open(me->key, O_RDONLY);
- if (ioctlfd != -1) {
- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
- }
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, offset);
}
if (ioctlfd >= 0) {
- int status = 1;
+ unsigned int status = 1;
- rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status);
+ rv = ops->askumount(ap->logopt, ioctlfd, &status);
if (rv) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
logerr("ioctl failed: %s", estr);
@@ -581,14 +555,14 @@ int umount_autofs_offset(struct autofs_p
return 1;
} else {
me->ioctlfd = -1;
- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
- close(ioctlfd);
+ ops->catatonic(ap->logopt, ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
goto force_umount;
}
}
me->ioctlfd = -1;
- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
- close(ioctlfd);
+ ops->catatonic(ap->logopt, ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
} else {
struct stat st;
char *estr;
@@ -653,11 +627,12 @@ force_umount:
int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
char buf[MAX_ERR_BUF];
struct mnt_params *mp;
time_t timeout = ap->exp_timeout;
struct stat st;
- int ioctlfd, cl_flags, status, ret;
+ int ioctlfd, status, ret;
const char *type, *map_name = NULL;
if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
@@ -760,19 +735,13 @@ int mount_autofs_offset(struct autofs_po
goto out_err;
}
- /* Root directory for ioctl()'s */
- ioctlfd = open(me->key, O_RDONLY);
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, offset);
if (ioctlfd < 0) {
crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
goto out_umount;
}
- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
-
- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout);
+ ops->timeout(ap->logopt, ioctlfd, &timeout);
ret = fstat(ioctlfd, &st);
if (ret == -1) {
@@ -783,14 +752,14 @@ int mount_autofs_offset(struct autofs_po
cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
- close(ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
debug(ap->logopt, "mounted trigger %s", me->key);
return 0;
out_close:
- close(ioctlfd);
+ ops->close(ap->logopt, ioctlfd);
out_umount:
umount(me->key);
out_err:
@@ -800,53 +769,9 @@ out_err:
return -1;
}
-static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
-{
- char buf[MAX_ERR_BUF];
- int ret, retries;
- struct stat st;
-
- if (fstat(ioctlfd, &st) == -1) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- debug(logopt, "fstat failed: %s", estr);
- return 0;
- }
-
- retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
-
- while (retries--) {
- struct timespec tm = {0, 100000000};
-
- /* Ggenerate expire message for the mount. */
- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
- if (ret == -1) {
- /* Mount has gone away */
- if (errno == EBADF || errno == EINVAL)
- return 1;
-
- /*
- * Other than EAGAIN is an expire error so continue.
- * Kernel try the same mount again, limited by
- * retries (ie. number of mounts directly under
- * mount point, should always be one for direct
- * mounts).
- */
- if (errno == EAGAIN)
- break;
- }
- nanosleep(&tm, NULL);
- }
-
- if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
- if (!ret)
- return 0;
- }
-
- return 1;
-}
-
void *expire_proc_direct(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct mnt_list *mnts = NULL, *next;
struct list_head list, *p;
struct expire_args *ea;
@@ -958,8 +883,8 @@ void *expire_proc_direct(void *arg)
ioctlfd = me->ioctlfd;
- ret = expire_direct(ioctlfd, next->path, now, ap->logopt);
- if (!ret) {
+ ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+ if (ret) {
left++;
pthread_setcancelstate(cur_state, NULL);
continue;
@@ -991,8 +916,8 @@ void *expire_proc_direct(void *arg)
debug(ap->logopt, "send expire to trigger %s", next->path);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
- ret = expire_direct(ioctlfd, next->path, now, ap->logopt);
- if (!ret)
+ ret = ops->expire(ap->logopt, ioctlfd, next->path, now);
+ if (ret)
left++;
pthread_setcancelstate(cur_state, NULL);
}
@@ -1023,8 +948,11 @@ static void pending_cond_destroy(void *a
static void expire_send_fail(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt = arg;
- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ struct autofs_point *ap = mt->ap;
+ ops->send_fail(ap->logopt,
+ mt->ioctlfd, mt->wait_queue_token, -ENOENT);
}
static void free_pending_args(void *arg)
@@ -1042,6 +970,7 @@ static void expire_mutex_unlock(void *ar
static void *do_expire_direct(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt;
struct autofs_point *ap;
size_t len;
@@ -1076,15 +1005,16 @@ static void *do_expire_direct(void *arg)
status = do_expire(ap, mt->name, len);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
if (status)
- send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ mt->ioctlfd, mt->wait_queue_token, -ENOENT);
else {
struct mapent *me;
cache_readlock(mt->mc);
me = cache_lookup_distinct(mt->mc, mt->name);
me->ioctlfd = -1;
cache_unlock(mt->mc);
- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
- close(mt->ioctlfd);
+ ops->send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ ops->close(ap->logopt, mt->ioctlfd);
}
pthread_setcancelstate(state, NULL);
@@ -1097,6 +1027,7 @@ static void *do_expire_direct(void *arg)
int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_direct_t *pkt)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct map_source *map;
struct mapent_cache *mc = NULL;
struct mapent *me = NULL;
@@ -1146,7 +1077,8 @@ int handle_packet_expire_direct(struct a
if (!mt) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
error(ap->logopt, "malloc: %s", estr);
- send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ me->ioctlfd, pkt->wait_queue_token, -ENOMEM);
cache_unlock(mc);
pthread_setcancelstate(state, NULL);
return 1;
@@ -1175,7 +1107,8 @@ int handle_packet_expire_direct(struct a
status = pthread_create(&thid, &thread_attr, do_expire_direct, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
- send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token);
+ ops->send_fail(ap->logopt,
+ mt->ioctlfd, pkt->wait_queue_token, -status);
cache_unlock(mc);
expire_mutex_unlock(NULL);
pending_cond_destroy(mt);
@@ -1203,9 +1136,11 @@ int handle_packet_expire_direct(struct a
static void mount_send_fail(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt = arg;
- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
- close(mt->ioctlfd);
+ struct autofs_point *ap = mt->ap;
+ ops->send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token, -ENOENT);
+ ops->close(ap->logopt, mt->ioctlfd);
}
static void mount_mutex_unlock(void *arg)
@@ -1217,6 +1152,7 @@ static void mount_mutex_unlock(void *arg
static void *do_mount_direct(void *arg)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct pending_args *mt;
struct autofs_point *ap;
struct passwd pw;
@@ -1409,15 +1345,19 @@ cont:
cache_unlock(mt->mc);
if (set_fd) {
me->ioctlfd = mt->ioctlfd;
- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+ ops->send_ready(ap->logopt,
+ mt->ioctlfd, mt->wait_queue_token);
} else {
- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
- close(mt->ioctlfd);
+ ops->send_ready(ap->logopt,
+ mt->ioctlfd, mt->wait_queue_token);
+ ops->close(ap->logopt, mt->ioctlfd);
}
info(ap->logopt, "mounted %s", mt->name);
} else {
- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token);
- close(mt->ioctlfd);
+ /* TODO: get mount return status from lookup_nss_mount */
+ ops->send_fail(ap->logopt,
+ mt->ioctlfd, mt->wait_queue_token, -ENOENT);
+ ops->close(ap->logopt, mt->ioctlfd);
info(ap->logopt, "failed to mount %s", mt->name);
}
pthread_setcancelstate(state, NULL);
@@ -1431,6 +1371,7 @@ cont:
int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
struct map_source *map;
struct mapent_cache *mc = NULL;
struct mapent *me = NULL;
@@ -1438,7 +1379,8 @@ int handle_packet_missing_direct(struct
struct pending_args *mt;
char buf[MAX_ERR_BUF];
int status = 0;
- int ioctlfd, cl_flags, state;
+ int ioctlfd, state;
+ unsigned int type;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
@@ -1475,12 +1417,16 @@ int handle_packet_missing_direct(struct
return 1;
}
+ type = direct;
+ if (me->multi != me && !list_empty(&me->multi_list))
+ type = offset;
+
if (me->ioctlfd != -1) {
/* Maybe someone did a manual umount, clean up ! */
ioctlfd = me->ioctlfd;
me->ioctlfd = -1;
} else
- ioctlfd = open(me->key, O_RDONLY);
+ ops->open(ap->logopt, &ioctlfd, -1, me->key, type);
if (ioctlfd == -1) {
cache_unlock(mc);
@@ -1490,11 +1436,6 @@ int handle_packet_missing_direct(struct
return 1;
}
- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) {
- cl_flags |= FD_CLOEXEC;
- fcntl(ioctlfd, F_SETFD, cl_flags);
- }
-
debug(ap->logopt, "token %ld, name %s, request pid %u",
(unsigned long) pkt->wait_queue_token, me->key, pkt->pid);
@@ -1502,8 +1443,9 @@ int handle_packet_missing_direct(struct
if (ap->shutdown ||
ap->state == ST_SHUTDOWN_FORCE ||
ap->state == ST_SHUTDOWN) {
- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
- close(ioctlfd);
+ ops->send_fail(ap->logopt,
+ ioctlfd, pkt->wait_queue_token, -ENOENT);
+ ops->close(ap->logopt, ioctlfd);
cache_unlock(mc);
pthread_setcancelstate(state, NULL);
return 1;
@@ -1513,8 +1455,9 @@ int handle_packet_missing_direct(struct
if (!mt) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
error(ap->logopt, "malloc: %s", estr);
- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
- close(ioctlfd);
+ ops->send_fail(ap->logopt,
+ ioctlfd, pkt->wait_queue_token, -ENOMEM);
+ ops->close(ap->logopt, ioctlfd);
cache_unlock(mc);
pthread_setcancelstate(state, NULL);
return 1;
@@ -1542,8 +1485,9 @@ int handle_packet_missing_direct(struct
status = pthread_create(&thid, &thread_attr, do_mount_direct, mt);
if (status) {
error(ap->logopt, "missing mount thread create failed");
- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
- close(ioctlfd);
+ ops->send_fail(ap->logopt,
+ ioctlfd, pkt->wait_queue_token, -status);
+ ops->close(ap->logopt, ioctlfd);
cache_unlock(mc);
mount_mutex_unlock(NULL);
pending_cond_destroy(mt);
diff -up autofs-5.0.3/daemon/automount.c.device-node-control autofs-5.0.3/daemon/automount.c
--- autofs-5.0.3/daemon/automount.c.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/daemon/automount.c 2008-02-25 09:03:12.000000000 +0900
@@ -579,40 +579,6 @@ int umount_autofs(struct autofs_point *a
return ret;
}
-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
-{
- char buf[MAX_ERR_BUF];
-
- if (wait_queue_token == 0)
- return 0;
-
- debug(logopt, "token = %d", wait_queue_token);
-
- if (ioctl(ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr("AUTOFS_IOC_READY: error %s", estr);
- return 1;
- }
- return 0;
-}
-
-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token)
-{
- char buf[MAX_ERR_BUF];
-
- if (wait_queue_token == 0)
- return 0;
-
- debug(logopt, "token = %d", wait_queue_token);
-
- if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
- logerr("AUTOFS_IOC_FAIL: error %s", estr);
- return 1;
- }
- return 0;
-}
-
static size_t get_kpkt_len(void)
{
size_t pkt_len = sizeof(struct autofs_v5_packet);
@@ -1540,7 +1506,9 @@ void *handle_mounts(void *arg)
while (ap->state != ST_SHUTDOWN) {
if (handle_packet(ap)) {
- int ret, result;
+ struct ioctl_ops *ops = get_ioctl_ops();
+ unsigned int result;
+ int ret;
state_mutex_lock(ap);
/*
@@ -1557,7 +1525,7 @@ void *handle_mounts(void *arg)
* If the ioctl fails assume the kernel doesn't have
* AUTOFS_IOC_ASKUMOUNT and just continue.
*/
- ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result);
+ ret = ops->askumount(ap->logopt, ap->ioctlfd, &result);
if (ret == -1) {
state_mutex_unlock(ap);
break;
@@ -2055,6 +2023,8 @@ int main(int argc, char *argv[])
exit(1);
}
+ init_ioctl_ctl();
+
if (!alarm_start_handler()) {
logerr("%s: failed to create alarm handler thread!", program);
master_kill(master_list);
@@ -2099,6 +2069,8 @@ int main(int argc, char *argv[])
if (dh)
dlclose(dh);
#endif
+ close_ioctl_ctl();
+
info(logging, "autofs stopped");
exit(0);
diff -up autofs-5.0.3/include/automount.h.device-node-control autofs-5.0.3/include/automount.h
--- autofs-5.0.3/include/automount.h.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/include/automount.h 2008-02-25 09:03:12.000000000 +0900
@@ -29,6 +29,7 @@
#include "log.h"
#include "rpc_subs.h"
#include "parse_subs.h"
+#include "dev-ioctl-lib.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
@@ -70,6 +71,10 @@ int load_autofs4_module(void);
#define SMB_SUPER_MAGIC 0x0000517BL
#define CIFS_MAGIC_NUMBER 0xFF534D42L
+#define AUTOFS_TYPE_INDIRECT 0x0001
+#define AUTOFS_TYPE_DIRECT 0x0002
+#define AUTOFS_TYPE_OFFSET 0x0004
+
/* This sould be enough for at least 20 host aliases */
#define HOST_ENT_BUF_SIZE 2048
@@ -367,7 +372,7 @@ void free_mnt_list(struct mnt_list *list
int contained_in_local_fs(const char *path);
int is_mounted(const char *table, const char *path, unsigned int type);
int has_fstab_option(const char *opt);
-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino);
+int find_mnt_devid(const char *table, const char *path, char *devid, unsigned int type);
char *get_offset(const char *prefix, char *offset,
struct list_head *head, struct list_head **pos);
void add_ordered_list(struct mnt_list *ent, struct list_head *head);
@@ -377,6 +382,7 @@ int tree_get_mnt_list(struct mnt_list *m
int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path);
int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type);
+int tree_find_mnt_devid(struct mnt_list *mnts, const char *path, char *devid, unsigned int type);
/* Core automount definitions */
@@ -470,8 +476,6 @@ struct autofs_point {
void *handle_mounts(void *arg);
int umount_multi(struct autofs_point *ap, const char *path, int incl);
-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
int do_expire(struct autofs_point *ap, const char *name, int namelen);
void *expire_proc_indirect(void *);
void *expire_proc_direct(void *);
diff -up /dev/null autofs-5.0.3/include/linux/auto_dev-ioctl.h
--- /dev/null 2008-02-25 17:16:11.149000952 +0900
+++ autofs-5.0.3/include/linux/auto_dev-ioctl.h 2008-02-25 09:03:44.000000000 +0900
@@ -0,0 +1,113 @@
+/*
+ * linux/include/linux/auto_dev-ioctl.h
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#ifndef _LINUX_AUTO_DEV_IOCTL_H
+#define _LINUX_AUTO_DEV_IOCTL_H
+
+#include <linux/types.h>
+
+#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1
+#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0
+
+#define AUTOFS_DEVID_LEN 16
+
+/*
+ * An ioctl interface for autofs mount point control.
+ */
+
+/*
+ * All theioctls use this structure.
+ * When sending a path size must account for the total length
+ * of the chunk of memory.
+ */
+
+struct autofs_dev_ioctl {
+ __u32 ver_major;
+ __u32 ver_minor;
+ __u32 size; /* total size of data passed in
+ * including this struct */
+ __s32 ioctlfd; /* automount command fd */
+
+ __u32 arg1; /* Command parameters */
+ __u32 arg2;
+
+ char path[0];
+};
+
+static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+{
+ in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+ in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+ in->size = sizeof(struct autofs_dev_ioctl);
+ in->ioctlfd = -1;
+ in->arg1 = 0;
+ in->arg2 = 0;
+ return;
+}
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to autofs-dev-ioctl.c:lookup_ioctl()
+ */
+enum {
+ /* Get various version info */
+ AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
+ AUTOFS_DEV_IOCTL_PROTOVER_CMD,
+ AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
+
+ /* Set mount we're acting on */
+ AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
+
+ /* Close mount ioctl fd */
+ AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
+
+ /* Mount/expire status returns */
+ AUTOFS_DEV_IOCTL_READY_CMD,
+ AUTOFS_DEV_IOCTL_FAIL_CMD,
+
+ /* Automount active/inactive */
+ AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
+ AUTOFS_DEV_IOCTL_CATATONIC_CMD,
+
+ /* Expiry timeout */
+ AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
+
+ /* Get mount last requesting uid and gid */
+ AUTOFS_DEV_IOCTL_REQUESTOR_CMD,
+
+ /* Check for eligible expire candidates */
+ AUTOFS_DEV_IOCTL_EXPIRE_CMD,
+
+ /* Request busy status */
+ AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
+
+ /* Check if path is a mountpoint */
+ AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
+};
+
+#define AUTOFS_IOCTL 0x93
+
+#define AUTOFS_DEV_IOCTL_VERSION _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_PROTOVER _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_PROTOSUBVER _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_OPENMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_CLOSEMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_READY _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_FAIL _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_SETPIPEFD _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_CATATONIC _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_TIMEOUT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_REQUESTOR _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_REQUESTOR_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_EXPIRE _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_ASKUMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
+#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
+
+#endif /* _LINUX_AUTO_DEV_IOCTL_H */
diff -up /dev/null autofs-5.0.3/include/mounts.h
--- /dev/null 2008-02-25 17:16:11.149000952 +0900
+++ autofs-5.0.3/include/mounts.h 2008-02-25 09:03:44.000000000 +0900
@@ -0,0 +1,96 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * mounts.h - header file for mount utilities module.
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2004-2006 Ian Kent <raven@themaw.net> - All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef MOUNTS_H
+#define MOUNTS_H
+
+#define AUTOFS_TYPE_INDIRECT 0x0001
+#define AUTOFS_TYPE_DIRECT 0x0002
+#define AUTOFS_TYPE_OFFSET 0x0004
+
+#define MNTS_ALL 0x0001
+#define MNTS_REAL 0x0002
+#define MNTS_AUTOFS 0x0004
+
+#define REMOUNT_SUCCESS 0x0000
+#define REMOUNT_OPEN_FAIL 0x0001
+#define REMOUNT_STAT_FAIL 0x0002
+#define REMOUNT_READ_MAP 0x0004
+
+extern const unsigned int indirect;
+extern const unsigned int direct;
+extern const unsigned int offset;
+
+struct mapent;
+
+struct mnt_list {
+ char *path;
+ char *fs_name;
+ char *fs_type;
+ char *opts;
+ pid_t owner;
+ /*
+ * List operations ie. get_mnt_list.
+ */
+ struct mnt_list *next;
+ /*
+ * Tree operations ie. tree_make_tree,
+ * tree_get_mnt_list etc.
+ */
+ struct mnt_list *left;
+ struct mnt_list *right;
+ struct list_head self;
+ struct list_head list;
+ struct list_head entries;
+ struct list_head sublist;
+ /*
+ * Offset mount handling ie. add_ordered_list
+ * and get_offset.
+ */
+ struct list_head ordered;
+};
+
+unsigned int query_kproto_ver(void);
+unsigned int get_kver_major(void);
+unsigned int get_kver_minor(void);
+char *make_options_string(char *path, int kernel_pipefd, char *extra);
+char *make_mnt_name_string(char *path);
+struct mnt_list *get_mnt_list(const char *table, const char *path, int include);
+struct mnt_list *reverse_mnt_list(struct mnt_list *list);
+void free_mnt_list(struct mnt_list *list);
+int contained_in_local_fs(const char *path);
+int is_mounted(const char *table, const char *path, unsigned int type);
+int has_fstab_option(const char *opt);
+int find_mnt_devid(const char *table, const char *path, char *devid, const unsigned int type);
+char *get_offset(const char *prefix, char *offset,
+ struct list_head *head, struct list_head **pos);
+void add_ordered_list(struct mnt_list *ent, struct list_head *head);
+void tree_free_mnt_tree(struct mnt_list *tree);
+struct mnt_list *tree_make_mnt_tree(const char *table, const char *path);
+int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
+int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
+int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path);
+int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type);
+int tree_find_mnt_devid(struct mnt_list *mnts, const char *path, char *devid, const unsigned int type);
+void set_tsd_user_vars(unsigned int, uid_t, gid_t);
+const char *mount_type_str(unsigned int);
+void notify_mount_result(struct autofs_point *, const char *, const char *);
+int remount_active_mount(struct autofs_point *, struct mapent_cache *,
+ const char *, dev_t devid, const unsigned int, int *);
+int umount_ent(struct autofs_point *, const char *);
+int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
+int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
+
+#endif
diff -up /dev/null autofs-5.0.3/include/dev-ioctl-lib.h
--- /dev/null 2008-02-25 17:16:11.149000952 +0900
+++ autofs-5.0.3/include/dev-ioctl-lib.h 2008-02-25 09:03:44.000000000 +0900
@@ -0,0 +1,62 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * dev-ioctl-lib.h - autofs device control.
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef AUTOFS_DEV_IOCTL_LIB_H
+#define AUTOFS_DEV_IOCTL_LIB_H
+
+#include <sys/types.h>
+#include "linux/auto_dev-ioctl.h"
+
+#define CONTROL_DEVICE "/dev/autofs"
+
+#define DEV_IOCTL_IS_MOUNTED 0x0001
+#define DEV_IOCTL_IS_AUTOFS 0x0002
+#define DEV_IOCTL_IS_OTHER 0x0004
+
+struct ioctl_ctl {
+ int devfd;
+ struct ioctl_ops *ops;
+};
+
+struct ioctl_ops {
+ int (*version)(unsigned int, int, struct autofs_dev_ioctl *);
+ int (*protover)(unsigned int, int, unsigned int *);
+ int (*protosubver)(unsigned int, int, unsigned int *);
+ int (*open)(unsigned int, int *, dev_t, const char *, unsigned int);
+ int (*close)(unsigned int, int);
+ int (*send_ready)(unsigned int, int, unsigned int);
+ int (*send_fail)(unsigned int, int, unsigned int, int);
+ int (*setpipefd)(unsigned int, int, int);
+ int (*catatonic)(unsigned int, int);
+ int (*timeout)(unsigned int, int, time_t *);
+ int (*requestor)(unsigned int, int, const char *, uid_t *, gid_t *);
+ int (*expire)(unsigned int, int, const char *, unsigned int);
+ int (*askumount)(unsigned int, int, unsigned int *);
+ int (*ismountpoint)(unsigned int, int, const char *, unsigned int *);
+};
+
+void init_ioctl_ctl(void);
+void close_ioctl_ctl(void);
+struct ioctl_ops *get_ioctl_ops(void);
+struct autofs_dev_ioctl *alloc_ioctl_ctl_open(const char *, unsigned int);
+void free_ioctl_ctl_open(struct autofs_dev_ioctl *);
+
+#endif
+
diff -up autofs-5.0.3/CHANGELOG.device-node-control autofs-5.0.3/CHANGELOG
--- autofs-5.0.3/CHANGELOG.device-node-control 2008-02-25 08:58:46.000000000 +0900
+++ autofs-5.0.3/CHANGELOG 2008-02-25 09:07:32.000000000 +0900
@@ -8,6 +8,7 @@
- another fix for don't fail on empty master map.
- fix expire working harder than needed.
- fix unlink of mount tree incorrectly causing autofs mount fail.
+- add miscellaneous device node interface library.
14/01/2008 autofs-5.0.3
-----------------------
diff -up autofs-5.0.3/redhat/autofs.init.in.device-node-control autofs-5.0.3/redhat/autofs.init.in
--- autofs-5.0.3/redhat/autofs.init.in.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/redhat/autofs.init.in 2008-02-25 09:03:12.000000000 +0900
@@ -13,6 +13,7 @@
DAEMON=@@sbindir@@/automount
prog=`basename $DAEMON`
MODULE="autofs4"
+DEVICE="autofs"
initdir=@@initdir@@
confdir=@@autofsconfdir@@
@@ -56,6 +57,15 @@ function start() {
echo
return $RETVAL
fi
+
+ # Check misc device
+ if [ -e "/proc/misc" ]; then
+ MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc`
+ if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then
+ mknod -m 0600 /dev/$DEVICE c 10 $MINOR
+ fi
+ fi
+
echo -n $"Starting $prog: "
$prog $OPTIONS
RETVAL=$?
diff -up autofs-5.0.3/lib/master_parse.y.device-node-control autofs-5.0.3/lib/master_parse.y
--- autofs-5.0.3/lib/master_parse.y.device-node-control 2008-02-25 08:58:46.000000000 +0900
+++ autofs-5.0.3/lib/master_parse.y 2008-02-25 09:03:12.000000000 +0900
@@ -796,6 +796,7 @@ int master_parse_entry(const char *buffe
return 0;
}
} else {
+ struct ioctl_ops *ops = get_ioctl_ops();
struct autofs_point *ap = entry->ap;
time_t tout = timeout;
@@ -807,7 +808,7 @@ int master_parse_entry(const char *buffe
ap->exp_timeout = timeout;
ap->exp_runfreq = (ap->exp_timeout + CHECK_RATIO - 1) / CHECK_RATIO;
if (ap->ioctlfd != -1 && ap->type == LKP_INDIRECT)
- ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout);
+ ops->timeout(ap->logopt, ap->ioctlfd, &tout);
}
}
entry->ap->random_selection = random_selection;
diff -up autofs-5.0.3/lib/mounts.c.device-node-control autofs-5.0.3/lib/mounts.c
--- autofs-5.0.3/lib/mounts.c.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/lib/mounts.c 2008-02-25 09:03:12.000000000 +0900
@@ -38,6 +38,7 @@ static const char kver_options_template[
unsigned int query_kproto_ver(void)
{
+ struct ioctl_ops *ops = get_ioctl_ops();
char dir[] = "/tmp/autoXXXXXX", *t_dir;
char options[MAX_OPTIONS_LEN + 1];
pid_t pgrp = getpgrp();
@@ -70,7 +71,7 @@ unsigned int query_kproto_ver(void)
close(pipefd[1]);
- ioctlfd = open(t_dir, O_RDONLY);
+ ops->open(LOGOPT_NONE, &ioctlfd, -1, t_dir, AUTOFS_TYPE_INDIRECT);
if (ioctlfd == -1) {
umount(t_dir);
close(pipefd[0]);
@@ -78,11 +79,11 @@ unsigned int query_kproto_ver(void)
return 0;
}
- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+ ops->catatonic(LOGOPT_NONE, ioctlfd);
/* If this ioctl() doesn't work, it is kernel version 2 */
- if (ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, &kver.major) == -1) {
- close(ioctlfd);
+ if (ops->protover(LOGOPT_NONE, ioctlfd, &kver.major)) {
+ ops->close(LOGOPT_NONE, ioctlfd);
umount(t_dir);
close(pipefd[0]);
rmdir(t_dir);
@@ -90,15 +91,15 @@ unsigned int query_kproto_ver(void)
}
/* If this ioctl() doesn't work, version is 4 or less */
- if (ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, &kver.minor) == -1) {
- close(ioctlfd);
+ if (ops->protosubver(LOGOPT_NONE, ioctlfd, &kver.minor)) {
+ ops->close(LOGOPT_NONE, ioctlfd);
umount(t_dir);
close(pipefd[0]);
rmdir(t_dir);
return 0;
}
- close(ioctlfd);
+ ops->close(LOGOPT_NONE, ioctlfd);
umount(t_dir);
close(pipefd[0]);
rmdir(t_dir);
@@ -456,49 +457,75 @@ int has_fstab_option(const char *opt)
return ret;
}
-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino)
+/*
+ * Find the device number of an autofs mount with given path and
+ * type (eg..AUTOFS_TYPE_DIRECT). An autofs display mount option
+ * "dev=<device number>" is provided by the kernel module for this.
+ *
+ * The device number is used by the kernel to identify the autofs
+ * super block when searching for the mount.
+ */
+int find_mnt_devid(const char *table,
+ const char *path, char *devid, unsigned int type)
{
- struct mntent mnt_wrk;
struct mntent *mnt;
+ struct mntent mnt_wrk;
char buf[PATH_MAX * 3];
- char *path = NULL;
- unsigned long l_dev = (unsigned long) dev;
- unsigned long l_ino = (unsigned long) ino;
FILE *tab;
+ char *dev;
tab = setmntent(table, "r");
if (!tab) {
- char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1);
- logerr("setmntent: %s", estr);
+ printf("failed to open mount table\n");
return 0;
}
+ dev = NULL;
while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
- char *p_dev, *p_ino;
- unsigned long m_dev, m_ino;
-
if (strcmp(mnt->mnt_type, "autofs"))
continue;
- p_dev = strstr(mnt->mnt_opts, "dev=");
- if (!p_dev)
- continue;
- sscanf(p_dev, "dev=%lu", &m_dev);
- if (m_dev != l_dev)
+ if (strcmp(mnt->mnt_dir, path))
continue;
- p_ino = strstr(mnt->mnt_opts, "ino=");
- if (!p_ino)
- continue;
- sscanf(p_ino, "ino=%lu", &m_ino);
- if (m_ino == l_ino) {
- path = strdup(mnt->mnt_dir);
+ switch (type) {
+ case AUTOFS_TYPE_INDIRECT:
+ if (!hasmntopt(mnt, "indirect"))
+ continue;
+ break;
+
+ case AUTOFS_TYPE_DIRECT:
+ if (!hasmntopt(mnt, "direct"))
+ continue;
+ break;
+
+ case AUTOFS_TYPE_OFFSET:
+ if (!hasmntopt(mnt, "offset"))
+ continue;
+ break;
+ }
+
+ dev = hasmntopt(mnt, "dev");
+ if (dev) {
+ char *start = strchr(dev, '=') + 1;
+ char *end = strchr(start, ',');
+ if (end)
+ *end = '\0';
+ if (start) {
+ int len = strlen(start);
+ memcpy(devid, start, len);
+ devid[len] = '\0';
+ }
break;
}
}
+
endmntent(tab);
- return path;
+ if (!dev)
+ return 0;
+
+ return 1;
}
char *get_offset(const char *prefix, char *offset,
@@ -976,3 +1003,70 @@ int tree_is_mounted(struct mnt_list *mnt
return mounted;
}
+int tree_find_mnt_devid(struct mnt_list *mnts,
+ const char *path, char *devid, unsigned int type)
+{
+ struct list_head *p;
+ struct list_head list;
+ size_t len = strlen(path);
+ char *dev;
+
+ INIT_LIST_HEAD(&list);
+
+ if (!tree_find_mnt_ents(mnts, &list, path))
+ return 0;
+
+ dev = NULL;
+ list_for_each(p, &list) {
+ struct mnt_list *mptr;
+
+ mptr = list_entry(p, struct mnt_list, entries);
+
+ if (strcmp(mptr->fs_type, "autofs"))
+ continue;
+
+ if (strlen(mptr->path) < len)
+ return 0;
+
+ if (strcmp(mptr->path, path))
+ continue;
+
+ switch (type) {
+ case AUTOFS_TYPE_INDIRECT:
+ if (!strstr(mptr->opts, "indirect"))
+ continue;
+ break;
+
+ case AUTOFS_TYPE_DIRECT:
+ if (!strstr(mptr->opts, "direct"))
+ continue;
+ break;
+
+ case AUTOFS_TYPE_OFFSET:
+ if (!strstr(mptr->opts, "offset"))
+ continue;
+ break;
+ }
+
+ dev = strstr(mptr->opts, "dev");
+ if (dev) {
+ char *start = strchr(dev, '=') + 1;
+ char *end = strchr(start, ',');
+ if (end)
+ *end = '\0';
+ if (start) {
+ int len = strlen(start);
+ memcpy(devid, start, len);
+ devid[len] = '\0';
+ }
+ *end = ',';
+ break;
+ }
+ }
+
+ if (!dev)
+ return 0;
+
+ return 1;
+}
+
diff -up autofs-5.0.3/lib/Makefile.device-node-control autofs-5.0.3/lib/Makefile
--- autofs-5.0.3/lib/Makefile.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/lib/Makefile 2008-02-25 09:03:12.000000000 +0900
@@ -7,12 +7,13 @@ include ../Makefile.rules
SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \
master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \
- args.c alarm.c macros.c master.c defaults.c parse_subs.c
+ args.c alarm.c macros.c master.c defaults.c parse_subs.c \
+ dev-ioctl-lib.c
RPCS = mount.h mount_clnt.c mount_xdr.c
OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \
mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \
nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \
- defaults.o parse_subs.o
+ defaults.o parse_subs.o dev-ioctl-lib.o
YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \
master_tok.c master_parse.tab.c master_parse.tab.h
diff -up /dev/null autofs-5.0.3/lib/dev-ioctl-lib.c
--- /dev/null 2008-02-25 17:16:11.149000952 +0900
+++ autofs-5.0.3/lib/dev-ioctl-lib.c 2008-02-25 09:03:44.000000000 +0900
@@ -0,0 +1,747 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * ctl-dev-lib.c - module for Linux automount mount table lookup functions
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net> - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <errno.h>
+#include <sys/vfs.h>
+
+#include "automount.h"
+
+/* ioctld control function interface */
+static struct ioctl_ctl ctl = { -1, NULL };
+
+#ifndef AUTOFS_SUPER_MAGIC
+#define AUTOFS_SUPER_MAGIC 0x0187
+#endif
+
+/*
+ * Define functions for autofs ioctl control.
+ *
+ * We provide two interfaces. One which routes ioctls via a
+ * miscelaneous device node and can be used to obtain an ioctl
+ * file descriptor for autofs mounts that are covered by an
+ * active mount (eg. active direct or multi-mount offsets).
+ * The other provides the traditional autofs ioctl implementation.
+ *
+ * The miscielaneous device control functions are prefixed with
+ * dev_ctl_ and the traditional ones are prefixed with ioctl_.
+ */
+static int dev_ioctl_version(unsigned int, int, struct autofs_dev_ioctl *);
+static int dev_ioctl_protover(unsigned int, int, unsigned int *);
+static int dev_ioctl_protosubver(unsigned int, int, unsigned int *);
+static int dev_ioctl_open(unsigned int, int *, dev_t, const char *, unsigned int);
+static int dev_ioctl_close(unsigned int, int);
+static int dev_ioctl_send_ready(unsigned int, int, unsigned int);
+static int dev_ioctl_send_fail(unsigned int, int, unsigned int, int);
+static int dev_ioctl_setpipefd(unsigned int, int, int);
+static int dev_ioctl_catatonic(unsigned int, int);
+static int dev_ioctl_timeout(unsigned int, int, time_t *);
+static int dev_ioctl_requestor(unsigned int, int, const char *, uid_t *, gid_t *);
+static int dev_ioctl_expire(unsigned int, int, const char *, unsigned int);
+static int dev_ioctl_askumount(unsigned int, int, unsigned int *);
+static int dev_ioctl_ismountpoint(unsigned int, int, const char *, unsigned int *);
+
+static int ioctl_protover(unsigned int, int, unsigned int *);
+static int ioctl_protosubver(unsigned int, int, unsigned int *);
+static int ioctl_open(unsigned int, int *, dev_t, const char *, unsigned int);
+static int ioctl_close(unsigned int, int);
+static int ioctl_send_ready(unsigned int, int, unsigned int);
+static int ioctl_send_fail(unsigned int, int, unsigned int, int);
+static int ioctl_catatonic(unsigned int, int);
+static int ioctl_timeout(unsigned int, int, time_t *);
+static int ioctl_expire(unsigned int, int, const char *, unsigned int);
+static int ioctl_askumount(unsigned int, int, unsigned int *);
+
+static struct ioctl_ops dev_ioctl_ops = {
+ .version = dev_ioctl_version,
+ .protover = dev_ioctl_protover,
+ .protosubver = dev_ioctl_protosubver,
+ .open = dev_ioctl_open,
+ .close = dev_ioctl_close,
+ .send_ready = dev_ioctl_send_ready,
+ .send_fail = dev_ioctl_send_fail,
+ .setpipefd = dev_ioctl_setpipefd,
+ .catatonic = dev_ioctl_catatonic,
+ .timeout = dev_ioctl_timeout,
+ .requestor = dev_ioctl_requestor,
+ .expire = dev_ioctl_expire,
+ .askumount = dev_ioctl_askumount,
+ .ismountpoint = dev_ioctl_ismountpoint
+};
+
+static struct ioctl_ops ioctl_ops = {
+ .version = NULL,
+ .protover = ioctl_protover,
+ .protosubver = ioctl_protosubver,
+ .open = ioctl_open,
+ .close = ioctl_close,
+ .send_ready = ioctl_send_ready,
+ .send_fail = ioctl_send_fail,
+ .setpipefd = NULL,
+ .catatonic = ioctl_catatonic,
+ .timeout = ioctl_timeout,
+ .requestor = NULL,
+ .expire = ioctl_expire,
+ .askumount = ioctl_askumount,
+ .ismountpoint = NULL
+};
+
+/*
+ * Allocate the control struct that holds the misc device file
+ * descriptor and operation despatcher table.
+ */
+void init_ioctl_ctl(void)
+{
+ int devfd;
+
+ if (ctl.ops)
+ return;
+
+ devfd = open(CONTROL_DEVICE, O_RDONLY);
+ if (devfd == -1)
+ ctl.ops = &ioctl_ops;
+ else {
+ int cl_flags = fcntl(devfd, F_GETFD, 0);
+ if (cl_flags != -1) {
+ cl_flags |= FD_CLOEXEC;
+ fcntl(devfd, F_SETFD, cl_flags);
+ }
+ ctl.devfd = devfd;
+ ctl.ops = &dev_ioctl_ops;
+ }
+ return;
+}
+
+void close_ioctl_ctl(void)
+{
+ if (ctl.devfd != -1) {
+ close(ctl.devfd);
+ ctl.devfd = -1;
+ }
+ ctl.ops = NULL;
+ return;
+}
+
+/* Return a pointer to the operations control struct */
+struct ioctl_ops *get_ioctl_ops(void)
+{
+ if (!ctl.ops)
+ init_ioctl_ctl();
+ return ctl.ops;
+}
+
+/* Get kenrel version of misc device code */
+static int dev_ioctl_version(unsigned int logopt,
+ int ioctlfd, struct autofs_dev_ioctl *param)
+{
+ param->ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_VERSION, param) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* Get major version of autofs kernel module mount protocol */
+static int dev_ioctl_protover(unsigned int logopt,
+ int ioctlfd, unsigned int *major)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOVER, ¶m) == -1)
+ return -1;
+
+ *major = param.arg1;
+
+ return 0;
+}
+
+static int ioctl_protover(unsigned int logopt,
+ int ioctlfd, unsigned int *major)
+{
+ return ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, major);
+}
+
+/* Get minor version of autofs kernel module mount protocol */
+static int dev_ioctl_protosubver(unsigned int logopt,
+ int ioctlfd, unsigned int *minor)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOSUBVER, ¶m) == -1)
+ return -1;
+
+ *minor = param.arg1;
+
+ return 0;
+}
+
+static int ioctl_protosubver(unsigned int logopt,
+ int ioctlfd, unsigned int *minor)
+{
+ return ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, minor);
+}
+
+/*
+ * Allocate a parameter struct for misc device ioctl used when
+ * opening an autofs mount point. Attach the path to the end
+ * of the struct. and lookup the device number if not given.
+ * Locating the device number relies on the mount option
+ * "dev=<device number>" being present in the autofs fs mount
+ * options.
+ */
+static struct autofs_dev_ioctl *alloc_dev_ioctl_open(const char *path, dev_t devid, unsigned int type)
+{
+ struct autofs_dev_ioctl *ioctl;
+ size_t size, p_len;
+ dev_t devno = devid;
+
+ if (!path)
+ return NULL;
+
+ if (devno == -1) {
+ char device[AUTOFS_DEVID_LEN];
+
+ if (!find_mnt_devid(_PROC_MOUNTS, path, device, type)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ devno = strtoul(device, NULL, 0);
+ }
+
+ p_len = strlen(path);
+ size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
+ ioctl = malloc(size);
+ if (!ioctl) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ init_autofs_dev_ioctl(ioctl);
+ ioctl->size = size;
+ memcpy(ioctl->path, path, p_len);
+ ioctl->path[p_len] = '\0';
+ ioctl->arg1 = devno;
+
+ return ioctl;
+}
+
+static void free_dev_ioctl_open(struct autofs_dev_ioctl *ioctl)
+{
+ free(ioctl);
+ return;
+}
+
+/*
+ * Allocate a parameter struct for misc device ioctl which includes
+ * a path. This is used when getting the last mount requestor uid
+ * and gid and when checking if a path within the autofs filesystem
+ * is a mount point. We add the path to the end of the struct.
+ */
+static struct autofs_dev_ioctl *alloc_dev_ioctl_path(int ioctlfd, const char *path)
+{
+ struct autofs_dev_ioctl *ioctl;
+ size_t size, p_len;
+
+ if (!path)
+ return NULL;
+
+ p_len = strlen(path);
+ size = sizeof(struct autofs_dev_ioctl) + p_len + 1;
+ ioctl = malloc(size);
+ if (!ioctl) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ init_autofs_dev_ioctl(ioctl);
+ ioctl->ioctlfd = ioctlfd;
+ ioctl->size = size;
+ memcpy(ioctl->path, path, p_len);
+ ioctl->path[p_len] = '\0';
+
+ return ioctl;
+}
+
+static void free_dev_ioctl_path(struct autofs_dev_ioctl *ioctl)
+{
+ free(ioctl);
+ return;
+}
+
+/* Get a file descriptor for control operations */
+static int dev_ioctl_open(unsigned int logopt, int *ioctlfd,
+ dev_t devid, const char *path, unsigned int type)
+{
+ struct autofs_dev_ioctl *param;
+
+ *ioctlfd = -1;
+
+ param = alloc_dev_ioctl_open(path, devid, type);
+ if (!param)
+ return -1;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) == -1) {
+ int save_errno = errno;
+ free_dev_ioctl_open(param);
+ errno = save_errno;
+ return -1;
+ }
+
+ *ioctlfd = param->ioctlfd;
+
+ free_dev_ioctl_open(param);
+
+ return 0;
+}
+
+static int ioctl_open(unsigned int logopt, int *ioctlfd,
+ dev_t devid, const char *path, unsigned int type)
+{
+ struct statfs sfs;
+ int save_errno, fd, cl_flags;
+
+ *ioctlfd = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ cl_flags = fcntl(fd, F_GETFD, 0);
+ if (cl_flags != -1) {
+ cl_flags |= FD_CLOEXEC;
+ fcntl(fd, F_SETFD, cl_flags);
+ }
+
+ if (fstatfs(fd, &sfs) == -1) {
+ save_errno = errno;
+ goto err;
+ }
+
+ if (sfs.f_type != AUTOFS_SUPER_MAGIC) {
+ save_errno = ENOENT;
+ goto err;
+ }
+
+ *ioctlfd = fd;
+
+ return 0;
+err:
+ close(fd);
+ errno = save_errno;
+ return -1;
+}
+
+/* Close */
+static int dev_ioctl_close(unsigned int logopt, int ioctlfd)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CLOSEMOUNT, ¶m) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int ioctl_close(unsigned int logopt, int ioctlfd)
+{
+ return close(ioctlfd);
+}
+
+/* Send ready status for given token */
+static int dev_ioctl_send_ready(unsigned int logopt,
+ int ioctlfd, unsigned int token)
+{
+ struct autofs_dev_ioctl param;
+
+ if (token == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ debug(logopt, "token = %d", token);
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+ param.arg1 = token;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_READY, ¶m) == -1) {
+ char *estr, buf[MAX_ERR_BUF];
+ int save_errno = errno;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr("AUTOFS_DEV_IOCTL_READY: error %s", estr);
+ errno = save_errno;
+ return -1;
+ }
+ return 0;
+}
+
+static int ioctl_send_ready(unsigned int logopt,
+ int ioctlfd, unsigned int token)
+{
+ if (token == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ debug(logopt, "token = %d", token);
+
+ if (ioctl(ioctlfd, AUTOFS_IOC_READY, token) == -1) {
+ char *estr, buf[MAX_ERR_BUF];
+ int save_errno = errno;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr("AUTOFS_IOC_READY: error %s", estr);
+ errno = save_errno;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Send ready status for given token.
+ *
+ * The device node ioctl implementation allows for sending a status
+ * of other than ENOENT, unlike the tradional interface.
+ */
+static int dev_ioctl_send_fail(unsigned int logopt,
+ int ioctlfd, unsigned int token, int status)
+{
+ struct autofs_dev_ioctl param;
+
+ if (token == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ debug(logopt, "token = %d", token);
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+ param.arg1 = token;
+ param.arg2 = status;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_FAIL, ¶m) == -1) {
+ char *estr, buf[MAX_ERR_BUF];
+ int save_errno = errno;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr("AUTOFS_DEV_IOCTL_FAIL: error %s", estr);
+ errno = save_errno;
+ return -1;
+ }
+ return 0;
+}
+
+static int ioctl_send_fail(unsigned int logopt,
+ int ioctlfd, unsigned int token, int status)
+{
+ if (token == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ debug(logopt, "token = %d", token);
+
+ if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, token) == -1) {
+ char *estr, buf[MAX_ERR_BUF];
+ int save_errno = errno;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr("AUTOFS_IOC_FAIL: error %s", estr);
+ errno = save_errno;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Set the pipe fd for kernel communication.
+ *
+ * Normally this is set at mount using an option but if we
+ * are reconnecting to a busy mount then we need to use this
+ * to tell the autofs kernel module about the new pipe fd. In
+ * order to protect mounts against incorrectly setting the
+ * pipefd we also require that the autofs mount be catatonic.
+ *
+ * If successful this also sets the process group id used to
+ * identify the controlling process to the process group of
+ * the caller.
+ */
+static int dev_ioctl_setpipefd(unsigned int logopt, int ioctlfd, int pipefd)
+{
+ struct autofs_dev_ioctl param;
+
+ if (pipefd == -1) {
+ errno = EBADF;
+ return -1;
+ }
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+ param.arg1 = pipefd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_SETPIPEFD, ¶m) == -1)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Make the autofs mount point catatonic, no longer responsive to
+ * mount requests. Also closes the kernel pipe file descriptor.
+ */
+static int dev_ioctl_catatonic(unsigned int logopt, int ioctlfd)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CATATONIC, ¶m) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int ioctl_catatonic(unsigned int logopt, int ioctlfd)
+{
+ return ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+}
+
+/* Set the autofs mount timeout */
+static int dev_ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+ param.arg1 = *timeout;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) == -1)
+ return -1;
+
+ *timeout = param.arg1;
+
+ return 0;
+}
+
+static int ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout)
+{
+ return ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, timeout);
+}
+
+/*
+ * Get the uid and gid of the last request for the mountpoint, path.
+ *
+ * When reconstructing an autofs mount tree with active mounts
+ * we need to re-connect to mounts that may have used the original
+ * process uid and gid (or string variations of them) for mount
+ * lookups within the map entry.
+ */
+static int dev_ioctl_requestor(unsigned int logopt,
+ int ioctlfd, const char *path,
+ uid_t *uid, gid_t *gid)
+{
+ struct autofs_dev_ioctl *param;
+ int err;
+
+ if (!path)
+ errno = EINVAL;
+
+ *uid = -1;
+ *gid = -1;
+
+
+ param = alloc_dev_ioctl_path(ioctlfd, path);
+ if (!param)
+ return -1;
+
+ err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_REQUESTOR, param);
+ if (err == -1) {
+ int save_errno = errno;
+ free_dev_ioctl_open(param);
+ errno = save_errno;
+ return -1;
+ }
+
+ *uid = param->arg1;
+ *gid = param->arg2;
+
+ free_dev_ioctl_path(param);
+
+ return 0;
+}
+
+/*
+ * Call repeatedly until it returns EAGAIN, meaning there's nothing
+ * more that can be done.
+ */
+static int expire(unsigned int logopt, int cmd, int fd,
+ int ioctlfd, const char *path, void *arg)
+{
+ char buf[MAX_ERR_BUF];
+ struct stat st;
+ unsigned int retries;
+ unsigned int ret;
+
+ if (fstat(ioctlfd, &st) == -1) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ debug(logopt, "fstat failed: %s", estr);
+ return 0;
+ }
+
+ retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+
+ ret = ioctl(fd, cmd, arg);
+ if (ret == -1) {
+ /* Mount has gone away */
+ if (errno == EBADF || errno == EINVAL)
+ return 0;
+
+ /*
+ * Other than EAGAIN is an expire error so continue.
+ * Kernel will try the next mount for indirect
+ * mounts. For direct mounts it will just try the
+ * same mount again, limited by retries (ie. number
+ * of mounts directly under mount point, should
+ * always be one for direct mounts).
+ */
+ if (errno == EAGAIN)
+ break;
+ }
+ nanosleep(&tm, NULL);
+ }
+
+ if (ctl.ops->askumount(logopt, ioctlfd, &ret))
+ return -1;
+
+ if (!ret)
+ return -1;
+
+ return 0;
+}
+
+static int dev_ioctl_expire(unsigned int logopt,
+ int ioctlfd, const char *path, unsigned int when)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+ param.arg1 = when;
+
+ return expire(logopt, AUTOFS_DEV_IOCTL_EXPIRE,
+ ctl.devfd, ioctlfd, path, (void *) ¶m);
+}
+
+static int ioctl_expire(unsigned int logopt,
+ int ioctlfd, const char *path, unsigned int when)
+{
+ return expire(logopt, AUTOFS_IOC_EXPIRE_MULTI,
+ ioctlfd, ioctlfd, path, (void *) &when);
+}
+
+/* Check if autofs mount point is in use */
+static int dev_ioctl_askumount(unsigned int logopt,
+ int ioctlfd, unsigned int *busy)
+{
+ struct autofs_dev_ioctl param;
+
+ init_autofs_dev_ioctl(¶m);
+ param.ioctlfd = ioctlfd;
+
+ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ASKUMOUNT, ¶m) == -1)
+ return -1;
+
+ *busy = param.arg1;
+
+ return 0;
+}
+
+static int ioctl_askumount(unsigned int logopt,
+ int ioctlfd, unsigned int *busy)
+{
+ return ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, busy);
+}
+
+/*
+ * Check if the given path is a mountpoint.
+ *
+ * The path is considered a mountpoint if it is itself a mountpoint
+ * or contains a mount, such as a multi-mount without a root mount.
+ * In addition, if the path is itself a mountpoint we return whether
+ * the mounted file system is an autofs filesystem or other file
+ * system.
+ */
+static int dev_ioctl_ismountpoint(unsigned int logopt,
+ int ioctlfd, const char *path,
+ unsigned int *mountpoint)
+{
+ struct autofs_dev_ioctl *param;
+ int err;
+
+ *mountpoint = 0;
+
+ if (!path) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ param = alloc_dev_ioctl_path(ioctlfd, path);
+ if (!param)
+ return -1;
+
+ err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param);
+ if (err == -1) {
+ int save_errno = errno;
+ free_dev_ioctl_open(param);
+ errno = save_errno;
+ return -1;
+ }
+
+ if (param->arg1) {
+ *mountpoint = DEV_IOCTL_IS_MOUNTED;
+
+ if (param->arg2) {
+ if (param->arg2 == AUTOFS_SUPER_MAGIC)
+ *mountpoint |= DEV_IOCTL_IS_AUTOFS;
+ else
+ *mountpoint |= DEV_IOCTL_IS_OTHER;
+ }
+ }
+
+ free_dev_ioctl_path(param);
+
+ return 0;
+}
diff -up autofs-5.0.3/samples/rc.autofs.in.device-node-control autofs-5.0.3/samples/rc.autofs.in
--- autofs-5.0.3/samples/rc.autofs.in.device-node-control 2008-01-14 13:39:16.000000000 +0900
+++ autofs-5.0.3/samples/rc.autofs.in 2008-02-25 09:03:12.000000000 +0900
@@ -12,6 +12,7 @@
DAEMON=@@sbindir@@/automount
prog=`basename $DAEMON`
MODULE="autofs4"
+DEVICE="autofs"
confdir=@@autofsconfdir@@
test -e $DAEMON || exit 0
@@ -47,6 +48,14 @@ function start() {
return 1
fi
+ # Check misc device
+ if [ -e "/proc/misc" ]; then
+ MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc`
+ if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then
+ mknod -m 0600 /dev/$DEVICE c 10 $MINOR
+ fi
+ fi
+
$prog $OPTIONS
RETVAL=$?
if [ $RETVAL -eq 0 ] ; then