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