|
Packit |
8480eb |
/* ----------------------------------------------------------------------- *
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* spawn.c - run programs synchronously with output redirected to syslog
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Copyright 1997 Transmeta Corporation - All Rights Reserved
|
|
Packit |
8480eb |
* Copyright 2005 Ian Kent <raven@themaw.net>
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8480eb |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8480eb |
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
|
|
Packit |
8480eb |
* USA; either version 2 of the License, or (at your option) any later
|
|
Packit |
8480eb |
* version; incorporated herein by reference.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* ----------------------------------------------------------------------- */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include <signal.h>
|
|
Packit |
8480eb |
#include <stdarg.h>
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
#include <stdlib.h>
|
|
Packit |
8480eb |
#include <string.h>
|
|
Packit |
8480eb |
#include <sys/types.h>
|
|
Packit |
8480eb |
#include <dirent.h>
|
|
Packit |
8480eb |
#include <grp.h>
|
|
Packit |
8480eb |
#include <time.h>
|
|
Packit |
8480eb |
#include <poll.h>
|
|
Packit |
8480eb |
#include <sys/wait.h>
|
|
Packit |
8480eb |
#include <sys/stat.h>
|
|
Packit |
8480eb |
#include <sys/mount.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#include "automount.h"
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static pthread_mutex_t spawn_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
8480eb |
static pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define SPAWN_OPT_NONE 0x0000
|
|
Packit |
8480eb |
#define SPAWN_OPT_LOCK 0x0001
|
|
Packit |
8480eb |
#define SPAWN_OPT_OPEN 0x0002
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define MTAB_LOCK_RETRIES 3
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void dump_core(void)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
sigset_t segv;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sigemptyset(&segv);
|
|
Packit |
8480eb |
sigaddset(&segv, SIGSEGV);
|
|
Packit |
8480eb |
pthread_sigmask(SIG_UNBLOCK, &segv, NULL);
|
|
Packit |
8480eb |
sigprocmask(SIG_UNBLOCK, &segv, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
raise(SIGSEGV);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void open_mutex_lock(void)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int _o_lock = pthread_mutex_lock(&open_mutex);
|
|
Packit |
8480eb |
if (_o_lock)
|
|
Packit |
8480eb |
fatal(_o_lock);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
void open_mutex_unlock(void)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int _o_unlock = pthread_mutex_unlock(&open_mutex);
|
|
Packit |
8480eb |
if (_o_unlock)
|
|
Packit |
8480eb |
fatal(_o_unlock);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Use CLOEXEC flag for open(), pipe(), fopen() (read-only case) and
|
|
Packit |
8480eb |
* socket() if possible.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static int cloexec_works = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static void check_cloexec(int fd)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
if (cloexec_works == 0) {
|
|
Packit |
8480eb |
int fl = fcntl(fd, F_GETFD);
|
|
Packit |
8480eb |
if (fl != -1)
|
|
Packit |
8480eb |
cloexec_works = (fl & FD_CLOEXEC) ? 1 : -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (cloexec_works > 0)
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
Packit |
8480eb |
return;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int open_fd(const char *path, int flags)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
|
|
Packit |
8480eb |
if (cloexec_works != -1)
|
|
Packit |
8480eb |
flags |= O_CLOEXEC;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
fd = open(path, flags);
|
|
Packit |
8480eb |
if (fd == -1) {
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
check_cloexec(fd);
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return fd;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int open_fd_mode(const char *path, int flags, int mode)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
|
|
Packit |
8480eb |
if (cloexec_works != -1)
|
|
Packit |
8480eb |
flags |= O_CLOEXEC;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
fd = open(path, flags, mode);
|
|
Packit |
8480eb |
if (fd == -1) {
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
check_cloexec(fd);
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return fd;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int open_pipe(int pipefd[2])
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC) && defined(HAVE_PIPE2)
|
|
Packit |
8480eb |
if (cloexec_works != -1) {
|
|
Packit |
8480eb |
ret = pipe2(pipefd, O_CLOEXEC);
|
|
Packit |
8480eb |
if (ret != -1)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
if (errno != EINVAL)
|
|
Packit |
8480eb |
goto err;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
ret = pipe(pipefd);
|
|
Packit |
8480eb |
if (ret == -1)
|
|
Packit |
8480eb |
goto err;
|
|
Packit |
8480eb |
check_cloexec(pipefd[0]);
|
|
Packit |
8480eb |
check_cloexec(pipefd[1]);
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
err:
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int open_sock(int domain, int type, int protocol)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#ifdef SOCK_CLOEXEC
|
|
Packit |
8480eb |
if (cloexec_works != -1)
|
|
Packit |
8480eb |
type |= SOCK_CLOEXEC;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
fd = socket(domain, type, protocol);
|
|
Packit |
8480eb |
if (fd == -1) {
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
check_cloexec(fd);
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return fd;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
FILE *open_fopen_r(const char *path)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
FILE *f;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
|
|
Packit |
8480eb |
if (cloexec_works != -1) {
|
|
Packit |
8480eb |
f = fopen(path, "re");
|
|
Packit |
8480eb |
if (f != NULL) {
|
|
Packit |
8480eb |
check_cloexec(fileno(f));
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return f;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
f = fopen(path, "r");
|
|
Packit |
8480eb |
if (f == NULL) {
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
check_cloexec(fileno(f));
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return f;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
FILE *open_setmntent_r(const char *table)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
FILE *tab;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
#if defined(O_CLOEXEC) && defined(SOCK_CLOEXEC)
|
|
Packit |
8480eb |
if (cloexec_works != -1) {
|
|
Packit |
8480eb |
tab = setmntent(table, "re");
|
|
Packit |
8480eb |
if (tab != NULL) {
|
|
Packit |
8480eb |
check_cloexec(fileno(tab));
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return tab;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
tab = fopen(table, "r");
|
|
Packit |
8480eb |
if (tab == NULL) {
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return NULL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
check_cloexec(fileno(tab));
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
return tab;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Used by subprocesses which exec to avoid carrying over the main
|
|
Packit |
8480eb |
* daemon's signalling environment
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
void reset_signals(void)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct sigaction sa;
|
|
Packit |
8480eb |
sigset_t allsignals;
|
|
Packit |
8480eb |
int i;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sigfillset(&allsignals);
|
|
Packit |
8480eb |
sigprocmask(SIG_BLOCK, &allsignals, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Discard all pending signals */
|
|
Packit |
8480eb |
sa.sa_handler = SIG_IGN;
|
|
Packit |
8480eb |
sigemptyset(&sa.sa_mask);
|
|
Packit |
8480eb |
sa.sa_flags = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
for (i = 1; i < NSIG; i++)
|
|
Packit |
8480eb |
if (i != SIGKILL && i != SIGSTOP)
|
|
Packit |
8480eb |
sigaction(i, &sa, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sa.sa_handler = SIG_DFL;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
for (i = 1; i < NSIG; i++)
|
|
Packit |
8480eb |
if (i != SIGKILL && i != SIGSTOP)
|
|
Packit |
8480eb |
sigaction(i, &sa, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* Ignore the user signals that may be sent so that we
|
|
Packit |
8480eb |
* don't terminate execed program by mistake */
|
|
Packit |
8480eb |
sa.sa_handler = SIG_IGN;
|
|
Packit |
8480eb |
sa.sa_flags = SA_RESTART;
|
|
Packit |
8480eb |
sigaction(SIGUSR1, &sa, NULL);
|
|
Packit |
8480eb |
sigaction(SIGUSR2, &sa, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sigprocmask(SIG_UNBLOCK, &allsignals, NULL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#define ERRBUFSIZ 2047 /* Max length of error string excl \0 */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int timed_read(int pipe, char *buf, size_t len, int time)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
struct pollfd pfd[1];
|
|
Packit |
8480eb |
int timeout = time;
|
|
Packit |
8480eb |
int ret;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pfd[0].fd = pipe;
|
|
Packit |
8480eb |
pfd[0].events = POLLIN;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (time != -1) {
|
|
Packit |
8480eb |
if (time >= (INT_MAX - 1)/1000)
|
|
Packit |
8480eb |
timeout = INT_MAX - 1;
|
|
Packit |
8480eb |
else
|
|
Packit |
8480eb |
timeout = time * 1000;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = poll(pfd, 1, timeout);
|
|
Packit |
8480eb |
if (ret <= 0) {
|
|
Packit |
8480eb |
if (ret == 0)
|
|
Packit |
8480eb |
ret = -ETIMEDOUT;
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (pfd[0].fd == -1)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if ((pfd[0].revents & (POLLIN|POLLHUP)) == POLLHUP)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while ((ret = read(pipe, buf, len)) == -1 && errno == EINTR);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
static int do_spawn(unsigned logopt, unsigned int wait,
|
|
Packit |
8480eb |
unsigned int options, const char *prog,
|
|
Packit |
8480eb |
const char *const *argv)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
pid_t f;
|
|
Packit |
8480eb |
int ret, status, pipefd[2];
|
|
Packit |
8480eb |
char errbuf[ERRBUFSIZ + 1], *p, *sp;
|
|
Packit |
8480eb |
int errp, errn;
|
|
Packit |
8480eb |
int cancel_state;
|
|
Packit |
8480eb |
unsigned int use_lock = options & SPAWN_OPT_LOCK;
|
|
Packit |
8480eb |
unsigned int use_open = options & SPAWN_OPT_OPEN;
|
|
Packit |
8480eb |
sigset_t allsigs, tmpsig, oldsig;
|
|
Packit |
8480eb |
struct thread_stdenv_vars *tsv;
|
|
Packit |
8480eb |
pid_t euid = 0;
|
|
Packit |
8480eb |
gid_t egid = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (open_pipe(pipefd))
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sigfillset(&allsigs);
|
|
Packit |
8480eb |
pthread_sigmask(SIG_BLOCK, &allsigs, &oldsig);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (use_lock) {
|
|
Packit |
8480eb |
status = pthread_mutex_lock(&spawn_mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tsv = pthread_getspecific(key_thread_stdenv_vars);
|
|
Packit |
8480eb |
if (tsv) {
|
|
Packit |
8480eb |
euid = tsv->uid;
|
|
Packit |
8480eb |
egid = tsv->gid;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
open_mutex_lock();
|
|
Packit |
8480eb |
f = fork();
|
|
Packit |
8480eb |
if (f == 0) {
|
|
Packit |
8480eb |
char **pargv = (char **) argv;
|
|
Packit |
8480eb |
int loc = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
reset_signals();
|
|
Packit |
8480eb |
close(pipefd[0]);
|
|
Packit |
8480eb |
dup2(pipefd[1], STDOUT_FILENO);
|
|
Packit |
8480eb |
dup2(pipefd[1], STDERR_FILENO);
|
|
Packit |
8480eb |
close(pipefd[1]);
|
|
Packit Service |
f147ab |
open_mutex_unlock();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* what to mount must always be second last */
|
|
Packit |
8480eb |
while (*pargv++)
|
|
Packit |
8480eb |
loc++;
|
|
Packit |
8480eb |
if (loc <= 3)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
loc -= 2;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the mount location starts with a "/" then it is
|
|
Packit |
8480eb |
* a local path. In this case it is a bind mount, a
|
|
Packit |
8480eb |
* loopback mount or a file system that uses a local
|
|
Packit |
8480eb |
* path so we need to check for dependent mounts.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* I hope host names are never allowed "/" as first char
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (use_open && *(argv[loc]) == '/') {
|
|
Packit |
8480eb |
char **p;
|
|
Packit |
8480eb |
int is_bind, fd;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
pid_t pgrp = getpgrp();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Pretend to be requesting user and set non-autofs
|
|
Packit |
8480eb |
* program group to trigger mount
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (euid) {
|
|
Packit |
8480eb |
if (!tsv->user)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: can't init groups\n");
|
|
Packit |
8480eb |
else if (initgroups(tsv->user, egid) == -1)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: initgroups: %s\n",
|
|
Packit |
8480eb |
strerror(errno));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (setegid(egid) == -1)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: setegid: %s\n",
|
|
Packit |
8480eb |
strerror(errno));
|
|
Packit |
8480eb |
if (seteuid(euid) == -1)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: seteuid: %s\n",
|
|
Packit |
8480eb |
strerror(errno));
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
setpgrp();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Trigger the recursive mount.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* Ignore the open(2) return code as there may be
|
|
Packit |
8480eb |
* multiple waiters for this mount and we need to
|
|
Packit |
8480eb |
* let the VFS handle returns to each individual
|
|
Packit |
8480eb |
* waiter.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
fd = open(argv[loc], O_DIRECTORY);
|
|
Packit |
8480eb |
if (fd != -1)
|
|
Packit |
8480eb |
close(fd);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (seteuid(0) == -1)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: seteuid: %s\n",
|
|
Packit |
8480eb |
strerror(errno));
|
|
Packit |
8480eb |
if (setegid(0) == -1)
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"warning: setegid: %s\n",
|
|
Packit |
8480eb |
strerror(errno));
|
|
Packit |
8480eb |
if (pgrp >= 0)
|
|
Packit |
8480eb |
setpgid(0, pgrp);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* The kernel leaves mount type autofs alone because
|
|
Packit |
8480eb |
* they are supposed to be autofs sub-mounts and they
|
|
Packit |
8480eb |
* look after their own expiration. So mounts bound
|
|
Packit |
8480eb |
* to an autofs submount won't ever be expired.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
is_bind = 0;
|
|
Packit |
8480eb |
p = (char **) argv;
|
|
Packit |
8480eb |
while (*p) {
|
|
Packit |
8480eb |
if (strcmp(*p, "--bind")) {
|
|
Packit |
8480eb |
p++;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
is_bind = 1;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (!is_bind)
|
|
Packit |
8480eb |
goto done;
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
if (is_mounted(_PROC_MOUNTS, argv[loc], MNTS_AUTOFS)) {
|
|
Packit |
8480eb |
fprintf(stderr,
|
|
Packit |
8480eb |
"error: can't bind to an autofs mount\n");
|
|
Packit |
8480eb |
close(STDOUT_FILENO);
|
|
Packit |
8480eb |
close(STDERR_FILENO);
|
|
Packit |
8480eb |
_exit(EINVAL);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
done:
|
|
Packit |
8480eb |
execv(prog, (char *const *) argv);
|
|
Packit |
8480eb |
_exit(255); /* execv() failed */
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
tmpsig = oldsig;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sigaddset(&tmpsig, SIGCHLD);
|
|
Packit |
8480eb |
pthread_sigmask(SIG_SETMASK, &tmpsig, NULL);
|
|
Packit |
8480eb |
open_mutex_unlock();
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
close(pipefd[1]);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (f < 0) {
|
|
Packit |
8480eb |
close(pipefd[0]);
|
|
Packit |
8480eb |
if (use_lock) {
|
|
Packit |
8480eb |
status = pthread_mutex_unlock(&spawn_mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
|
|
Packit |
8480eb |
pthread_setcancelstate(cancel_state, NULL);
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
errp = 0;
|
|
Packit |
8480eb |
do {
|
|
Packit |
8480eb |
errn = timed_read(pipefd[0],
|
|
Packit |
8480eb |
errbuf + errp, ERRBUFSIZ - errp, wait);
|
|
Packit |
8480eb |
if (errn > 0) {
|
|
Packit |
8480eb |
errp += errn;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
sp = errbuf;
|
|
Packit |
8480eb |
while (errp && (p = memchr(sp, '\n', errp))) {
|
|
Packit |
8480eb |
*p++ = '\0';
|
|
Packit |
8480eb |
if (sp[0]) /* Don't output empty lines */
|
|
Packit |
8480eb |
warn(logopt, ">> %s", sp);
|
|
Packit |
8480eb |
errp -= (p - sp);
|
|
Packit |
8480eb |
sp = p;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (errp && sp != errbuf)
|
|
Packit |
8480eb |
memmove(errbuf, sp, errp);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (errp >= ERRBUFSIZ) {
|
|
Packit |
8480eb |
/* Line too long, split */
|
|
Packit |
8480eb |
errbuf[errp] = '\0';
|
|
Packit |
8480eb |
warn(logopt, ">> %s", errbuf);
|
|
Packit |
8480eb |
errp = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} while (errn > 0);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (errn == -ETIMEDOUT)
|
|
Packit |
8480eb |
kill(f, SIGTERM);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
close(pipefd[0]);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (errp > 0) {
|
|
Packit |
8480eb |
/* End of file without \n */
|
|
Packit |
8480eb |
errbuf[errp] = '\0';
|
|
Packit |
8480eb |
warn(logopt, ">> %s", errbuf);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (waitpid(f, &ret, 0) != f)
|
|
Packit |
8480eb |
ret = -1; /* waitpid() failed */
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (use_lock) {
|
|
Packit |
8480eb |
status = pthread_mutex_unlock(&spawn_mutex);
|
|
Packit |
8480eb |
if (status)
|
|
Packit |
8480eb |
fatal(status);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
|
|
Packit |
8480eb |
pthread_setcancelstate(cancel_state, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int spawnv(unsigned logopt, const char *prog, const char *const *argv)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, argv);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int spawnl(unsigned logopt, const char *prog, ...)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
va_list arg;
|
|
Packit Service |
42268b |
int argc;
|
|
Packit |
8480eb |
char **argv, **p;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, prog);
|
|
Packit |
8480eb |
for (argc = 1; va_arg(arg, char *); argc++);
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
if (!(argv = alloca(sizeof(char *) * argc)))
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, prog);
|
|
Packit |
8480eb |
p = argv;
|
|
Packit |
8480eb |
while ((*p++ = va_arg(arg, char *)));
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, (const char **) argv);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int spawn_mount(unsigned logopt, ...)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
va_list arg;
|
|
Packit |
8480eb |
int argc;
|
|
Packit |
8480eb |
char **argv, **p;
|
|
Packit |
8480eb |
char prog[] = PATH_MOUNT;
|
|
Packit |
8480eb |
char arg0[] = PATH_MOUNT;
|
|
Packit |
8480eb |
char argn[] = "-n";
|
|
Packit |
8480eb |
/* In case we need to use the fake option to mount */
|
|
Packit |
8480eb |
char arg_fake[] = "-f";
|
|
Packit |
8480eb |
unsigned int options;
|
|
Packit |
8480eb |
unsigned int retries = MTAB_LOCK_RETRIES;
|
|
Packit |
8480eb |
int update_mtab = 1, ret, printed = 0;
|
|
Packit |
8480eb |
unsigned int wait = defaults_get_mount_wait();
|
|
Packit |
8480eb |
char buf[PATH_MAX + 1];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If we use mount locking we can't validate the location */
|
|
Packit |
8480eb |
#ifdef ENABLE_MOUNT_LOCKING
|
|
Packit |
8480eb |
options = SPAWN_OPT_LOCK;
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
options = SPAWN_OPT_OPEN;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit |
8480eb |
for (argc = 1; va_arg(arg, char *); argc++);
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
|
|
Packit |
8480eb |
if (ret != -1) {
|
|
Packit |
8480eb |
buf[ret] = '\0';
|
|
Packit |
8480eb |
if (!strcmp(buf, _PROC_MOUNTS) ||
|
|
Packit |
8480eb |
!strcmp(buf, _PROC_SELF_MOUNTS)) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"mtab link detected, passing -n to mount");
|
|
Packit |
8480eb |
argc++;
|
|
Packit |
8480eb |
update_mtab = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
/* Alloc 1 extra slot in case we need to use the "-f" option */
|
|
Packit Service |
42268b |
if (!(argv = alloca(sizeof(char *) * (argc + 2))))
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
argv[0] = arg0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit Service |
42268b |
if (update_mtab)
|
|
Packit Service |
42268b |
p = argv + 1;
|
|
Packit Service |
42268b |
else {
|
|
Packit Service |
42268b |
argv[1] = argn;
|
|
Packit Service |
42268b |
p = argv + 2;
|
|
Packit Service |
42268b |
}
|
|
Packit |
8480eb |
while ((*p = va_arg(arg, char *))) {
|
|
Packit |
8480eb |
if (options == SPAWN_OPT_OPEN && !strcmp(*p, "-t")) {
|
|
Packit |
8480eb |
*(++p) = va_arg(arg, char *);
|
|
Packit |
8480eb |
if (!*p)
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* A cifs mount location begins with a "/" but
|
|
Packit |
8480eb |
* is not a local path, so don't try to resolve
|
|
Packit |
8480eb |
* it. Mmmm ... does anyone use smbfs these days?
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (strstr(*p, "cifs"))
|
|
Packit |
8480eb |
options = SPAWN_OPT_NONE;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
p++;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (retries--) {
|
|
Packit |
8480eb |
ret = do_spawn(logopt, wait, options, prog, (const char **) argv);
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
struct timespec tm = {3, 0};
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the mount succeeded but the mtab was not
|
|
Packit |
8480eb |
* updated, then retry the mount with the -f (fake)
|
|
Packit |
8480eb |
* option to just update the mtab.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!printed) {
|
|
Packit |
8480eb |
debug(logopt, "mount failed with error code 16"
|
|
Packit |
8480eb |
", retrying with the -f option");
|
|
Packit |
8480eb |
printed = 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Move the last two args so do_spawn() can find the
|
|
Packit |
8480eb |
* mount target.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!argv[argc]) {
|
|
Packit |
8480eb |
argv[argc + 1] = NULL;
|
|
Packit |
8480eb |
argv[argc] = argv[argc - 1];
|
|
Packit |
8480eb |
argv[argc - 1] = argv[argc - 2];
|
|
Packit |
8480eb |
argv[argc - 2] = arg_fake;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
nanosleep(&tm, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* This is not a fatal error */
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Version 5 requires that /etc/mtab be in sync with
|
|
Packit |
8480eb |
* /proc/mounts. If we're unable to update matb after
|
|
Packit |
8480eb |
* retrying then we have no choice but umount the mount
|
|
Packit |
8480eb |
* and return a fail.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
warn(logopt,
|
|
Packit |
8480eb |
"Unable to update the mtab file, forcing mount fail!");
|
|
Packit |
8480eb |
umount(argv[argc]);
|
|
Packit |
8480eb |
ret = MNT_FORCE_FAIL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* For bind mounts that depend on the target being mounted (possibly
|
|
Packit |
8480eb |
* itself an automount) we attempt to mount the target using an open(2)
|
|
Packit |
8480eb |
* call. For this to work the location must be the second last arg.
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* NOTE: If mount locking is enabled this type of recursive mount cannot
|
|
Packit |
8480eb |
* work.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
int spawn_bind_mount(unsigned logopt, ...)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
va_list arg;
|
|
Packit |
8480eb |
int argc;
|
|
Packit |
8480eb |
char **argv, **p;
|
|
Packit |
8480eb |
char prog[] = PATH_MOUNT;
|
|
Packit |
8480eb |
char arg0[] = PATH_MOUNT;
|
|
Packit |
8480eb |
char bind[] = "--bind";
|
|
Packit |
8480eb |
char argn[] = "-n";
|
|
Packit |
8480eb |
/* In case we need to use the fake option to mount */
|
|
Packit |
8480eb |
char arg_fake[] = "-f";
|
|
Packit |
8480eb |
unsigned int options;
|
|
Packit |
8480eb |
unsigned int retries = MTAB_LOCK_RETRIES;
|
|
Packit |
8480eb |
int update_mtab = 1, ret, printed = 0;
|
|
Packit |
8480eb |
unsigned int wait = defaults_get_mount_wait();
|
|
Packit |
8480eb |
char buf[PATH_MAX + 1];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* If we use mount locking we can't validate the location */
|
|
Packit |
8480eb |
#ifdef ENABLE_MOUNT_LOCKING
|
|
Packit |
8480eb |
options = SPAWN_OPT_LOCK;
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
options = SPAWN_OPT_OPEN;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Alloc 2 extra slots, one for the bind option and one in case
|
|
Packit |
8480eb |
* we need to use the "-f" option
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit |
8480eb |
for (argc = 2; va_arg(arg, char *); argc++);
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
|
|
Packit |
8480eb |
if (ret != -1) {
|
|
Packit |
8480eb |
buf[ret] = '\0';
|
|
Packit |
8480eb |
if (!strcmp(buf, _PROC_MOUNTS) ||
|
|
Packit |
8480eb |
!strcmp(buf, _PROC_SELF_MOUNTS)) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"mtab link detected, passing -n to mount");
|
|
Packit |
8480eb |
argc++;
|
|
Packit |
8480eb |
update_mtab = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
if (!(argv = alloca(sizeof(char *) * (argc + 2))))
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
argv[0] = arg0;
|
|
Packit |
8480eb |
argv[1] = bind;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit |
8480eb |
if (update_mtab)
|
|
Packit |
8480eb |
p = argv + 2;
|
|
Packit |
8480eb |
else {
|
|
Packit |
8480eb |
argv[2] = argn;
|
|
Packit |
8480eb |
p = argv + 3;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
while ((*p++ = va_arg(arg, char *)));
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (retries--) {
|
|
Packit |
8480eb |
ret = do_spawn(logopt, wait, options, prog, (const char **) argv);
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
struct timespec tm = {3, 0};
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the mount succeeded but the mtab was not
|
|
Packit |
8480eb |
* updated, then retry the mount with the -f (fake)
|
|
Packit |
8480eb |
* option to just update the mtab.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!printed) {
|
|
Packit |
8480eb |
debug(logopt, "mount failed with error code 16"
|
|
Packit |
8480eb |
", retrying with the -f option");
|
|
Packit |
8480eb |
printed = 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Move the last two args so do_spawn() can find the
|
|
Packit |
8480eb |
* mount target.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!argv[argc]) {
|
|
Packit |
8480eb |
argv[argc + 1] = NULL;
|
|
Packit |
8480eb |
argv[argc] = argv[argc - 1];
|
|
Packit |
8480eb |
argv[argc - 1] = argv[argc - 2];
|
|
Packit |
8480eb |
argv[argc - 2] = arg_fake;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
nanosleep(&tm, NULL);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* This is not a fatal error */
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* Version 5 requires that /etc/mtab be in sync with
|
|
Packit |
8480eb |
* /proc/mounts. If we're unable to update matb after
|
|
Packit |
8480eb |
* retrying then we have no choice but umount the mount
|
|
Packit |
8480eb |
* and return a fail.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
warn(logopt,
|
|
Packit |
8480eb |
"Unable to update the mtab file, forcing mount fail!");
|
|
Packit |
8480eb |
umount(argv[argc]);
|
|
Packit |
8480eb |
ret = MNT_FORCE_FAIL;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int spawn_umount(unsigned logopt, ...)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
va_list arg;
|
|
Packit |
8480eb |
int argc;
|
|
Packit |
8480eb |
char **argv, **p;
|
|
Packit |
8480eb |
char prog[] = PATH_UMOUNT;
|
|
Packit |
8480eb |
char arg0[] = PATH_UMOUNT;
|
|
Packit |
8480eb |
#ifdef HAVE_NO_CANON_UMOUNT
|
|
Packit |
8480eb |
char * const arg_c = "-c";
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
char * const arg_c = NULL;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
char argn[] = "-n";
|
|
Packit |
8480eb |
unsigned int options;
|
|
Packit |
8480eb |
unsigned int retries = MTAB_LOCK_RETRIES;
|
|
Packit |
8480eb |
int update_mtab = 1, ret, printed = 0;
|
|
Packit |
8480eb |
unsigned int wait = defaults_get_umount_wait();
|
|
Packit |
8480eb |
char buf[PATH_MAX + 1];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#ifdef ENABLE_MOUNT_LOCKING
|
|
Packit |
8480eb |
options = SPAWN_OPT_LOCK;
|
|
Packit |
8480eb |
#else
|
|
Packit |
8480eb |
options = SPAWN_OPT_NONE;
|
|
Packit |
8480eb |
#endif
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit |
8480eb |
for (argc = 1; va_arg(arg, char *); argc++);
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
|
|
Packit |
8480eb |
if (ret != -1) {
|
|
Packit |
8480eb |
buf[ret] = '\0';
|
|
Packit |
8480eb |
if (!strcmp(buf, _PROC_MOUNTS) ||
|
|
Packit |
8480eb |
!strcmp(buf, _PROC_SELF_MOUNTS)) {
|
|
Packit |
8480eb |
debug(logopt,
|
|
Packit |
8480eb |
"mtab link detected, passing -n to mount");
|
|
Packit |
8480eb |
argc++;
|
|
Packit |
8480eb |
update_mtab = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
if (arg_c)
|
|
Packit |
8480eb |
argc++;;
|
|
Packit |
8480eb |
|
|
Packit Service |
42268b |
if (!(argv = alloca(sizeof(char *) * (argc + 1))))
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
p = argv;
|
|
Packit |
8480eb |
*p++ = arg0;
|
|
Packit |
8480eb |
if (arg_c)
|
|
Packit |
8480eb |
*p++ = arg_c;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (!update_mtab)
|
|
Packit |
8480eb |
*p++ = argn;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
va_start(arg, logopt);
|
|
Packit |
8480eb |
while ((*p++ = va_arg(arg, char *)));
|
|
Packit |
8480eb |
va_end(arg);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
while (retries--) {
|
|
Packit |
8480eb |
ret = do_spawn(logopt, wait, options, prog, (const char **) argv);
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* If the mount succeeded but the mtab was not
|
|
Packit |
8480eb |
* updated, then retry the umount just to update
|
|
Packit |
8480eb |
* the mtab.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (!printed) {
|
|
Packit |
8480eb |
debug(logopt, "umount failed with error code 16"
|
|
Packit |
8480eb |
", retrying with the -f option");
|
|
Packit |
8480eb |
printed = 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
} else {
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* umount does not support the "fake" option. Thus,
|
|
Packit |
8480eb |
* if we got a return value of MTAB_NOTUPDATED the
|
|
Packit |
8480eb |
* first time, that means the umount actually
|
|
Packit |
8480eb |
* succeeded. Then, a following umount will fail
|
|
Packit |
8480eb |
* due to the fact that nothing was mounted on the
|
|
Packit |
8480eb |
* mount point. So, report this as success.
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
if (retries < MTAB_LOCK_RETRIES - 1)
|
|
Packit |
8480eb |
ret = 0;
|
|
Packit |
8480eb |
break;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* This is not a fatal error */
|
|
Packit |
8480eb |
if (ret == MTAB_NOTUPDATED) {
|
|
Packit |
8480eb |
warn(logopt, "Unable to update the mtab file, /proc/mounts "
|
|
Packit |
8480eb |
"and /etc/mtab will differ");
|
|
Packit |
8480eb |
ret = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return ret;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|