]> CyberLeo.Net >> Repos - CDN/j.git/blob - j
j: move root dir to <name>/root so other things can be stored out of band
[CDN/j.git] / j
1 #!/bin/sh
2 # Copyright 2011 CyberLeo, All Rights Reserved
3 # http://wiki.cyberleo.net/wiki/CyberLeo/COPYRIGHT
4
5 # Need root beyond here
6 [ "$(id -u)" -eq 0 ] || exec sudo env "J_ARCH=${J_ARCH}" "J_BASE=${J_BASE}" "J_NAME=${J_NAME}" "J_USER=${J_USER:-${USER}}" "${0}" "${@}"
7
8 meh() { printf " \033[1;32m*\033[0m %s%s\n" "${jname:+${jname}: }" "${*}"; }
9 omg() { printf " \033[1;33m*\033[0m %s%s\n" "${jname:+${jname}: }" "${*}"; }
10 wtf() { printf " \033[1;31m*\033[0m %s%s\n" "${jname:+${jname}: }" "${*}"; exit 1; }
11 pebkac() {
12   [ "${*}" ] && printf "%s\n\n" "${*}"
13   cat <<EOF
14 Usage:
15   <command> <name> [arguments]
16   list
17   ls      list available chroots
18
19   status  show jail status
20
21   start   prepare an existing chroot for use
22
23   stop    undo what 'start' did
24
25   enter
26   shell   spawn a shell or command within the chroot
27
28   eval    evaluate a shell command line within the chroot
29
30 EOF
31   exit 1
32 }
33
34 cmd="$(basename "${0}")"
35 jarch="${J_ARCH:-$(uname -m)}"
36 jbase="${J_BASE:-$(realpath "$(dirname "${0}")/../")}"
37 jname="${J_NAME:-$(basename "${1}")}" #"
38 juser="${J_USER}"
39
40 # Remove chroot name from argument stack, if passed in
41 [ "${J_NAME}" ] || shift
42
43 # Propagate certain environment variables; sterilize the rest of the environment
44 jenv="
45   LANG=${LANG}
46   TERM=${TERM}
47   USER=${USER}
48 "
49
50 # Debian-specific init: prepare Debian chroot with debootstrap
51 j_init_debian() {
52   jdir="${1}"
53   suite="$(echo "${2:-squeeze}" | tr 'A-Z' 'a-z')"
54
55   # Validation
56   [ "$(which debootstrap 2>&-)" ] || pebkac "j_init_debian: debootstrap not found"
57   [ "${jdir}" ] || pebkac "j_init_debian: jdir must be specified"
58   [ ! -d "${jdir}" ] || pebkac "j_init_debian: jdir must not exist ('${jdir}')"
59   [ -d "$(dirname "${jdir}")" ] || pebkac "j_init_debian: parent of jdir must exist ('${jdir}')"
60
61   # Figure out arch
62   case "${jarch}" in
63   x86|i386) arch=i386 ;;
64   amd64|x86_64|x64) arch=amd64 ;;
65   *) pebkac "Unsupported arch '${jarch}'" ;;
66   esac
67
68   cmd="debootstrap --arch=${arch} --include=curl,file,less,locales,sudo,build-essential,libreadline-dev,zlib1g-dev '${suite}' '${jdir}'"
69   echo "Executing ${cmd}"
70   eval "${cmd}"
71   
72   # Make sure locales are generated on first start
73   mkdir -p "${jdir}/etc/rcJ.d"
74   cat > "${jdir}/etc/rcJ.d/S00localegen" <<"EOF"
75 #!/bin/sh
76 /bin/sed -i '/en_US/s/^# //' /etc/locale.gen
77 /usr/sbin/locale-gen
78 /bin/rm -f "${0}"
79 EOF
80   chmod 755 "${jdir}/etc/rcJ.d/S00localegen"
81 }
82
83 # Gentoo-specific init: prepare Gentoo chroot with stage3+portage tarballs
84 j_init_gentoo() {
85   arch="$(uname -m)"
86   base="http://distfiles.gentoo.org/releases/${arch}/autobuilds"
87   pointer="${base}/latest-stage3.txt"
88   # Fetch stage3
89   # Fetch portage
90   # Validate signatures
91   # Unpack stage3
92   # Unpack portage
93 }
94
95 # Create a new chroot, somehow
96 j_init() {
97   # Make sure this does NOT exist
98   jname="${1:-jname}"
99   dist="$(echo "${2:-debian}" | tr 'A-Z' 'a-z')"
100   jdir="${jbase}/${jname}"
101   [ -d "${jdir}" ] && pebkac "j_init: ${jname} already exists"
102   shift 2
103   case "${dist}" in
104   debian) j_init_debian "${jdir}" "${@}" ;;
105   gentoo) j_init_gentoo "${jdir}" "${@}" ;;
106   *) pebkac "Unsupported distro '${dist}'" ;;
107   esac
108 }
109
110 # Figure out and set chroot parameters; needed for all functions that follow
111 j_params() {
112   ( jname="${1:-jname}"
113
114     # Make sure jname is not empty
115     if [ -z "${jname}" ]
116     then
117       printf "jerror='%s'\n" "jname empty"
118       return 1
119     fi
120
121     # Given a chroot name, find and set up the chroot dir
122     jdir="${jbase}/${jname}"
123     jroot="${jdir}/root"
124     if [ ! -d "${jdir}" -o ! -d "${jroot}" ]
125     then
126       printf "jerror='%s'\n" "not a directory"
127       return 1
128     fi
129
130     # Where is the shell?
131     jshell=""
132     for shell in /bin/bash /usr/bin/bash /usr/local/bin/bash /bin/sh
133     do
134       if [ -f "${jroot}/${shell}" ]
135       then
136         jshell=${shell}
137         break
138       fi
139     done
140     if [ -z "${jshell}" ]
141     then
142       printf "jerror='%s'\n" "unable to locate usable shell; is this a jail?"
143       return 1
144     fi
145
146     printf "jerror='' jname='%s' jdir='%s' jroot='%s' jshell='%s'\n" "${jname}" "${jdir}" "${jroot}" "${jshell}"
147   )
148 }
149
150 # Is this a chroot?
151 j_is() {
152   eval $(j_params "${1}")
153   [ "${jerror}" ] && return 1 || return 0
154 }
155
156 # List available chroots
157 j_ls() {
158   ( cd "${jbase}"; ls -1 ) | while read jname
159   do
160     j_is "${jname}" && echo "${jname}"
161   done
162 }
163
164 # Chroot is 'up' if /dev/pts and /proc are mounted
165 j_up() {
166   jname="${1:-${jname}}"
167   eval "$(j_params "${jname}")"
168   [ "${jerror}" ] && wtf "${jerror}"
169   grep -q "^devpts ${jroot}/dev/pts devpts" /proc/mounts || return 1
170   grep -q "^proc ${jroot}/proc proc" /proc/mounts || return 1
171   return 0
172 }
173
174 # Poll chroot status (j_up)
175 j_status() {
176   [ -z "${1}" ] && set - $(j_ls)
177   while [ "${1}" ]
178   do
179     j_up "${1}" && meh "$(printf '\033[1;32mup\033[0m')" || meh "$(printf '\033[1;31mdown\033[0m')"
180     shift
181   done
182 }
183
184 # Mount /dev/pts and /proc in the chroot
185 j_start() {
186   jname="${1:-${jname}}"
187   j_up "${jname}" && return 0
188   eval "$(j_params "${jname}")"
189   meh "starting ${jname} ..."
190   mount -t devpts devpts "${jroot}/dev/pts"
191   mount -t proc proc "${jroot}/proc"
192
193   # Start all services in /etc/rcJ.d
194   j_root_eval "${jname}" '[ -d /etc/rcJ.d ] && ( ls -1 /etc/rcJ.d/* 2>&- | grep /S | sort | sed -e "s/$/ start/" | sh )'
195 }
196
197 # Execute command in chroot as root
198 j_root_eval() {
199   jname="${1:-${jname}}"
200   j_up "${jname}" || wtf "chroot not running"
201   eval "$(j_params "${jname}")"
202   shift
203   env -i ${jenv} /usr/bin/chroot "${jroot}" /bin/sh -c "${*}"
204 }
205
206 # Execute command in chroot
207 j_eval() {
208   jname="${1:-${jname}}"
209   j_up "${jname}" || wtf "chroot not running"
210   eval "$(j_params "${jname}")"
211   shift
212   env -i ${jenv} /usr/bin/chroot "${jroot}" /bin/su "${juser:-${USER}}" -c "${*}"
213 }
214
215 j_shell() {
216   jname="${1:-${jname}}"
217   eval "$(j_params "${jname}")"
218   j_eval "${jname}" "cd; exec ${jshell} -l"
219 }
220
221 # Unmount /dev/pts and /proc in the chroot
222 j_stop() {
223   jname="${1:-${jname}}"
224   eval "$(j_params "${jname}")"
225   j_up "${jname}" || return 0
226   meh "stopping ${jname} ..."
227
228   # Stop all services in /etc/rcJ.d
229   j_root_eval "${jname}" '[ -d /etc/rcJ.d ] && ( ls -1 /etc/rcJ.d/* 2>&- | grep /S | sort -r | sed -e "s/$/ stop/" | sh )'
230
231   umount "${jroot}/proc"
232   umount "${jroot}/dev/pts"
233 }
234
235 case "${cmd}" in
236 init|create) j_init "${jname}" "${@}" ;;
237 ls|list) j_ls ;;
238 status) j_status "${jname}" "${@}" ;;
239 start) j_start "${jname}" ;;
240 shell|enter) j_shell "${jname}" ;;
241 eval) j_eval "${jname}" "${*}" ;;
242 stop) j_stop "${jname}" ;;
243 *) pebkac ;;
244 esac