Commit becc02e5 authored by Mike Hibler's avatar Mike Hibler
Browse files

Updates for soon-to-be FreeBSD 11.0.

parent 53b7f133
......@@ -15,8 +15,11 @@ include $(TESTBED_SRCDIR)/GNUmakerules
CFLAGS += -DDEBUGSHELL -DSECURE -DLOGIN_CAP -DCOMPAT_SYSV_INIT -DTESTBED
init: init.c pathnames.h
$(CC) $(CFLAGS) -static -o init $< -lutil -lcrypt
init.c: pathnames.h mntopts.h
getmntopts.c: mntopts.h
init: init.c getmntopts.c
$(CC) $(CFLAGS) -static -o init $^ -lutil -lcrypt
install:
......
/*-
* Copyright (c) 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#ifndef lint
static char sccsid[] = "@(#)getmntopts.c 8.3 (Berkeley) 3/29/95";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: releng/11.0/sbin/mount/getmntopts.c 230372 2012-01-20 07:29:29Z jh $");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mntopts.h"
int getmnt_silent = 0;
void
getmntopts(const char *options, const struct mntopt *m0, int *flagp,
int *altflagp)
{
const struct mntopt *m;
int negative, len;
char *opt, *optbuf, *p;
int *thisflagp;
/* Copy option string, since it is about to be torn asunder... */
if ((optbuf = strdup(options)) == NULL)
err(1, NULL);
for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
/* Check for "no" prefix. */
if (opt[0] == 'n' && opt[1] == 'o') {
negative = 1;
opt += 2;
} else
negative = 0;
/*
* for options with assignments in them (ie. quotas)
* ignore the assignment as it's handled elsewhere
*/
p = strchr(opt, '=');
if (p != NULL)
*++p = '\0';
/* Scan option table. */
for (m = m0; m->m_option != NULL; ++m) {
len = strlen(m->m_option);
if (strncasecmp(opt, m->m_option, len) == 0)
if (opt[len] == '\0' || opt[len] == '=')
break;
}
/* Save flag, or fail if option is not recognized. */
if (m->m_option) {
thisflagp = m->m_altloc ? altflagp : flagp;
if (negative == m->m_inverse)
*thisflagp |= m->m_flag;
else
*thisflagp &= ~m->m_flag;
} else if (!getmnt_silent) {
errx(1, "-o %s: option not supported", opt);
}
}
free(optbuf);
}
void
rmslashes(char *rrpin, char *rrpout)
{
char *rrpoutstart;
*rrpout = *rrpin;
for (rrpoutstart = rrpout; *rrpin != '\0'; *rrpout++ = *rrpin++) {
/* skip all double slashes */
while (*rrpin == '/' && *(rrpin + 1) == '/')
rrpin++;
}
/* remove trailing slash if necessary */
if (rrpout - rrpoutstart > 1 && *(rrpout - 1) == '/')
*(rrpout - 1) = '\0';
else
*rrpout = '\0';
}
int
checkpath(const char *path, char *resolved)
{
struct stat sb;
if (realpath(path, resolved) == NULL || stat(resolved, &sb) != 0)
return (1);
if (!S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
return (1);
}
return (0);
}
void
build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
size_t len)
{
int i;
if (*iovlen < 0)
return;
i = *iovlen;
*iov = realloc(*iov, sizeof **iov * (i + 2));
if (*iov == NULL) {
*iovlen = -1;
return;
}
(*iov)[i].iov_base = strdup(name);
(*iov)[i].iov_len = strlen(name) + 1;
i++;
(*iov)[i].iov_base = val;
if (len == (size_t)-1) {
if (val != NULL)
len = strlen(val) + 1;
else
len = 0;
}
(*iov)[i].iov_len = (int)len;
*iovlen = ++i;
}
/*
* This function is needed for compatibility with parameters
* which used to use the mount_argf() command for the old mount() syscall.
*/
void
build_iovec_argf(struct iovec **iov, int *iovlen, const char *name,
const char *fmt, ...)
{
va_list ap;
char val[255] = { 0 };
va_start(ap, fmt);
vsnprintf(val, sizeof(val), fmt, ap);
va_end(ap);
build_iovec(iov, iovlen, name, strdup(val), (size_t)-1);
}
......@@ -41,11 +41,12 @@ static const char copyright[] =
static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93";
#endif
static const char rcsid[] =
"$FreeBSD: head/sbin/init/init.c 270111 2014-08-17 19:06:26Z neel $";
"$FreeBSD: releng/11.0/sbin/init/init.c 299874 2016-05-16 00:34:48Z araujo $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
......@@ -79,6 +80,7 @@ static const char rcsid[] =
#include <login_cap.h>
#endif
#include "mntopts.h"
#include "pathnames.h"
/*
......@@ -103,6 +105,7 @@ static void warning(const char *, ...) __printflike(1, 2);
static void emergency(const char *, ...) __printflike(1, 2);
static void disaster(int);
static void badsys(int);
static void revoke_ttys(void);
static int runshutdown(void);
static char *strk(char *);
......@@ -122,6 +125,8 @@ static state_func_t clean_ttys(void);
static state_func_t catatonia(void);
static state_func_t death(void);
static state_func_t death_single(void);
static state_func_t reroot(void);
static state_func_t reroot_phase_two(void);
static state_func_t run_script(const char *);
......@@ -133,6 +138,7 @@ static int Reboot = FALSE;
static int howto = RB_AUTOBOOT;
static int devfs;
static char *init_path_argv0;
static void transition(state_t);
static state_t requested_transition;
......@@ -193,7 +199,7 @@ main(int argc, char *argv[])
{
state_t initial_transition = runcom;
char kenv_value[PATH_MAX];
int c;
int c, error;
struct sigaction sa;
sigset_t mask;
......@@ -226,6 +232,9 @@ main(int argc, char *argv[])
case 'q': /* rescan /etc/ttys */
sig = SIGHUP;
break;
case 'r': /* remount root */
sig = SIGEMT;
break;
default:
goto invalid;
}
......@@ -238,6 +247,11 @@ invalid:
#endif
errx(1, "already running");
}
init_path_argv0 = strdup(argv[0]);
if (init_path_argv0 == NULL)
err(1, "strdup");
/*
* Note that this does NOT open a file...
* Does 'init' deserve its own facility number?
......@@ -247,7 +261,7 @@ invalid:
/*
* Create an initial session.
*/
if (setsid() < 0)
if (setsid() < 0 && (errno != EPERM || getsid(0) != 1))
warning("initial setsid() failed: %m");
/*
......@@ -261,7 +275,7 @@ invalid:
* This code assumes that we always get arguments through flags,
* never through bits set in some random machine register.
*/
while ((c = getopt(argc, argv, "dsf")) != -1)
while ((c = getopt(argc, argv, "dsfr")) != -1)
switch (c) {
case 'd':
devfs = 1;
......@@ -272,6 +286,9 @@ invalid:
case 'f':
runcom_mode = FASTBOOT;
break;
case 'r':
initial_transition = reroot_phase_two;
break;
default:
warning("unrecognized flag '-%c'", c);
break;
......@@ -287,13 +304,13 @@ invalid:
handle(badsys, SIGSYS, 0);
handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU,
SIGXFSZ, 0);
handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGUSR1,
SIGUSR2, 0);
handle(transition_handler, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP,
SIGUSR1, SIGUSR2, 0);
handle(alrm_handler, SIGALRM, 0);
sigfillset(&mask);
delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM,
SIGUSR1, SIGUSR2, 0);
SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP,
SIGALRM, SIGUSR1, SIGUSR2, 0);
sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
......@@ -311,7 +328,7 @@ invalid:
if (kenv(KENV_GET, "init_script", kenv_value, sizeof(kenv_value)) > 0) {
state_func_t next_transition;
if ((next_transition = run_script(kenv_value)) != 0)
if ((next_transition = run_script(kenv_value)) != NULL)
initial_transition = (state_t) next_transition;
}
......@@ -373,6 +390,16 @@ invalid:
free(s);
}
if (initial_transition != reroot_phase_two) {
/*
* Unmount reroot leftovers. This runs after init(8)
* gets reexecuted after reroot_phase_two() is done.
*/
error = unmount(_PATH_REROOT, MNT_FORCE);
if (error != 0 && errno != EINVAL)
warning("Cannot unmount %s: %m", _PATH_REROOT);
}
/*
* Start the state machine.
*/
......@@ -620,6 +647,218 @@ write_stderr(const char *message)
write(STDERR_FILENO, message, strlen(message));
}
static int
read_file(const char *path, void **bufp, size_t *bufsizep)
{
struct stat sb;
size_t bufsize;
void *buf;
ssize_t nbytes;
int error, fd;
fd = open(path, O_RDONLY);
if (fd < 0) {
emergency("%s: %s", path, strerror(errno));
return (-1);
}
error = fstat(fd, &sb);
if (error != 0) {
emergency("fstat: %s", strerror(errno));
close(fd);
return (error);
}
bufsize = sb.st_size;
buf = malloc(bufsize);
if (buf == NULL) {
emergency("malloc: %s", strerror(errno));
close(fd);
return (error);
}
nbytes = read(fd, buf, bufsize);
if (nbytes != (ssize_t)bufsize) {
emergency("read: %s", strerror(errno));
close(fd);
free(buf);
return (error);
}
error = close(fd);
if (error != 0) {
emergency("close: %s", strerror(errno));
free(buf);
return (error);
}
*bufp = buf;
*bufsizep = bufsize;
return (0);
}
static int
create_file(const char *path, const void *buf, size_t bufsize)
{
ssize_t nbytes;
int error, fd;
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0700);
if (fd < 0) {
emergency("%s: %s", path, strerror(errno));
return (-1);
}
nbytes = write(fd, buf, bufsize);
if (nbytes != (ssize_t)bufsize) {
emergency("write: %s", strerror(errno));
close(fd);
return (-1);
}
error = close(fd);
if (error != 0) {
emergency("close: %s", strerror(errno));
return (-1);
}
return (0);
}
static int
mount_tmpfs(const char *fspath)
{
struct iovec *iov;
char errmsg[255];
int error, iovlen;
iov = NULL;
iovlen = 0;
memset(errmsg, 0, sizeof(errmsg));
build_iovec(&iov, &iovlen, "fstype",
__DECONST(void *, "tmpfs"), (size_t)-1);
build_iovec(&iov, &iovlen, "fspath",
__DECONST(void *, fspath), (size_t)-1);
build_iovec(&iov, &iovlen, "errmsg",
errmsg, sizeof(errmsg));
error = nmount(iov, iovlen, 0);
if (error != 0) {
if (*errmsg != '\0') {
emergency("cannot mount tmpfs on %s: %s: %s",
fspath, errmsg, strerror(errno));
} else {
emergency("cannot mount tmpfs on %s: %s",
fspath, strerror(errno));
}
return (error);
}
return (0);
}
static state_func_t
reroot(void)
{
void *buf;
size_t bufsize;
int error;
buf = NULL;
bufsize = 0;
revoke_ttys();
runshutdown();
/*
* Make sure nobody can interfere with our scheme.
* Ignore ESRCH, which can apparently happen when
* there are no processes to kill.
*/
error = kill(-1, SIGKILL);
if (error != 0 && errno != ESRCH) {
emergency("kill(2) failed: %s", strerror(errno));
goto out;
}
/*
* Copy the init binary into tmpfs, so that we can unmount
* the old rootfs without committing suicide.
*/
error = read_file(init_path_argv0, &buf, &bufsize);
if (error != 0)
goto out;
error = mount_tmpfs(_PATH_REROOT);
if (error != 0)
goto out;
error = create_file(_PATH_REROOT_INIT, buf, bufsize);
if (error != 0)
goto out;
/*
* Execute the temporary init.
*/
execl(_PATH_REROOT_INIT, _PATH_REROOT_INIT, "-r", NULL);
emergency("cannot exec %s: %s", _PATH_REROOT_INIT, strerror(errno));
out:
emergency("reroot failed; going to single user mode");
free(buf);
return (state_func_t) single_user;
}
static state_func_t
reroot_phase_two(void)
{
char init_path[PATH_MAX], *path, *path_component;
size_t init_path_len;
int nbytes, error;
/*
* Ask the kernel to mount the new rootfs.
*/
error = reboot(RB_REROOT);
if (error != 0) {
emergency("RB_REBOOT failed: %s", strerror(errno));
goto out;
}
/*
* Figure out where the destination init(8) binary is. Note that
* the path could be different than what we've started with. Use
* the value from kenv, if set, or the one from sysctl otherwise.
* The latter defaults to a hardcoded value, but can be overridden
* by a build time option.
*/
nbytes = kenv(KENV_GET, "init_path", init_path, sizeof(init_path));
if (nbytes <= 0) {
init_path_len = sizeof(init_path);
error = sysctlbyname("kern.init_path",
init_path, &init_path_len, NULL, 0);
if (error != 0) {
emergency("failed to retrieve kern.init_path: %s",
strerror(errno));
goto out;
}
}
/*
* Repeat the init search logic from sys/kern/init_path.c
*/
path_component = init_path;
while ((path = strsep(&path_component, ":")) != NULL) {
/*
* Execute init(8) from the new rootfs.
*/
execl(path, path, NULL);
}
emergency("cannot exec init from %s: %s", init_path, strerror(errno));
out:
emergency("reroot failed; going to single user mode");
return (state_func_t) single_user;
}
/*
* Bring the system up single user.
*/
......@@ -729,7 +968,7 @@ single_user(void)
write_stderr(banner);
for (;;) {
clear = getpass("Password:");
if (clear == 0 || *clear == '\0')
if (clear == NULL || *clear == '\0')
_exit(0);
password = crypt(clear, pp->pw_passwd);
bzero(clear, _PASSWORD_LEN);
......@@ -842,7 +1081,7 @@ runcom(void)
{
state_func_t next_transition;
if ((next_transition = run_script(_PATH_RUNCOM)) != 0)
if ((next_transition = run_script(_PATH_RUNCOM)) != NULL)
return next_transition;
runcom_mode = AUTOBOOT; /* the default */
......@@ -910,8 +1149,9 @@ run_script(const char *script)
if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
collect_child(wpid);
if (wpid == -1) {
if (requested_transition == death_single)
return (state_func_t) death_single;
if (requested_transition == death_single ||
requested_transition == reroot)
return (state_func_t) requested_transition;
if (errno == EINTR)
continue;
warning("wait for %s on %s failed: %m; going to "
......@@ -958,7 +1198,7 @@ start_session_db(void)
{
if (session_db && (*session_db->close)(session_db))
emergency("session database close: %s", strerror(errno));
if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL) {
emergency("session database open: %s", strerror(errno));
return (1);
}
......@@ -1027,7 +1267,7 @@ construct_argv(char *command)
char **argv = (char **) malloc(((strlen(command) + 1) / 2 + 1)
* sizeof (char *));
if ((argv[argc++] = strk(command)) == 0) {
if ((argv[argc++] = strk(command)) == NULL) {
free(argv);
return (NULL);
}
......@@ -1098,7 +1338,7 @@ new_session(session_t *sprev, struct ttyent *typ)
}
sp->se_next = 0;
if (sprev == 0) {