#!/bin/sh -e #- # Copyright (c) 2012-2013 SRI International # Copyright (c) 2012 Robert N. M. Watson # All rights reserved. # # This software was developed by SRI International and the University of # Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) # ("CTSRD"), as part of the DARPA CRASH research programme. # # 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. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. # # $FreeBSD$ usage() { cat <&2 usage: makeroot.sh [-B byte-order] [-d] [-e ] [-f ] [-k [-K ]] [-p [-g ]] [-s ] EOF exit 1 } warn() { echo `basename $0` "$@" 1>&2 } err() { ret=$1 shift warn "$@" exit $ret } atexit() { if [ -z "${DEBUG}" ]; then rm -rf ${tmpdir} else warn "temp directory left at ${tmpdir}" fi } DEBUG= # Allow duplice manifest entries when not file list is given because the # FreeBSD METALOG still includes it. DUPFLAG=-D EXTRAS= FILELIST= GROUP= KEYDIR= KEYUSERS= PASSWD= while getopts "Bde:f:g:K:k:p:s:" opt; do case "$opt" in B) BFLAG="-B ${OPTARG}" ;; d) DEBUG=1 ;; e) EXTRAS="${EXTRAS} ${OPTARG}" ;; f) FILELIST="${OPTARG}"; DUPFLAG= ;; g) GROUP="${OPTARG}" ;; K) KEYUSERS="${KEYUSERS} ${OPTARG}" ;; k) KEYDIR="${OPTARG}" ;; p) PASSWD="${OPTARG}" ;; s) SIZE="${OPTARG}" ;; *) usage ;; esac done shift $(($OPTIND - 1)) if [ $# -ne 2 ]; then usage; fi IMGFILE=$(realpath $(dirname $1))/$(basename $1) BSDROOT=$2 DBDIR=${BSDROOT}/etc if [ ! -r ${BSDROOT}/METALOG ]; then err 1 "${BSDROOT} does not contain a METALOG" fi if [ -n "${GROUP}" -a -z "${PASSWD}" ]; then warn "-g requires -p" usage fi if [ -n "${KEYUSERS}" -a -z "${KEYDIR}" ]; then warn "-K requires -k" usage fi if [ -n "${KEYDIR}" -a -z "${KEYUSERS}" ]; then KEYUSERS=root fi tmpdir=`mktemp -d /tmp/makeroot.XXXXX` if [ -z "${tmpdir}" -o ! -d "${tmpdir}" ]; then err 1 "failed to create tmpdir" fi trap atexit EXIT manifest=${tmpdir}/manifest echo "#mtree 2.0" > ${manifest} if [ -n "${PASSWD}" ]; then cp ${PASSWD} ${tmpdir}/master.passwd pwd_mkdb -d ${tmpdir} -p ${tmpdir}/master.passwd if [ -z "${GROUP}" ]; then cp ${DBDIR}/group ${tmpdir} else cp ${GROUP} ${tmpdir} fi cat <> ${tmpdir}/passwd.mtree ./etc/group type=file uname=root gname=wheel mode=0644 contents=${tmpdir}/group ./etc/master.passwd type=file uname=root gname=wheel mode=0600 contents=${tmpdir}/master.passwd ./etc/passwd type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/passwd ./etc/pwd.db type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/pwd.db ./etc/spwd.db type=file mode=0600 uname=root gname=wheel contents=${tmpdir}/spwd.db EOF EXTRAS="${EXTRAS} ${tmpdir}/passwd.mtree" DBDIR=${tmpdir} fi if [ -n "${FILELIST}" ]; then # build manifest from root manifest and FILELIST (echo .; grep -v ^# ${FILELIST} | while read path; do # Print each included path and all its sub-paths with a ./ # prepended. The "sort -u" will then discard all the # duplicate directory entries. This ensures that we # extract the permissions for each unlisted directory # from the METALOG. path="/${path}" while [ -n "${path}" ]; do echo ".${path}" path="${path%/*}" done done) | sort -u ${BSDROOT}/METALOG - | \ awk ' !/ type=/ { file = $1 } / type=/ { if ($1 == file) {print} }' >> ${manifest} else # Start with all the files in BSDROOT/METALOG except those in # one of the EXTRAS manifests. grep -h type=file ${EXTRAS} | cut -d' ' -f1 | \ sort -u ${BSDROOT}/METALOG - | awk ' !/ type=/ { file = $1 } / type=/ { if ($1 != file) {print} }' >> ${manifest} fi # For each extras file, add contents kyes relative to the directory the # manifest lives in for each file line that does not have one. Adjust # contents keys relative to ./ to be relative to the same directory. for eman in ${EXTRAS}; do if [ ! -f ${eman} ]; then err 1 "${eman} is not a regular file" fi extradir=`realpath ${eman}`; extradir=`dirname ${extradir}` awk '{ if ($0 !~ /type=file/) { print } else { if ($0 !~ /contents=/) { printf ("%s contents=%s\n", $0, $1) } else { print } } }' ${eman} | \ sed -e "s|contents=\./|contents=${extradir}/|" >> ${manifest} done # /etc/rcorder.start allows the startup order to be stable even if # not all startup scripts are installed. In theory it should be # unnecessicary, but dependencies in rc.d appear to be under recorded. # This is a hack local to beri/cheribsd. # echo /etc/rc.d/FIRST > ${tmpdir}/rcorder.start rcorder -s nostart ${BSDROOT}/etc/rc.d/* | sed -e "s:^${BSDROOT}::" | \ grep -v LAST | grep -v FIRST >> \ ${tmpdir}/rcorder.start echo /etc/rc.d/LAST >> ${tmpdir}/rcorder.start echo "./etc/rcorder.start type=file mode=644 uname=root gname=wheel" \ "contents=${tmpdir}/rcorder.start" >> ${manifest} # Add all public keys in KEYDIR to roots' authorized_keys file. if [ -n "${KEYDIR}" ]; then cat ${KEYDIR}/*.pub > ${tmpdir}/authorized_keys if [ ! -s ${tmpdir}/authorized_keys ]; then err 1 "no keys found in ${KEYDIR}" fi for user in ${KEYUSERS}; do userdir=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$9; exit} }" ${DBDIR}/master.passwd` gid=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$4; exit} }" ${DBDIR}/master.passwd` group=`awk -F: "{if (\\\$3 == \"${gid}\") {print \\\$1; exit} }" ${DBDIR}/group` if [ -z "${userdir}" ]; then err 1 "${user}: not found in ${DBDIR}/master.passwd" fi echo ".${userdir}/.ssh type=dir mode=700 uname=${user} gname=${group}" >> ${manifest} echo ".${userdir}/.ssh/authorized_keys type=file mode=600 uname=${user} gname=${group} contents=${tmpdir}/authorized_keys" >> ${manifest} done fi if [ -n "${SIZE}" ]; then SIZEFLAG="-s ${SIZE}" fi cd ${BSDROOT}; makefs ${DUPFLAG} -N ${DBDIR} ${SIZEFLAG} ${BFLAG} \ -t ffs -f 256 ${IMGFILE} ${manifest}