commit
04e6c3c3b1
11 changed files with 1393 additions and 0 deletions
@ -0,0 +1,2 @@ |
||||
/askpass |
||||
/secrets/* |
@ -0,0 +1,11 @@ |
||||
Copyright (c) 2010-2018, Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
Copyright (c) 2020-2022, Shiz <hi@shiz.me> |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
||||
* 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. |
||||
* Neither the name of Piotr Karbowski nor Shiz 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. |
@ -0,0 +1,418 @@ |
||||
/*
|
||||
* askpass.c - prompts a user for a passphrase using any suitable method |
||||
* and prints the result to stdout. |
||||
* |
||||
* Copyright (C) 2008 David Härdeman <david@hardeman.nu> |
||||
* |
||||
* This package 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; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This package 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. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this package; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
* |
||||
* 2012 - Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
* * Dropped splasy code. |
||||
*/ |
||||
|
||||
#define _GNU_SOURCE |
||||
#define _BSD_SOURCE |
||||
#define _POSIX_C_SOURCE 1 |
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include <errno.h> |
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
#include <termios.h> |
||||
#include <sys/klog.h> |
||||
#include <sys/select.h> |
||||
#include <sys/ioctl.h> |
||||
#include <signal.h> |
||||
#include <dirent.h> |
||||
#include <linux/vt.h> |
||||
#include <sys/un.h> |
||||
#include <sys/uio.h> |
||||
|
||||
#define DEBUG 0 |
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
||||
|
||||
static bool disable_method(const char *method); |
||||
|
||||
/*****************************************************************************
|
||||
* Utility functions * |
||||
*****************************************************************************/ |
||||
static void |
||||
debug(const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
static bool first = true; |
||||
static FILE *dbgfile; |
||||
|
||||
if (!DEBUG) |
||||
return; |
||||
|
||||
if (first) { |
||||
first = false; |
||||
dbgfile = fopen("/tmp/askpass.debug", "a"); |
||||
} |
||||
|
||||
if (!dbgfile) |
||||
return; |
||||
|
||||
va_start(ap, fmt); |
||||
vfprintf(dbgfile, fmt, ap); |
||||
va_end(ap); |
||||
} |
||||
|
||||
static void |
||||
usage(const char *arg0, const char *errmsg) |
||||
{ |
||||
if (errmsg) |
||||
fprintf(stderr, "Error: %s\nUsage: %s PROMPT\n", errmsg, arg0); |
||||
else |
||||
fprintf(stderr, "Usage: %s PROMPT\n", arg0); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
static void |
||||
fifo_common_finish(int fd, char **buf, size_t *used, size_t *size) |
||||
{ |
||||
if (fd >= 0) |
||||
close(fd); |
||||
|
||||
if (!*buf) |
||||
return; |
||||
|
||||
memset(*buf, '\0', *size); |
||||
free(*buf); |
||||
*buf = NULL; |
||||
*used = 0; |
||||
*size = 0; |
||||
} |
||||
|
||||
static bool |
||||
fifo_common_read(int fd, char **buf, size_t *used, size_t *size) |
||||
{ |
||||
ssize_t result; |
||||
|
||||
again: |
||||
if ((*size - *used) == 0) { |
||||
*size += 4096; |
||||
*buf = realloc(*buf, *size); |
||||
if (!*buf) { |
||||
*size = 0; |
||||
*used = 0; |
||||
debug("Failed to allocate memory for passphrase\n"); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
reread: |
||||
result = read(fd, *buf + *used, *size - *used); |
||||
|
||||
if (result < 0) { |
||||
if (errno == EAGAIN) |
||||
return false; |
||||
if (errno == EINTR) |
||||
goto reread; |
||||
debug("Error when reading from fifo\n"); |
||||
return false; |
||||
} |
||||
|
||||
debug("Read %i bytes from fifo\n", (int)result); |
||||
*used += result; |
||||
|
||||
if (result == 0) |
||||
return true; |
||||
|
||||
goto again; |
||||
} |
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* fifo functions * |
||||
*****************************************************************************/ |
||||
#define FIFO_PATH "/luks_passfifo" |
||||
static size_t fifoused = 0; |
||||
static size_t fifosize = 0; |
||||
static char *fifobuf = NULL; |
||||
|
||||
static void |
||||
fifo_finish(int fd) |
||||
{ |
||||
fifo_common_finish(fd, &fifobuf, &fifoused, &fifosize); |
||||
} |
||||
|
||||
static bool |
||||
fifo_read(int fd, char **buf, size_t *size) |
||||
{ |
||||
debug("In fifo_read\n"); |
||||
if (fifo_common_read(fd, &fifobuf, &fifoused, &fifosize)) { |
||||
*buf = fifobuf; |
||||
*size = fifoused; |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
static int |
||||
fifo_prepare(const char *prompt) |
||||
{ |
||||
int ret; |
||||
|
||||
ret = mkfifo(FIFO_PATH, 0600); |
||||
if (ret && errno != EEXIST) |
||||
return -1; |
||||
|
||||
return open(FIFO_PATH, O_RDONLY | O_NONBLOCK); |
||||
} |
||||
|
||||
/*****************************************************************************
|
||||
* console functions * |
||||
*****************************************************************************/ |
||||
#define CONSOLE_PATH "/dev/console" |
||||
static struct termios term_old; |
||||
static bool term_set = false; |
||||
static char *consolebuf = NULL; |
||||
static size_t consolebuflen = 0; |
||||
|
||||
static void |
||||
console_finish(int fd) |
||||
{ |
||||
if (consolebuf) { |
||||
memset(consolebuf, '\0', consolebuflen); |
||||
free(consolebuf); |
||||
consolebuf = NULL; |
||||
consolebuflen = 0; |
||||
} |
||||
|
||||
if (!term_set || fd < 0) |
||||
return; |
||||
|
||||
term_set = false; |
||||
tcsetattr(fd, TCSAFLUSH, &term_old); |
||||
fprintf(stderr, "\n"); |
||||
klogctl(7, NULL, 0); |
||||
} |
||||
|
||||
bool |
||||
console_read(int fd, char **buf, size_t *size) |
||||
{ |
||||
ssize_t nread; |
||||
|
||||
/* Console is in ICANON mode so we'll get entire lines */ |
||||
nread = getline(&consolebuf, &consolebuflen, stdin); |
||||
|
||||
if (nread < 0) |
||||
return NULL; |
||||
|
||||
/* Strip trailing newline, if any */ |
||||
if (nread > 0 && consolebuf[nread - 1] == '\n') { |
||||
nread--; |
||||
consolebuf[nread] = '\0'; |
||||
} |
||||
|
||||
*size = nread; |
||||
*buf = consolebuf; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static int |
||||
console_prepare(const char *prompt) |
||||
{ |
||||
struct termios term_new; |
||||
char *prompt_ptr = prompt; |
||||
char *newline = NULL; |
||||
|
||||
if (!isatty(STDIN_FILENO)) { |
||||
if (access(CONSOLE_PATH, R_OK | W_OK)) { |
||||
debug("No access to console device " CONSOLE_PATH "\n"); |
||||
return -1; |
||||
} |
||||
|
||||
if (!freopen(CONSOLE_PATH, "r", stdin) || |
||||
!freopen(CONSOLE_PATH, "a", stdout) || |
||||
!freopen(CONSOLE_PATH, "a", stderr) || |
||||
!isatty(STDIN_FILENO)) { |
||||
debug("Failed to open console\n"); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
if (tcgetattr(STDIN_FILENO, &term_old)) { |
||||
debug("Failed to get terminal settings\n"); |
||||
return -1; |
||||
} |
||||
|
||||
term_new = term_old; |
||||
term_new.c_lflag &= ~ECHO; |
||||
term_new.c_lflag |= ICANON; |
||||
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_new)) { |
||||
debug("Failed to disable echoing\n"); |
||||
return -1; |
||||
} |
||||
|
||||
/* handle any non-literal embedded newlines in prompt */ |
||||
while ( (newline = strstr(prompt_ptr,"\\n")) != NULL ) { |
||||
/* Calculate length of string leading up to newline. */ |
||||
int line_len = newline - prompt_ptr; |
||||
|
||||
/* Force trimming of prompt to location of newline. */ |
||||
if (fwrite(prompt_ptr, line_len, 1, stderr) < 1 || |
||||
fwrite("\n", 1, 1, stderr) < 1) { |
||||
debug("Failed to print prompt\n"); |
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_old); |
||||
return -1; |
||||
} |
||||
|
||||
/* Skip over newline. */ |
||||
prompt_ptr = newline + 2; |
||||
} |
||||
if (fputs(prompt_ptr, stderr) < 0) { |
||||
debug("Failed to print prompt\n"); |
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_old); |
||||
return -1; |
||||
} |
||||
|
||||
/* Disable printk to console */ |
||||
klogctl(6, NULL, 0); |
||||
term_set = true; |
||||
return STDIN_FILENO; |
||||
} |
||||
|
||||
/*****************************************************************************
|
||||
* main functions * |
||||
*****************************************************************************/ |
||||
|
||||
struct method { |
||||
const char *name; |
||||
int (*prepare)(const char *prompt); |
||||
bool (*read)(int fd, char **buf, size_t *size); |
||||
void (*finish)(int fd); |
||||
bool active; |
||||
bool enabled; |
||||
int fd; |
||||
}; |
||||
|
||||
static struct method methods[] = { |
||||
{ "fifo", fifo_prepare, fifo_read, fifo_finish, false, true, -1 }, |
||||
{ "console", console_prepare, console_read, console_finish, false, true, -1 } |
||||
}; |
||||
|
||||
static bool |
||||
disable_method(const char *method) |
||||
{ |
||||
int i; |
||||
bool result = false; |
||||
|
||||
debug("Disabling method %s\n", method ? method : "ALL"); |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(methods); i++) { |
||||
/* A NULL method means all methods should be disabled */ |
||||
if (method && strcmp(methods[i].name, method)) |
||||
continue; |
||||
if (!methods[i].enabled) |
||||
continue; |
||||
if (methods[i].active) |
||||
methods[i].finish(methods[i].fd); |
||||
|
||||
methods[i].active = false; |
||||
methods[i].fd = -1; |
||||
methods[i].enabled = false; |
||||
result = true; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
int |
||||
main(int argc, char **argv, char **envp) |
||||
{ |
||||
char *pass = NULL; |
||||
size_t passlen = 0; |
||||
int i; |
||||
int nfds; |
||||
fd_set fds; |
||||
int ret; |
||||
bool done = false; |
||||
sigset_t sigset; |
||||
|
||||
if (argc != 2) |
||||
usage(argv[0], "incorrect number of arguments"); |
||||
|
||||
sigfillset(&sigset); |
||||
sigprocmask(SIG_BLOCK, &sigset, NULL); |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(methods); i++) { |
||||
if (!methods[i].enabled) |
||||
continue; |
||||
debug("Enabling method %s\n", methods[i].name); |
||||
methods[i].fd = methods[i].prepare(argv[1]); |
||||
if (methods[i].fd < 0) |
||||
methods[i].active = false; |
||||
else |
||||
methods[i].active = true; |
||||
} |
||||
|
||||
while (!done) { |
||||
nfds = 0; |
||||
FD_ZERO(&fds); |
||||
for (i = 0; i < ARRAY_SIZE(methods); i++) { |
||||
if (!methods[i].enabled || methods[i].fd < 0) |
||||
continue; |
||||
debug("method %i has fd %i and name %s\n", i, methods[i].fd, methods[i].name); |
||||
FD_SET(methods[i].fd, &fds); |
||||
if (methods[i].fd + 1 > nfds) |
||||
nfds = methods[i].fd + 1; |
||||
} |
||||
|
||||
if (nfds == 0) { |
||||
debug("All methods disabled\n"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
debug("Starting select with nfds %i\n", nfds); |
||||
ret = select(nfds, &fds, NULL, NULL, NULL); |
||||
|
||||
if (ret <= 0) { |
||||
if (ret == 0 || errno == EINTR) |
||||
continue; |
||||
debug("Select failed\n"); |
||||
disable_method(NULL); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(methods); i++) { |
||||
if (!methods[i].enabled || methods[i].fd < 0) |
||||
continue; |
||||
if (!FD_ISSET(methods[i].fd, &fds)) |
||||
continue; |
||||
if (methods[i].read(methods[i].fd, &pass, &passlen) && pass) { |
||||
done = true; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
debug("Writing %i bytes to stdout\n", (int)passlen); |
||||
write(STDOUT_FILENO, pass, passlen); |
||||
disable_method(NULL); |
||||
exit(EXIT_SUCCESS); |
||||
} |
||||
|
@ -0,0 +1,51 @@ |
||||
#!/bin/sh |
||||
set -e |
||||
|
||||
if [ $# -lt 1 ]; then |
||||
echo "usage: $0 <image> [cmdline] [arch]" |
||||
exit 1 |
||||
fi |
||||
image="$1" |
||||
cmdline="$2" |
||||
arch="$3" |
||||
|
||||
staging=$(mktemp -d) |
||||
trap "rm -rf '$staging'" EXIT |
||||
|
||||
if [ -z "$arch" ]; then |
||||
arch=$(apk --print-arch) |
||||
fi |
||||
|
||||
apk add --root="$staging" --arch "$arch" --repositories-file /etc/apk/repositories --keys-dir /etc/apk/keys --initdb \ |
||||
alpine-baselayout busybox busybox-suid cryptsetup zfs dropbear |
||||
|
||||
cp -R rootfs/* "$staging" |
||||
cc -static askpass.c -o "$staging"/bin/askpass |
||||
|
||||
git_tag="$(git describe --tags --exact-match HEAD 2>/dev/null || true)" |
||||
git_branch="$(git symbolic-ref HEAD 2>/dev/null || true)" |
||||
git_latestcommit="$(git log -1 --date='short' --format='%h-%ad' || true)" |
||||
if [ -n "$git_tag" ]; then |
||||
version="$git_tag" |
||||
elif [ -n "$git_latestcommit" ]; then |
||||
version="$git_branch-$git_latestcommit" |
||||
elif [ -n "$git_branch" ]; then |
||||
version="$git_branch-???" |
||||
else |
||||
version="???" |
||||
fi |
||||
echo "$version" > "$staging"/VERSION |
||||
|
||||
cp secrets/authorized_keys "$staging" |
||||
mkdir -p "$staging"/etc/dropbear |
||||
for x in rsa ecdsa; do |
||||
hostkey=secrets/dropbear_${x}_host_key |
||||
if ! [ -f "$hostkey" ]; then |
||||
"$staging"/usr/bin/dropbearkey -t $x -f "$hostkey" |
||||
fi |
||||
cp "$hostkey" "$staging"/etc/dropbear |
||||
done |
||||
|
||||
echo " $cmdline" >> "$staging"/cmdline |
||||
|
||||
(cd "$staging" && find . | cpio -H newc -o | gzip -9) > "$image" |
@ -0,0 +1,42 @@ |
||||
#!/bin/sh |
||||
set -e |
||||
|
||||
if [ $# -lt 1 ]; then |
||||
echo "usage: $0 <dest.img> [version]" |
||||
exit 1 |
||||
fi |
||||
|
||||
dest="$1" |
||||
version="${2:-$(uname -r)}" |
||||
basedir="/lib/modules/$version" |
||||
|
||||
stagedir=$(mktemp -d) |
||||
trap "rm -rf '$stagedir'" EXIT |
||||
|
||||
# Copy modules |
||||
mkdir -p "$stagedir/etc" |
||||
mkdir -p "$stagedir/$basedir" |
||||
cp "$basedir"/modules.* "$stagedir/$basedir" |
||||
grep -v '^#' /etc/modules | while read module; do |
||||
modprobe -S "$version" -D "$module" | while read -r action file; do |
||||
mkdir -p "$stagedir/$(dirname "$file")" |
||||
cp "$file" "$stagedir/$file" |
||||
done |
||||
echo "$module" >> "$stagedir"/etc/modules |
||||
done |
||||
|
||||
# Copy loader |
||||
mkdir -p "$stagedir"/hooks/early |
||||
cat <<'EOF' > "$stagedir"/hooks/early/modules |
||||
#!/bin/sh |
||||
|
||||
if [ -f /etc/modules ]; then |
||||
while read module; do |
||||
modprobe "$module" |
||||
done < /etc/modules |
||||
fi |
||||
EOF |
||||
chmod +x "$stagedir"/hooks/early/modules |
||||
|
||||
# Make initramfs |
||||
(cd "$stagedir" && find . | cpio --quiet -H newc -o | gzip -9) > "$dest" |
@ -0,0 +1,35 @@ |
||||
#!/bin/sh |
||||
# better-initramfs project |
||||
# https://bitbucket.org/piotrkarbowski/better-initramfs |
||||
# Copyright (c) 2010-2013, Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are met: |
||||
# * Redistributions of source code must retain the above copyright notice, |
||||
# this list of conditions and the following disclaimer. |
||||
# * 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. |
||||
# * Neither the name of the Piotr Karbowski 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 |
||||
|
||||
# A small script to resume boot process. |
||||
# Kill regular rescueshell (which is exected on error OR forced via 'rescueshell' boot option' |
||||
# And remove /remote-rescueshell.lock what is executed when you login over ssh in the sshd_wait period |
||||
|
||||
if [ -f '/rescueshell.pid' ]; then kill -9 "$(cat /rescueshell.pid)"; fi |
||||
if [ -f '/remote-rescueshell.lock' ]; then rm '/remote-rescueshell.lock'; fi |
@ -0,0 +1,46 @@ |
||||
#!/bin/sh |
||||
# better-initramfs project |
||||
# https://bitbucket.org/piotrkarbowski/better-initramfs |
||||
# Copyright (c) 2010-2013, Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are met: |
||||
# * Redistributions of source code must retain the above copyright notice, |
||||
# this list of conditions and the following disclaimer. |
||||
# * 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. |
||||
# * Neither the name of the Piotr Karbowski 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 |
||||
|
||||
# Read password with hidden input and pass it to fifo. |
||||
|
||||
. /functions.sh |
||||
|
||||
IFS='' |
||||
|
||||
if ! [ -e '/luks_passfifo' ]; then |
||||
eerror "There is no '/luks_passfifo'." |
||||
exit 1 |
||||
fi |
||||
|
||||
printf 'Enter password: ' |
||||
stty -echo |
||||
read -r luks_password |
||||
stty echo |
||||
printf "%s" "${luks_password}" >/luks_passfifo |
||||
printf '\n' |
@ -0,0 +1,686 @@ |
||||
#!/bin/sh |
||||
# better-initramfs project |
||||
# https://bitbucket.org/piotrkarbowski/better-initramfs |
||||
# Copyright (c) 2010-2013, Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are met: |
||||
# * Redistributions of source code must retain the above copyright notice, |
||||
# this list of conditions and the following disclaimer. |
||||
# * 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. |
||||
# * Neither the name of the Piotr Karbowski 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 |
||||
|
||||
einfo() { echo -ne "\033[1;30m>\033[0;36m>\033[1;36m> \033[0m${*}\n" ;} |
||||
ewarn() { echo -ne "\033[1;30m>\033[0;33m>\033[1;33m> \033[0m${*}\n" >&2;} |
||||
eerror() { echo -ne "\033[1;30m>\033[0;31m>\033[1;31m> ${*}\033[0m\n" >&2 ;} |
||||
die() { eerror "$*"; rescueshell; } |
||||
|
||||
|
||||
InitializeBusybox() { |
||||
einfo "Create all the symlinks to /bin/busybox." |
||||
run /bin/busybox --install -s |
||||
} |
||||
|
||||
rescueshell() { |
||||
if [ "$rescueshell" != 'true' ]; then |
||||
# If we did not forced rescueshell by kernel opt, print additional message. |
||||
ewarn "Dropping to rescueshell because of above error." |
||||
fi |
||||
|
||||
ewarn "Rescue Shell (busybox's /bin/sh)" |
||||
ewarn "To reboot, press 'control-alt-delete'." |
||||
ewarn "If you wish resume booting process, run 'resume-boot'." |
||||
if [ "$console" ] && [ -c "/dev/${console}" ]; then |
||||
setsid sh -c "exec sh --login </dev/"${console}" >/dev/${console} 2>&1" |
||||
elif [ -c '/dev/tty1' ]; then |
||||
setsid sh -c 'exec sh --login </dev/tty1 >/dev/tty1 2>&1' |
||||
else |
||||
sh --login |
||||
fi |
||||
echo |
||||
:> /rescueshell.pid |
||||
} |
||||
|
||||
was_shell() { |
||||
[ -f '/rescueshell.pid' ] |
||||
return $? |
||||
} |
||||
|
||||
run() { |
||||
if "$@"; then |
||||
echo "Executed: '$@'" >> /init.log |
||||
else |
||||
eerror "'$@' failed." |
||||
echo "Failed: '$@'" >> /init.log |
||||
echo "$@" >> /.ash_history |
||||
rescueshell |
||||
fi |
||||
} |
||||
|
||||
get_opt() { |
||||
echo "${*#*=}" |
||||
} |
||||
|
||||
run_hooks() { |
||||
# Support for optional code injection via hooks placed into |
||||
# multiple initramfs images. |
||||
if [ -d "/hooks/$1" ]; then |
||||
for i in /hooks/$1/*; do |
||||
[ "$i" = "/hooks/$1/*" ] && break |
||||
einfo "Running '$i' hook ..." |
||||
[ -x "$i" ] && . "$i" |
||||
done |
||||
fi |
||||
} |
||||
|
||||
populate_dev_disk_by_label_and_uuid() { |
||||
# Create /dev/disk/by-{uuid,label} symlinks. |
||||
# We could run it with mdev as a trigger on event, |
||||
# but binit uses devtmpfs by default. |
||||
|
||||
# It is possible that later whatever manages /dev |
||||
# will not probe block device and create symlinks, |
||||
# so we should do it before we move /dev to /newroot/dev |
||||
|
||||
# Fix for an issue reported under Gentoo's bug #559026. |
||||
|
||||
local block_device blkid_output LABEL UUID TYPE |
||||
local vars |
||||
|
||||
einfo "Populating /dev/disk/by-{uuid,label} ..." |
||||
|
||||
dodir /dev/disk /dev/disk/by-uuid /dev/disk/by-label |
||||
|
||||
for block_device in /sys/class/block/*; do |
||||
unset blkid_output LABEL UUID TYPE |
||||
|
||||
block_device="${block_device##*/}" |
||||
|
||||
blkid_output="$(blkid "/dev/${block_device}")" |
||||
[ "${blkid_output}" ] || continue |
||||
vars="${blkid_output#*:}" |
||||
eval "${vars}" |
||||
|
||||
[ "${LABEL}" ] && ! [ -e "/dev/disk/by-label/${LABEL}" ] && run ln -s "../../${block_device}" "/dev/disk/by-label/${LABEL}" |
||||
[ "${UUID}" ] && ! [ -e "/dev/disk/by-uuid/${UUID}" ] && run ln -s "../../${block_device}" "/dev/disk/by-uuid/${UUID}" |
||||
done |
||||
} |
||||
|
||||
resolve_device() { |
||||
# This function will check if variable at $1 contain LABEL or UUID and then, if LABEL/UUID is vaild. |
||||
device="$(eval echo \$$1)" |
||||
case "${device}" in |
||||
LABEL\=*|UUID\=*) |
||||
eval $1="$(findfs $device)" |
||||
if [ -z "$(eval echo \$$1)" ]; then |
||||
eerror "Wrong UUID or LABEL." |
||||
rescueshell |
||||
fi |
||||
;; |
||||
esac |
||||
} |
||||
|
||||
process_commandline_options() { |
||||
for i in $(cat /cmdline /proc/cmdline); do |
||||
case "${i}" in |
||||
initramfsdebug) |
||||
set -x |
||||
;; |
||||
root\=*) |
||||
root=$(get_opt $i) |
||||
;; |
||||
init\=*) |
||||
init=$(get_opt $i) |
||||
;; |
||||
enc_root\=*) |
||||
enc_root=$(get_opt $i) |
||||
;; |
||||
zfs) |
||||
zfs=true |
||||
;; |
||||
luks) |
||||
luks=true |
||||
;; |
||||
lvm) |
||||
lvm=true |
||||
;; |
||||
softraid) |
||||
softraid=true |
||||
;; |
||||
rescueshell) |
||||
rescueshell=true |
||||
;; |
||||
swsusp) |
||||
swsusp=true |
||||
;; |
||||
uswsusp) |
||||
uswsusp=true |
||||
;; |
||||
tuxonice) |
||||
tuxonice=true |
||||
;; |
||||
resume\=*) |
||||
resume=$(get_opt $i) |
||||
;; |
||||
rootfstype\=*) |
||||
rootfstype=$(get_opt $i) |
||||
;; |
||||
|
||||
rootflags\=*) |
||||
rootfsmountparams="-o $(get_opt $i)" |
||||
;; |
||||
|
||||
ro|rw) |
||||
root_rw_ro=$i |
||||
;; |
||||
sshd) |
||||
sshd=true |
||||
;; |
||||
sshd_wait\=*) |
||||
sshd_wait=$(get_opt $i) |
||||
;; |
||||
sshd_port\=*) |
||||
sshd_port=$(get_opt $i) |
||||
;; |
||||
sshd_interface\=*) |
||||
# deprecated |
||||
sshd_interface=$(get_opt $i) |
||||
;; |
||||
sshd_ipv4\=*) |
||||
# deprecated |
||||
sshd_ipv4=$(get_opt $i) |
||||
;; |
||||
sshd_ipv4_gateway\=*) |
||||
# deprecated |
||||
sshd_ipv4_gateway=$(get_opt $i) |
||||
;; |
||||
binit_net_if\=*) |
||||
binit_net_if=$(get_opt $i) |
||||
;; |
||||
binit_net_addr\=*) |
||||
binit_net_addr=$(get_opt $i) |
||||
;; |
||||
binit_net_route\=*) |
||||
binit_net_routes="${binit_net_routes} $(get_opt $i)" |
||||
;; |
||||
binit_net_gw\=*) |
||||
binit_net_gw=$(get_opt $i) |
||||
;; |
||||
rootdelay\=*) |
||||
rootdelay=$(get_opt $i) |
||||
;; |
||||
console\=*) |
||||
console=$(get_opt $i) |
||||
console="${console%,*}" |
||||
;; |
||||
mdev) |
||||
mdev=true |
||||
;; |
||||
luks_no_discards) |
||||
luks_no_discards=true |
||||
;; |
||||
bcache) |
||||
bcache=true |
||||
;; |
||||
esac |
||||
done |
||||
} |
||||
|
||||
use() { |
||||
name="$(eval echo \$$1)" |
||||
# Check if $name isn't empty and if $name isn't set to false or zero. |
||||
if [ -n "${name}" ] && [ "${name}" != 'false' ] && [ "${name}" != '0' ]; then |
||||
if [ -n "$2" ]; then |
||||
$2 |
||||
else |
||||
return 0 |
||||
fi |
||||
else |
||||
return 1 |
||||
fi |
||||
} |
||||
|
||||
musthave() { |
||||
while [ -n "$1" ]; do |
||||
# We can handle it by use() function, yay! |
||||
if ! use "$1"; then |
||||
eerror "The \"$1\" variable is empty, set to false or zero but shoudn't be." |
||||
local missing_variable='true' |
||||
fi |
||||
shift |
||||
done |
||||
|
||||
if [ "${missing_variable}" = 'true' ]; then |
||||
rescueshell |
||||
fi |
||||
} |
||||
|
||||
dodir() { |
||||
for dir in "$@"; do |
||||
run mkdir -m 700 -p "${dir}" |
||||
done |
||||
} |
||||
|
||||
loadkeymap() { |
||||
if [ -f /keymap ]; then |
||||
loadkmap < /keymap |
||||
fi |
||||
} |
||||
|
||||
get_majorminor() { |
||||
local device="$1" |
||||
musthave device |
||||
|
||||
local major_hex="$(stat -L -c '%t' "${device}")" |
||||
local minor_hex="$(stat -L -c '%T' "${device}")" |
||||
|
||||
musthave major_hex minor_hex |
||||
|
||||
if [ -n "${major_hex}" ] && [ -n "${minor_hex}" ]; then |
||||
printf '%u:%u\n' "0x${major_hex}" "0x${minor_hex}" |
||||
fi |
||||
} |
||||
|
||||
which() { |
||||
command -v "$1" |
||||
} |
||||
|
||||
exists() { |
||||
which "$1" >/dev/null |
||||
} |
||||
|
||||
InitializeLUKS() { |
||||
if ! exists cryptsetup ; then |
||||
eerror "There is no cryptsetup binary into initramfs image." |
||||
rescueshell |
||||
fi |
||||
|
||||
musthave enc_root |
||||
|
||||
local enc_num='1' |
||||
local dev_name="enc_root" |
||||
# We will use : to separate devices but we need normal IFS inside the for loop anyway. |
||||
local IFS=":" |
||||
for enc_dev in ${enc_root}; do |
||||
IFS="${default_ifs}" |
||||
if ! [ "${enc_num}" = '1' ]; then |
||||
dev_name="enc_root${enc_num}" |
||||
fi |
||||
|
||||
resolve_device enc_dev |
||||
|
||||
einfo "Opening encrypted partition '${enc_dev##*/}' and mapping to '/dev/mapper/${dev_name}'." |
||||
|
||||
# Hack for cryptsetup which trying to run /sbin/udevadm. |
||||
run echo -e "#!/bin/sh\nexit 0" > /sbin/udevadm |
||||
run chmod 755 /sbin/udevadm |
||||
|
||||
local cryptsetup_args="" |
||||
if ! use luks_no_discards; then |
||||
cryptsetup_args="${cryptsetup_args} --allow-discards" |
||||
fi |
||||
|
||||
if use sshd; then |
||||
askpass "Enter passphrase for ${enc_dev}: " | run cryptsetup --tries 1 --key-file=- luksOpen ${cryptsetup_args} "${enc_dev}" "${dev_name}" |
||||
# Remove the fifo, askpass will create new if needed (ex multiple devices). |
||||
rm '/luks_passfifo' |
||||
else |
||||
run cryptsetup luksOpen --tries 25 ${cryptsetup_args} "${enc_dev}" "${dev_name}" |
||||
fi |
||||
enc_num="$((enc_num+1))" |
||||
done |
||||
} |
||||
|
||||
InitializeLVM() { |
||||
einfo "Scaning all disks for volume groups." |
||||
# We have to ensure that cache does not exist so vgchange will run 'vgscan' itself. |
||||
if [ -d '/etc/lvm/cache' ]; then run rm -rf '/etc/lvm/cache'; fi |
||||
run lvm vgchange -a y |
||||
} |
||||
|
||||
InitializeSoftwareRaid() { |
||||
einfo "Scaning for software raid arrays." |
||||
if ! [ -f '/etc/mdadm.conf' ]; then |
||||
run mdadm --examine --scan > /etc/mdadm.conf |
||||
fi |
||||
run mdadm --assemble --scan |
||||
|
||||
# The software raid arrays may have partitions on them. |
||||
rereadpt |
||||
} |
||||
|
||||
InitializeZFS() { |
||||
einfo "Initializing ZFS." |
||||
modprobe zfs |
||||
run zpool import -a |
||||
} |
||||
|
||||
rereadpt() { |
||||
# Check for partition table on all block devices. |
||||
for i in /dev/*; do |
||||
if [ -b "${i}" ]; then |
||||
blockdev --rereadpt "${i}" >/dev/null 2>&1 |
||||
fi |
||||
done |
||||
} |
||||
|
||||
SwsuspResume() { |
||||
musthave resume |
||||
resolve_device resume |
||||
if [ -f '/sys/power/resume' ]; then |
||||
local resume_majorminor="$(get_majorminor "${resume}")" |
||||
musthave resume_majorminor |
||||
einfo 'Sending resume device to /sys/power/resume ...' |
||||
echo "${resume_majorminor}" > /sys/power/resume |
||||
else |
||||
ewarn "Apparently this kernel does not support suspend." |
||||
fi |
||||
} |
||||
|
||||
UswsuspResume() { |
||||
musthave resume |
||||
resolve_device resume |
||||
if [ -f '/sys/power/resume' ]; then |
||||
run resume --resume_device "${resume}" |
||||
else |
||||
ewarn "Apparently this kernel does not support suspend." |
||||
fi |
||||
} |
||||
|
||||
TuxOnIceResume() { |
||||
musthave resume |
||||
if [ -f '/sys/power/tuxonice/do_resume' ]; then |
||||
einfo "Sending do_resume signal to TuxOnIce." |
||||
run echo 1 > /sys/power/tuxonice/do_resume |
||||
else |
||||
ewarn "Apparently this kernel does not support TuxOnIce." |
||||
fi |
||||
} |
||||
|
||||
register_bcache_devices() { |
||||
# Push all the block devices to register_quiet |
||||
# If its bcache, it will bring it up, if not, it will simply ignore it. |
||||
if ! [ -e /sys/fs/bcache/register_quiet ]; then |
||||
ewarn "There's no bcache interface. Missing kernel driver?" |
||||
return 0 |
||||
fi |
||||
|
||||
for i in $(awk '$4 !~ /^(name$|$)/ { print $4 }' /proc/partitions); do |
||||
if [ -e "/dev/${i}" ]; then |
||||
echo "/dev/${i}" >/sys/fs/bcache/register_quiet |
||||
else |
||||
echo "Looks like there's no '/dev/${i}', but should be." |
||||
fi |
||||
done |
||||
} |
||||
|
||||
SetupNetwork() { |
||||
# Defaults ... |
||||
vlan='false' |
||||
|
||||
# backward compatibility |
||||
if [ "${sshd_interface}" ]; then |
||||
ewarn "sshd_interface is deprecated, check README" |
||||
ewarn "and switch to binit_net_if!" |
||||
binit_net_if="${sshd_interface}" |
||||
binit_net_addr="${sshd_ipv4}" |
||||
binit_net_gw="${sshd_ipv4_gateway}" |
||||
fi |
||||
|
||||
# setting _interface is the trigger. |
||||
# after dropping backward compatibility there should be |
||||
# a 'use FOO && SetupNetwork' in init script. |
||||
use binit_net_if || return |
||||
|
||||
musthave binit_net_addr |
||||
|
||||
run ip link set up dev lo |
||||
|
||||
case "${binit_net_if}" in |
||||
*'.'*) |
||||
vlan='true' |
||||
binit_net_physif="${binit_net_if%%.*}" |
||||
local binit_net_vlan="${binit_net_if##*.}" |
||||
einfo "Bringing up ${binit_net_physif} interface ..." |
||||
run ip link set up dev "${binit_net_physif}" |
||||
einfo "Adding VLAN ${binit_net_vlan} on ${binit_net_physif} interface ..." |
||||
run vconfig add "${binit_net_physif}" "${binit_net_vlan}" |
||||
;; |
||||
esac |
||||
|
||||
einfo "Bringing up ${binit_net_if} interface ..." |
||||
run ip link set up dev "${binit_net_if}" |
||||
|
||||
einfo "Setting ${binit_net_addr} on ${binit_net_if} ..." |
||||
run ip addr add "${binit_net_addr}" dev "${binit_net_if}" |
||||
|
||||
if [ -n "${binit_net_routes}" ]; then |
||||
for route in ${binit_net_routes}; do |
||||
einfo "Adding additional route '${route}' ..." |
||||
run ip route add "${route}" dev "${binit_net_if}" |
||||
done |
||||
fi |
||||
|
||||
if [ -n "${binit_net_gw}" ]; then |
||||
einfo "Setting default routing via '${binit_net_gw}' ..." |
||||
run ip route add default via "${binit_net_gw}" dev "${binit_net_if}" |
||||
fi |
||||
} |
||||
|
||||
setup_sshd() { |
||||
# Prepare /dev/pts. |
||||
einfo "Mounting /dev/pts ..." |
||||
if ! [ -d /dev/pts ]; then run mkdir /dev/pts; fi |
||||
run mount -t devpts none /dev/pts |
||||
|
||||
# Prepare dirs. |
||||
dodir /etc/dropbear /var/log /var/run /root/.ssh |
||||
|
||||
# Generate host keys. |
||||
einfo "Generating dropbear ssh host keys ..." |
||||
for x in rsa ecdsa; do |
||||
test -f /etc/dropbear/dropbear_$x_host_key || \ |
||||
run dropbearkey -t $x -f /etc/dropbear/dropbear_$x_host_key > /dev/null |
||||
done |
||||
|
||||
# Prepare root account. |
||||
run echo 'root:x:0:0:root:/root:/bin/sh' > /etc/passwd |
||||
|
||||
if [ -f /authorized_keys ]; then |
||||
run cp /authorized_keys /root/.ssh/authorized_keys |
||||
else |
||||
eerror "Missing /authorized_keys file, you will be no able login via sshd." |
||||
rescueshell |
||||
fi |
||||
|
||||
einfo 'Starting dropbear sshd ...' |
||||
run dropbear -s -p "${binit_net_addr%/*}:${sshd_port:-22}" |
||||
} |
||||
|
||||
wait_sshd() { |
||||
if use sshd_wait; then |
||||
# sshd_wait exist, now we should sleep for X sec. |
||||
if [ "${sshd_wait}" -gt 0 2>/dev/null ]; then |
||||
einfo "Waiting ${sshd_wait}s (sshd_wait)" |
||||
while [ ${sshd_wait} -gt 0 ]; do |
||||
[ -f '/remote-rescueshell.lock' ] && break |
||||
sshd_wait=$((sshd_wait - 1)) |
||||
sleep 1 |
||||
done |
||||
else |
||||
ewarn "\$sshd_wait variable must be numeric and greater than zero. Skipping sshd_wait." |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
cleanup() { |
||||
if use binit_net_if; then |
||||
if [ -f '/remote-rescueshell.lock' ]; then |
||||
ewarn "The lockfile at '/remote-rescueshell.lock' exist." |
||||
ewarn "The boot process will be paused until the lock is removed." |
||||
while true; do |
||||
if [ -f '/remote-rescueshell.lock' ]; then |
||||
sleep 1 |
||||
else |
||||
break |
||||
fi |
||||
done |
||||
fi |
||||
|
||||
fi |
||||
|
||||
was_shell && rm /rescueshell.pid |
||||
|
||||
if use sshd; then |
||||
run pkill -9 dropbear > /dev/null 2>&1 |
||||
fi |
||||
|
||||
if use binit_net_if; then |
||||
run ip addr flush dev "${binit_net_if}" |
||||
run ip route flush dev "${binit_net_if}" |
||||
run ip link set down dev "${binit_net_if}" |
||||
if use vlan; then |
||||
run ip link del "${binit_net_if}" |
||||
run ip link set down dev "${binit_net_physif}" |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
boot_newroot() { |
||||
init="${init:-/sbin/init}" |
||||
einfo "Switching root to /newroot and executing ${init}." |
||||
if ! [ -x "/newroot/${init}" ]; then die "There is no executable '/newroot/${init}'."; fi |
||||
exec env -i \ |
||||
TERM="${TERM:-linux}" \ |
||||
PATH="${PATH:-/bin:/sbin:/usr/bin:/usr/sbin}" \ |
||||
switch_root /newroot "${init}" |
||||
} |
||||
|
||||
emount() { |
||||
# All mounts into one place is good idea. |
||||
local mountparams |
||||
while [ "$#" -gt 0 ]; do |
||||
case $1 in |
||||
'/newroot') |
||||
if mountpoint -q '/newroot'; then |
||||
einfo "/newroot already mounted, skipping..." |
||||
else |
||||
einfo "Mounting /newroot..." |
||||
musthave root |
||||
if [ "${rootfsmountparams}" ]; then |
||||
mountparams="${rootfsmountparams}" |
||||
fi |
||||
if [ -n "${rootfstype}" ]; then |
||||
mountparams="${mountparams} -t ${rootfstype}" |
||||
fi |
||||
resolve_device root |
||||
run mount -o ${root_rw_ro:-ro} ${mountparams} "${root}" '/newroot' |
||||
fi |
||||
;; |
||||
|
||||
'/newroot/usr') |
||||
if [ -f '/newroot/etc/fstab' ]; then |
||||
while read device mountpoint fstype fsflags _; do |
||||
if [ "${mountpoint}" = '/usr' ]; then |
||||
if [ -d '/newroot/usr' ]; then |
||||
einfo "Mounting /newroot/usr..." |
||||
run mount -o "${fsflags},${root_rw_ro:-ro}" -t "${fstype}" "${device}" '/newroot/usr' |
||||
else |
||||
die "/usr in fstab present but no mountpoint /newroot/usr found." |
||||
fi |
||||
break |
||||
fi |
||||
done < '/newroot/etc/fstab' |
||||
else |
||||
ewarn "No /newroot/etc/fstab present." |
||||
ewarn "Early mouting of /usr will not be done." |
||||
fi |
||||
;; |
||||
|
||||
'/dev') |
||||
local devmountopts='nosuid,relatime,size=10240k,mode=755' |
||||
|
||||
if grep -q 'devtmpfs' '/proc/filesystems' && ! use mdev; then |
||||
einfo "Mounting /dev (devtmpfs)..." |
||||
run mount -t devtmpfs -o ${devmountopts} devtmpfs /dev |
||||
else |
||||
einfo "Mounting /dev (mdev over tmpfs)..." |
||||
run mount -t tmpfs -o ${devmountopts} dev /dev |
||||
run touch /etc/mdev.conf |
||||
run echo /sbin/mdev > /proc/sys/kernel/hotplug |
||||
run mdev -s |
||||
# Looks like mdev create /dev/pktcdvd as a file when both udev and devtmpfs do it as a dir. |
||||
# We will do it 'better' to avoid non-fatal-error while starting udev after switching to /newroot. |
||||
# TODO: Can mdev.conf handle it? |
||||
if [ -c '/dev/pktcdvd' ]; then |
||||
run rm '/dev/pktcdvd' |
||||
run mkdir '/dev/pktcdvd' |
||||
run mknod '/dev/pktcdvd/control' c 10 61 |
||||
fi |
||||
fi |
||||
;; |
||||
|
||||
'/proc') |
||||
einfo "Mounting /proc..." |
||||
run mount -t proc proc /proc |
||||
;; |
||||
|
||||
'/sys') |
||||
einfo "Mounting /sys..." |
||||
run mount -t sysfs sysfs /sys |
||||
;; |
||||
|
||||
*) |
||||
eerror "emount() does not understand \"$1\"" |
||||
;; |
||||
esac |
||||
shift |
||||
done |
||||
} |
||||
|
||||
eumount() { |
||||
while [ "$#" -gt 0 ]; do |
||||
case "$1" in |
||||
*) |
||||
einfo "Unmounting ${1}..." |
||||
run umount "$1" |
||||
;; |
||||
esac |
||||
shift |
||||
done |
||||
} |
||||
|
||||
moveDev() { |
||||
einfo "Moving /dev to /newroot/dev..." |
||||
if mountpoint -q /dev/pts; then umount -l /dev/pts; fi |
||||
if use mdev; then run echo '' > /proc/sys/kernel/hotplug; fi |
||||
run mount --move /dev /newroot/dev |
||||
} |
||||
|
||||
rootdelay() { |
||||
if [ "${rootdelay}" -gt 0 2>/dev/null ]; then |
||||
einfo "Waiting ${rootdelay}s (rootdelay)" |
||||
run sleep ${rootdelay} |
||||
else |
||||
ewarn "\$rootdelay variable must be numeric and greater than zero. Skipping rootdelay." |
||||
fi |
||||
} |
||||
|
||||
# vim: noexpandtab |
@ -0,0 +1,102 @@ |
||||
#!/bin/sh |
||||
# better-initramfs project |
||||
# https://bitbucket.org/piotrkarbowski/better-initramfs |
||||
# Copyright (c) 2010-2013, Piotr Karbowski <piotr.karbowski@gmail.com> |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are met: |
||||
# * Redistributions of source code must retain the above copyright notice, |
||||
# this list of conditions and the following disclaimer. |
||||
# * 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. |
||||
# * Neither the name of the Piotr Karbowski 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 |
||||
|
||||
: ${PATH:=/bin:/sbin:/usr/bin:/usr/sbin} |
||||
|
||||
# Load functions. |
||||
. /functions.sh |
||||
|
||||
run_hooks init |
||||
|
||||
# Prepare dirs |
||||
run dodir /dev /newroot /sbin /proc /sys /etc /var/log /var/run |
||||
|
||||
# Basic /dev content, we need it as fast as possible. |
||||
[ ! -e /dev/console ] && run mknod /dev/console c 5 1 |
||||
[ ! -e /dev/null ] && run mknod /dev/null c 1 3 |
||||
[ ! -e /dev/tty ] && run mknod /dev/tty c 5 0 |
||||
[ ! -e /dev/urandom ] && run mknod /dev/urandom c 1 9 |
||||
[ ! -e /dev/random ] && run mknod /dev/random c 1 8 |
||||
[ ! -e /dev/zero ] && run mknod /dev/zero c 1 5 |
||||
|
||||
# Clear the screen |
||||
clear |
||||
|
||||
# Save IFS so we can easly restore it if we ever change it. |
||||
readonly default_ifs="${IFS}" |
||||
|
||||
# Basic |
||||
kernelver="$(uname -r)" |
||||
ver="$(cat /VERSION)" |
||||
|
||||
einfo "better-initramfs ${ver}. Linux kernel ${kernelver}.\n" |
||||
echo -e "\nWelcome to better-initramfs ${ver}. Linux kernel ${kernelver}.\n" > /etc/motd |
||||
|
||||
emount /proc /sys |
||||
|
||||
# Disable kernel messages from popping onto the screen |
||||
echo 0 > /proc/sys/kernel/printk |
||||
|
||||
process_commandline_options |
||||
InitializeBusybox |
||||
emount /dev |
||||
run_hooks early |
||||
SetupNetwork |
||||
use sshd && setup_sshd |
||||
loadkeymap |
||||
|
||||
# Let's try to support all possible combinations of storage layers. |
||||
use bcache register_bcache_devices |
||||
use softraid InitializeSoftwareRaid && use bcache register_bcache_devices |
||||
use lvm InitializeLVM && use bcache register_bcache_devices |
||||
use luks InitializeLUKS && use lvm InitializeLVM && use bcache register_bcache_devices |
||||
use zfs InitializeZFS |
||||
|
||||
populate_dev_disk_by_label_and_uuid |
||||
|
||||
use rescueshell rescueshell |
||||
use swsusp && SwsuspResume |
||||
use uswsusp && UswsuspResume |
||||
use tuxonice TuxOnIceResume |
||||
run_hooks pre_newroot_mount |
||||
use rootdelay rootdelay |
||||
emount /newroot |
||||
emount /newroot/usr |
||||
# Wait for sshd connection only if rescueshell have never occur. |
||||
use sshd && was_shell || wait_sshd |
||||
cleanup |
||||
moveDev |
||||
eumount /sys /proc |
||||
run_hooks pre_switch_root |
||||
boot_newroot |
||||
|
||||
ewarn "Something went wrong." |
||||
rescueshell |
||||
|
||||
# vim: noexpandtab |
Loading…
Reference in new issue