]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/makeroot/makeroot.sh
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / makeroot / makeroot.sh
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
34 usage()
35 {
36         cat <<EOF 1>&2
37 usage: 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>
41 EOF
42         exit 1
43 }
44
45 warn()
46 {
47         echo `basename $0` "$@" 1>&2
48 }
49
50 err()
51 {
52         ret=$1
53         shift
54         warn "$@"
55         exit $ret
56 }
57
58 atexit()
59 {
60         if [ -z "${DEBUG}" ]; then
61                 rm -rf ${tmpdir}
62         else
63                 warn "temp directory left at ${tmpdir}"
64         fi
65 }
66
67 DEBUG=
68 # Allow duplice manifest entries when not file list is given because the
69 # FreeBSD METALOG still includes it.
70 DUPFLAG=-D
71 EXTRAS=
72 FILELIST=
73 GROUP=
74 KEYDIR=
75 KEYUSERS=
76 PASSWD=
77
78 while getopts "Bde:f:g:K:k: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}"; DUPFLAG= ;;
84         g)      GROUP="${OPTARG}" ;;
85         K)      KEYUSERS="${KEYUSERS} ${OPTARG}" ;;
86         k)      KEYDIR="${OPTARG}" ;;
87         p)      PASSWD="${OPTARG}" ;;
88         s)      SIZE="${OPTARG}" ;;
89         *)      usage ;;
90         esac
91 done
92 shift $(($OPTIND - 1))
93
94 if [ $# -ne 2 ]; then
95         usage;
96 fi
97
98 IMGFILE=$(realpath $(dirname $1))/$(basename $1)
99 BSDROOT=$2
100
101 DBDIR=${BSDROOT}/etc
102
103 if [ ! -r ${BSDROOT}/METALOG ]; then
104         err 1 "${BSDROOT} does not contain a METALOG"
105 fi
106
107 if [ -n "${GROUP}" -a -z "${PASSWD}" ]; then
108         warn "-g requires -p"
109         usage
110 fi
111
112 if [ -n "${KEYUSERS}" -a -z "${KEYDIR}" ]; then
113         warn "-K requires -k"
114         usage
115 fi
116 if [ -n "${KEYDIR}" -a -z "${KEYUSERS}" ]; then
117         KEYUSERS=root
118 fi
119
120 tmpdir=`mktemp -d /tmp/makeroot.XXXXX`
121 if [ -z "${tmpdir}" -o ! -d "${tmpdir}" ]; then
122         err 1 "failed to create tmpdir"
123 fi
124 trap atexit EXIT
125
126 manifest=${tmpdir}/manifest
127
128 echo "#mtree 2.0" > ${manifest}
129
130 if [ -n "${PASSWD}" ]; then
131         cp ${PASSWD} ${tmpdir}/master.passwd
132         pwd_mkdb -d ${tmpdir} -p ${tmpdir}/master.passwd
133         if [ -z "${GROUP}" ]; then
134                 cp ${DBDIR}/group ${tmpdir}
135         else
136                 cp ${GROUP} ${tmpdir}
137         fi
138
139         cat <<EOF >> ${tmpdir}/passwd.mtree
140 ./etc/group type=file uname=root gname=wheel mode=0644 contents=${tmpdir}/group
141 ./etc/master.passwd type=file uname=root gname=wheel mode=0600 contents=${tmpdir}/master.passwd
142 ./etc/passwd type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/passwd
143 ./etc/pwd.db type=file mode=0644 uname=root gname=wheel contents=${tmpdir}/pwd.db
144 ./etc/spwd.db type=file mode=0600 uname=root gname=wheel contents=${tmpdir}/spwd.db
145 EOF
146         EXTRAS="${EXTRAS} ${tmpdir}/passwd.mtree"
147
148         DBDIR=${tmpdir}
149 fi
150
151 if [ -n "${FILELIST}" ]; then
152         # build manifest from root manifest and FILELIST
153         (echo .; grep -v ^# ${FILELIST} | while read path; do
154                 # Print each included path and all its sub-paths with a ./
155                 # prepended.  The "sort -u" will then discard all the
156                 # duplicate directory entries.  This ensures that we
157                 # extract the permissions for each unlisted directory
158                 # from the METALOG.
159                 path="/${path}"
160                 while [ -n "${path}" ]; do
161                         echo ".${path}"
162                         path="${path%/*}"
163                 done 
164         done) | sort -u ${BSDROOT}/METALOG - | \
165             awk '
166                 !/ type=/ { file = $1 }
167                 / type=/ { if ($1 == file) {print} }' >> ${manifest}
168 else
169         # Start with all the files in BSDROOT/METALOG except those in
170         # one of the EXTRAS manifests.
171         grep -h type=file ${EXTRAS} | cut -d' ' -f1 | \
172             sort -u ${BSDROOT}/METALOG - | awk '
173                 !/ type=/ { file = $1 }
174                 / type=/ { if ($1 != file) {print} }' >> ${manifest}
175 fi
176
177 # For each extras file, add contents kyes relative to the directory the
178 # manifest lives in for each file line that does not have one.  Adjust
179 # contents keys relative to ./ to be relative to the same directory.
180 for eman in ${EXTRAS}; do
181         if [ ! -f ${eman} ]; then
182                 err 1 "${eman} is not a regular file"
183         fi
184         extradir=`realpath ${eman}`; extradir=`dirname ${extradir}`
185
186         awk '{
187                 if ($0 !~ /type=file/) {
188                         print
189                 } else {
190                         if ($0 !~ /contents=/) {
191                                 printf ("%s contents=%s\n", $0, $1)
192                         } else {
193                                 print
194                         }
195                 }
196         }' ${eman} | \
197             sed -e "s|contents=\./|contents=${extradir}/|" >> ${manifest}
198 done
199
200 # /etc/rcorder.start allows the startup order to be stable even if
201 # not all startup scripts are installed.  In theory it should be
202 # unnecessicary, but dependencies in rc.d appear to be under recorded.
203 # This is a hack local to beri/cheribsd.
204 #
205 echo /etc/rc.d/FIRST > ${tmpdir}/rcorder.start
206 rcorder -s nostart ${BSDROOT}/etc/rc.d/* | sed -e "s:^${BSDROOT}::" | \
207      grep -v LAST | grep -v FIRST >> \
208     ${tmpdir}/rcorder.start
209 echo /etc/rc.d/LAST >> ${tmpdir}/rcorder.start
210 echo "./etc/rcorder.start type=file mode=644 uname=root gname=wheel" \
211    "contents=${tmpdir}/rcorder.start" >> ${manifest}
212
213 # Add all public keys in KEYDIR to roots' authorized_keys file.
214 if [ -n "${KEYDIR}" ]; then
215         cat ${KEYDIR}/*.pub > ${tmpdir}/authorized_keys
216         if [ ! -s ${tmpdir}/authorized_keys ]; then
217                 err 1 "no keys found in ${KEYDIR}"
218         fi
219         for user in ${KEYUSERS}; do
220                 userdir=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$9; exit} }" ${DBDIR}/master.passwd`
221                 gid=`awk -F: "{if (\\\$1 == \"${user}\") {print \\\$4; exit} }" ${DBDIR}/master.passwd`
222                 group=`awk -F: "{if (\\\$3 == \"${gid}\") {print \\\$1; exit} }" ${DBDIR}/group`
223                 if [ -z "${userdir}" ]; then
224                         err 1 "${user}: not found in ${DBDIR}/master.passwd"
225                 fi
226                 echo ".${userdir}/.ssh type=dir mode=700 uname=${user} gname=${group}" >> ${manifest}
227                 echo ".${userdir}/.ssh/authorized_keys type=file mode=600 uname=${user} gname=${group} contents=${tmpdir}/authorized_keys" >> ${manifest}
228         done
229 fi
230
231 if [ -n "${SIZE}" ]; then
232 SIZEFLAG="-s ${SIZE}"
233 fi
234
235 cd ${BSDROOT}; makefs ${DUPFLAG} -N ${DBDIR} ${SIZEFLAG} ${BFLAG} \
236      -t ffs -f 256 ${IMGFILE} ${manifest}