]> CyberLeo.Net >> Repos - CDN/j.git/blob - j
j, ipcc, ipcd: support gitk and gitka verbs, to spawn gitk on a git repo
[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     [ -e gitk ] || ln -s ipcc gitk
161     [ -e gitka ] || ln -s ipcc gitka
162   )
163 }
164
165 # Launch ipcd on jail
166 j_ipc_start() {
167   ipcd_pid="${jdir}/ipcd.pid"
168   su "${ORIG_USER}" "${jbase}/j/ipcd" "${jdir}" &
169   echo "${!}" > "${ipcd_pid}"
170 }
171
172 # Stop ipcd on jail
173 j_ipc_stop() {
174   ipcd_pid="${jdir}/ipcd.pid"
175   [ -f "${ipcd_pid}" ] && pid="$(cat "${ipcd_pid}")"
176   [ "${pid}" ] && kill -TERM ${pid}
177 }
178
179 # Is this a chroot?
180 j_is() {
181   eval $(j_params "${1}")
182   [ "${jerror}" ] && return 1 || return 0
183 }
184
185 # List available chroots
186 j_ls() {
187   ( cd "${jbase}"; ls -1 ) | while read jname
188   do
189     j_is "${jname}" && echo "${jname}"
190   done
191 }
192
193 # Chroot is 'up' if /dev/pts and /proc are mounted
194 j_up() {
195   jname="${1:-${jname}}"
196   eval "$(j_params "${jname}")"
197   [ "${jerror}" ] && wtf "${jerror}"
198   grep -q "^devpts ${jroot}/dev/pts devpts" /proc/mounts || return 1
199   grep -q "^proc ${jroot}/proc proc" /proc/mounts || return 1
200   return 0
201 }
202
203 # Poll chroot status (j_up)
204 j_status() {
205   [ -z "${1}" ] && set - $(j_ls)
206   while [ "${1}" ]
207   do
208     j_up "${1}" && meh "$(printf '\033[1;32mup\033[0m')" || meh "$(printf '\033[1;31mdown\033[0m')"
209     shift
210   done
211 }
212
213 # Mount /dev/pts and /proc in the chroot
214 j_start() {
215   jname="${1:-${jname}}"
216   j_up "${jname}" && return 0
217   eval "$(j_params "${jname}")"
218   meh "starting ${jname} ..."
219   mount -t devpts devpts "${jroot}/dev/pts"
220   mount -t proc proc "${jroot}/proc"
221
222   # Copy in ipcc and launch ipcd
223   j_ipc_setup
224   j_ipc_start
225
226   # Start all services in /etc/rcJ.d
227   j_root_eval "${jname}" '[ -d /etc/rcJ.d ] && ( ls -1 /etc/rcJ.d/* 2>&- | grep /S | sort | sed -e "s/$/ start/" | sh )'
228 }
229
230 # Execute command in chroot as root
231 j_root_eval() {
232   jname="${1:-${jname}}"
233   j_up "${jname}" || wtf "chroot not running"
234   eval "$(j_params "${jname}")"
235   shift
236   env -i ${jenv} /usr/bin/chroot "${jroot}" /bin/sh -c "${*}"
237 }
238
239 # Execute command in chroot
240 j_eval() {
241   jname="${1:-${jname}}"
242   j_up "${jname}" || wtf "chroot not running"
243   eval "$(j_params "${jname}")"
244   shift
245   env -i ${jenv} /usr/bin/chroot "${jroot}" /bin/su "${juser:-${USER}}" -c "${*}"
246 }
247
248 j_shell() {
249   jname="${1:-${jname}}"
250   eval "$(j_params "${jname}")"
251   j_eval "${jname}" "cd; exec ${jshell} -l"
252 }
253
254 # Unmount /dev/pts and /proc in the chroot
255 j_stop() {
256   jname="${1:-${jname}}"
257   eval "$(j_params "${jname}")"
258   j_up "${jname}" || return 0
259   meh "stopping ${jname} ..."
260
261   # Stop all services in /etc/rcJ.d
262   j_root_eval "${jname}" '[ -d /etc/rcJ.d ] && ( ls -1 /etc/rcJ.d/* 2>&- | grep /S | sort -r | sed -e "s/$/ stop/" | sh )'
263
264   # Terminate ipcd
265   j_ipc_stop
266
267   umount "${jroot}/proc"
268   umount "${jroot}/dev/pts"
269 }
270
271 case "${cmd}" in
272 init|create) j_init "${jname}" "${@}" ;;
273 ls|list) j_ls ;;
274 status) j_status "${jname}" "${@}" ;;
275 start) j_start "${jname}" ;;
276 shell|enter) j_shell "${jname}" ;;
277 eval) j_eval "${jname}" "${*}" ;;
278 stop) j_stop "${jname}" ;;
279 *) pebkac ;;
280 esac