-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathpolecat
executable file
·233 lines (210 loc) · 5.04 KB
/
polecat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/bin/sh
# polecat: Portable Containered Application build shell script
#
# Copyright (C) 2015 Masami Hiramatsu <[email protected]>
# This program is released under the MIT License, see LICENSE.
absdir() {
(cd $1; pwd)
}
__LIBEXEC=`dirname $0`/libexec
LIBEXEC=`absdir $__LIBEXEC`
MINCEXEC=$LIBEXEC/minc-exec
MINCCOAT=$LIBEXEC/minc-coat
TRAPPER=$LIBEXEC/minc-trapper
MINCFARM=$LIBEXEC/minc-farm
OUTFILE=polecat-out
FORMAT=sh
# Exit if any errors
set -e
set -u
usage() { # [error messages]
test $# -ne 0 && echo "$*"
echo "$0 - Build a self-executable containered application"
echo "Usage: $0 [options] <rootdir> [command]"
echo " options:"
echo " -h or --help Show this help"
echo " -o or --output <FILE> Output to FILE (default: $OUTFILE)"
echo " -s or --script <FILE> Use FILE as build-script"
echo " -f or --format <FORMAT> Output format (tgz, squashfs(sfs), sh)"
exit $#
}
export MINC_DEBUG_PREFIX=
export MINC_RWBIND=
export MINC_OPT_PTY=""
export MINC_CPUMASK=
export MINC_NETNS=
export MINC_DEBUG=
export MINC_BASEDIR=/
export MINC_USE_DEV=
export MINC_IGNORE_STATE=0
export MINC_PORT_MAP=
export MINC_ARCH=`uname -m`
export MINC_BACKGROUND=
export MINC_PIVOT=0
export MINC_SSHFS_HOST=
SCRIPT=
TMPDIR=
test $# -eq 0 && usage
while [ $# -ne 0 ]; do
case $1 in
-h|--help)
usage
;;
-o|--output)
OUTFILE=$2
shift 2
;;
-s|--script)
SCRIPT=$2
shift 2
;;
-f|--format)
FORMAT=$2
case "$2" in sh|squashfs|sfs|tgz) ;;
*) usage "$2 is not supported format " ;; esac
shift 2
;;
-t|--tempdir)
TMPDIR=$2
shift 2
;;
--debug)
set -x
export MINC_DEBUG=1
shift 1
;;
--ignore-state)
export MINC_IGNORE_STATE=1
shift 1
;;
*)
break;
;;
esac
done
USE_FARM=no
#test -d "$1" || usage "$1 is not a directory"
if [ ! -d "$1" ]; then
# ensure the given id image exists
$MINCFARM pull $1 > /dev/null || \
usage "Error: no such image: $MINC_BASEDIR"
USE_FARM=image
fi
ROOTFS=$1
shift 1
:;: Preparing working dir ;:
if [ -d "$TMPDIR" ] ; then
export MINC_TMPDIR=$TMPDIR
else
export MINC_TMPDIR=`mktemp -d polecat-XXXXXXXX`
MINC_TMPDIR=`(cd $MINC_TMPDIR; pwd)`
trap "rm -rf $MINC_TMPDIR" EXIT
fi
# Working sub-directories
if [ $USE_FARM = "image" ]; then
export MINC_BASEDIR=`$MINCFARM imagestack $ROOTFS`
else
export MINC_BASEDIR=$ROOTFS
fi
$MINCCOAT bind $MINC_TMPDIR $MINC_BASEDIR
RD=$MINC_TMPDIR/root
# At first, install minc libs
mkdir -p $RD/opt/libexec
cp $LIBEXEC/minc* $RD/opt/libexec/
# Scripting mode
if [ -f "$SCRIPT" ]; then
MKDIRS=
RMDIRS=
COMMAND=
. $SCRIPT || usage "Importing error: $SCRIPT"
cp $SCRIPT $RD/opt/libexec/
# Build install script
cat > $RD/install.sh << EOF
#!/bin/sh
set -e
. /opt/libexec/`basename $SCRIPT`
install_command
EOF
chmod a+x $RD/*.sh
trap "" INT
$MINCCOAT unbind $MINC_TMPDIR
# Install phase
echo "--- Installation stage ---"
export MINC_TMPDIR
$MINCEXEC /install.sh
# Testing phase
trap '' TERM
echo "--- Testing stage (Press ^C after test run) ---"
$TRAPPER -r $ROOTFS $MINC_TMPDIR $COMMAND
# Note that this could cause directory traversal. Do not shoot your foot.
echo "--- Preparing files ---"
UD=$MINC_TMPDIR/storage
[ "$MKDIRS" ] && for i in $MKDIRS; do mkdir -p $UD/$i; done
[ "$RMDIRS" ] && for i in $RMDIRS; do rm -rf $UD/$i; done
rm -f $UD/install.sh
trap - INT
# Now we can directly use upper directory as root directory.
RD=$UD
else
$MINCCOAT unbind $MINC_TMPDIR
# Simple command execution
COMMAND="$@"
$TRAPPER -r $ROOTFS $MINC_TMPDIR $COMMAND
RD=$MINC_TMPDIR/storage
fi
:;: "Adding some required files" ;:
touch $RD/etc/hosts
touch $RD/etc/resolv.conf
OUTDIR=`dirname $OUTFILE`
mkdir -p $OUTDIR
OUTDIR=`absdir $OUTDIR`
OUTFILE=`basename $OUTFILE`
:;: "Output files in specified format" ;:
case $FORMAT in
tgz)
cd $RD;
tar czf ${OUTDIR}/${OUTFILE}.${FORMAT} .
exit 0
;;
squashfs|sfs)
mksquashfs $RD ${OUTDIR}/${OUTFILE}.${FORMAT}
exit 0
;;
esac
# Make a squashfs image
SFS=$MINC_TMPDIR/rootfs.sfs
mksquashfs $RD $SFS
SIZE=`stat --format=%s $SFS`
cat > $MINC_TMPDIR/polecat.sh << EOF
#!/bin/sh
set -e
SELF=\$0
SIZE=$SIZE
TOTAL=\`stat --format=%s \$SELF\`
OFFS=\$((TOTAL - SIZE))
PLCDIR=\`mktemp -d /tmp/polecat-run-XXXXXXXX\`
TRAPCMD="rm -rf \$PLCDIR"; trap "\$TRAPCMD" EXIT
export MINC_DEBUG_PREFIX=
export MINC_RWBIND=
export MINC_OPT_PTY=""
export MINC_CPUMASK=
export MINC_NETNS=
export MINC_PIVOT=0
[ "\$MINC_DEBUG" ] || export MINC_DEBUG=
export MINC_USE_DEV=
export MINC_BASEDIR=\$PLCDIR/rootfs
export MINC_TMPDIR=\$PLCDIR/tmp
mkdir \$MINC_BASEDIR \$MINC_TMPDIR
mount -t squashfs -o ro,loop,offset=\$OFFS \$SELF \$MINC_BASEDIR
TRAPCMD="umount \$MINC_BASEDIR;\$TRAPCMD"; trap "\$TRAPCMD" EXIT
sh \$MINC_BASEDIR/opt/libexec/minc-coat bind \$MINC_TMPDIR \$MINC_BASEDIR
TRAPCMD="sh \$MINC_BASEDIR/opt/libexec/minc-coat unbind \$MINC_TMPDIR;\$TRAPCMD"; trap "\$TRAPCMD" EXIT
trap '' INT
export MINC_DIRECT=1
sh \$MINC_BASEDIR/opt/libexec/minc-exec $COMMAND
exit \$?
EOF
cat $MINC_TMPDIR/polecat.sh $SFS > $OUTDIR/$OUTFILE
chmod a+x $OUTDIR/$OUTFILE
echo -n "done:" ; ls -sh $OUTDIR/$OUTFILE
exit 0