1#!/bin/sh -e 2#- 3# Copyright (c) 2012-2013 SRI International 4# Copyright (c) 2012 Robert N. M. Watson 5# All rights reserved. 6# 7# This software was developed by SRI International and the University of 8# Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9# ("CTSRD"), as part of the DARPA CRASH research programme. 10# 11# Redistribution and use in source and binary forms, with or without 12# modification, are permitted provided that the following conditions 13# are met: 14# 1. Redistributions of source code must retain the above copyright 15# notice, this list of conditions and the following disclaimer. 16# 2. Redistributions in binary form must reproduce the above copyright 17# notice, this list of conditions and the following disclaimer in the 18# documentation and/or other materials provided with the distribution. 19# 20# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30# SUCH DAMAGE. 31# 32# $FreeBSD$ 33 34usage() 35{ 36 cat <<EOF 1>&2 37usage: makeroot.sh [-B byte-order] [-d] [-e <extras manifest>] [-f <filelist>] 38 [-k <keydir> [-K <user>]] 39 [-p <master.passwd> [-g <groupfile>]] [-s <size>] 40 <image> <bsdroot> 41EOF 42 exit 1 43} 44 45warn() 46{ 47 echo `basename $0` "$@" 1>&2 48} 49 50err() 51{ 52 ret=$1 53 shift 54 warn "$@" 55 exit $ret 56} 57 58atexit() 59{ 60 if [ -z "${DEBUG}" ]; then 61 rm -rf ${tmpdir} 62 else 63 warn "temp directory left at ${tmpdir}" 64 fi 65} 66 67DEBUG= 68# Allow duplicate manifest entries when not file list is given because the 69# FreeBSD METALOG still includes it. 70DUPFLAG=-D 71EXTRAS= 72FILELIST= 73GROUP= 74KEYDIR= 75KEYUSERS= 76PASSWD= 77 78while getopts "B:de:f:g:K:k:l:p:s:" opt; do 79 case "$opt" in 80 B) BFLAG="-B ${OPTARG}" ;; 81 d) DEBUG=1 ;; 82 e) EXTRAS="${EXTRAS} ${OPTARG}" ;; 83 f) FILELIST="${OPTARG}";; 84 g) GROUP="${OPTARG}" ;; 85 K) KEYUSERS="${KEYUSERS} ${OPTARG}" ;; 86 k) KEYDIR="${OPTARG}" ;; 87 l) LABEL="${OPTARG}" ;; 88 p) PASSWD="${OPTARG}" ;; 89 s) SIZE="${OPTARG}" ;; 90 *) usage ;; 91 esac 92done 93shift $(($OPTIND - 1)) 94 95if [ $# -ne 2 ]; then 96 usage; 97fi 98 99IMGFILE=$(realpath $(dirname $1))/$(basename $1) 100BSDROOT=$2 101 102DBDIR=${BSDROOT}/etc 103 104if [ ! -r ${BSDROOT}/METALOG ]; then 105 err 1 "${BSDROOT} does not contain a METALOG" 106fi 107 108if [ -n "${GROUP}" -a -z "${PASSWD}" ]; then 109 warn "-g requires -p" 110 usage 111fi 112 113if [ -n "${KEYUSERS}" -a -z "${KEYDIR}" ]; then 114 warn "-K requires -k" 115 usage 116fi 117if [ -n "${KEYDIR}" -a -z "${KEYUSERS}" ]; then 118 KEYUSERS=root 119fi 120 121tmpdir=`mktemp -d /tmp/makeroot.XXXXX` 122if [ -z "${tmpdir}" -o ! -d "${tmpdir}" ]; then 123 err 1 "failed to create tmpdir" 124fi 125trap atexit EXIT 126 127manifest=${tmpdir}/manifest 128 129echo "#mtree 2.0" > ${manifest} 130 131if [ -n "${PASSWD}" ]; then 132 cp ${PASSWD} ${tmpdir}/master.passwd 133 pwd_mkdb -d ${tmpdir} -p ${tmpdir}/master.passwd 134 if [ -z "${GROUP}" ]; then 135 cp ${DBDIR}/group ${tmpdir} 136 else 137 cp ${GROUP} ${tmpdir} 138 fi 139 140 cat <<EOF >> ${tmpdir}/passwd.mtree 141./etc/group type=file uname=root gname=wheel mode=0644 contents=${tmpdir}/group 142./etc/master.passwd type=file uname=root gname=wheel mode=0600 contents=${tmpdir}/master.passwd 143./etc/passwd type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/passwd 144./etc/pwd.db type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/pwd.db 145./etc/spwd.db type=file mode=0600 uname=root gname=wheel contents=${tmpdir}/spwd.db 146EOF 147 EXTRAS="${EXTRAS} ${tmpdir}/passwd.mtree" 148 149 DBDIR=${tmpdir} 150fi 151 152if [ -n "${FILELIST}" ]; then 153 # build manifest from root manifest and FILELIST 154 (echo .; grep -v ^# ${FILELIST} | while read path; do 155 # Print each included path and all its sub-paths with a ./ 156 # prepended. The "sort -u" will then discard all the 157 # duplicate directory entries. This ensures that we 158 # extract the permissions for each unlisted directory 159 # from the METALOG. 160 path="/${path}" 161 while [ -n "${path}" ]; do 162 echo ".${path}" 163 path="${path%/*}" 164 done 165 done) | sort -u ${BSDROOT}/METALOG - | \ 166 awk ' 167 !/ type=/ { file = $1 } 168 / type=/ { if ($1 == file) {print} }' >> ${manifest} 169elif [ -n "${EXTRAS}" ]; then 170 # Start with all the files in BSDROOT/METALOG except those in 171 # one of the EXTRAS manifests. 172 grep -h type=file ${EXTRAS} | cut -d' ' -f1 | \ 173 sort -u ${BSDROOT}/METALOG - | awk ' 174 !/ type=/ { file = $1 } 175 / type=/ { if ($1 != file) {print} }' >> ${manifest} 176else 177 sort -u ${BSDROOT}/METALOG >> ${manifest} 178fi 179 180# For each extras file, add contents keys relative to the directory the 181# manifest lives in for each file line that does not have one. Adjust 182# contents keys relative to ./ to be relative to the same directory. 183for eman in ${EXTRAS}; do 184 if [ ! -f ${eman} ]; then 185 err 1 "${eman} is not a regular file" 186 fi 187 extradir=`realpath ${eman}`; extradir=`dirname ${extradir}` 188 189 awk '{ 190 if ($0 !~ /type=file/) { 191 print 192 } else { 193 if ($0 !~ /contents=/) { 194 printf ("%s contents=%s\n", $0, $1) 195 } else { 196 print 197 } 198 } 199 }' ${eman} | \ 200 sed -e "s|contents=\./|contents=${extradir}/|" >> ${manifest} 201done 202 203# /etc/rcorder.start allows the startup order to be stable even if 204# not all startup scripts are installed. In theory it should be 205# unnecessary, but dependencies in rc.d appear to be under recorded. 206# This is a hack local to beri/cheribsd. 207# 208echo /etc/rc.d/FIRST > ${tmpdir}/rcorder.start 209rcorder -s nostart ${BSDROOT}/etc/rc.d/* | sed -e "s:^${BSDROOT}::" | \ 210 grep -v LAST | grep -v FIRST >> \ 211 ${tmpdir}/rcorder.start 212echo /etc/rc.d/LAST >> ${tmpdir}/rcorder.start 213echo "./etc/rcorder.start type=file mode=644 uname=root gname=wheel" \ 214 "contents=${tmpdir}/rcorder.start" >> ${manifest} 215 216# Add all public keys in KEYDIR to roots' authorized_keys file. 217if [ -n "${KEYDIR}" ]; then 218 cat ${KEYDIR}/*.pub > ${tmpdir}/authorized_keys 219 if [ ! -s ${tmpdir}/authorized_keys ]; then 220 err 1 "no keys found in ${KEYDIR}" 221 fi 222 for user in ${KEYUSERS}; do 223 userdir=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$9; exit} }" ${DBDIR}/master.passwd` 224 gid=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$4; exit} }" ${DBDIR}/master.passwd` 225 group=`awk -F: "{if (\\\$3 == \"${gid}\") {print \\\$1; exit} }" ${DBDIR}/group` 226 if [ -z "${userdir}" ]; then 227 err 1 "${user}: not found in ${DBDIR}/master.passwd" 228 fi 229 echo ".${userdir}/.ssh type=dir mode=700 uname=${user} gname=${group}" >> ${manifest} 230 echo ".${userdir}/.ssh/authorized_keys type=file mode=600 uname=${user} gname=${group} contents=${tmpdir}/authorized_keys" >> ${manifest} 231 done 232fi 233 234if [ -n "${LABEL}" ]; then 235LABELFLAG="-o label=${LABEL}" 236fi 237if [ -n "${SIZE}" ]; then 238SIZEFLAG="-s ${SIZE}" 239fi 240 241cd ${BSDROOT}; makefs ${DUPFLAG} -N ${DBDIR} ${SIZEFLAG} ${BFLAG} \ 242 -t ffs ${LABELFLAG} -f 256 ${IMGFILE} ${manifest} 243