# Functions for managing prokit sessions # # Copyright (C) 2014 Patrick McDermott # # This file is part of the ProteanOS Development Kit. # # The ProteanOS Development Kit is free software: you can redistribute # it and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # The ProteanOS Development Kit is distributed in the hope that it # will be useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with the ProteanOS Development Kit. If not, see # . session_id= session_root= session_arch= session_plat= session_mountdir= session_sigs= _session_es= _session_mount() { local fs= local dir= local fstype= local options= while read fs dir fstype options; do [ "x${dir}" = 'x' ] && continue mount -t "${fstype}" -o "${options}" -- "${fs}" \ "${session_root}/${dir}" done <<-EOF $(profile_get_fstab "${session_arch}" "${session_plat}") EOF } _session_umount() { local fs= local dir= local fstype= local options= while read fs dir fstype options; do [ "x${dir}" = 'x' ] && continue # umount sometimes complains that the /dev file system is busy. # Here's a kludge to try to handle that. We better make sure # bind mounts get unmounted; otherwise, `rm -Rf ${root}` can be # painful. while ! umount -- "${session_root}/${dir}"; do sleep 1 done done <<-EOF $(profile_get_fstab "${session_arch}" "${session_plat}" | \ sed -n '1!G;h;$p') EOF } session_end() { trap : ${session_sigs} # Unregister the session. profile_bind_umount "${session_arch}" "${session_plat}" \ "${session_mountdir}" \ "${session_root}/prokit/sessions/${session_id}/wd" rmdir -- "${session_root}/prokit/sessions/${session_id}/wd" rmdir -- "${session_root}/prokit/sessions/${session_id}" if ! mutex_is_unlockable "${session_root}/prokit/sessions.lock"; then if ! mutex_timedlock "${session_root}/prokit/sessions.lock" 5 then error "$(get_msg 'cant_lock_sessions')" trap - ${session_sigs} return 1 fi fi # Clear the sessions pool. If there are no more sessions, unmount the # file systems. if rmdir -- "${session_root}/prokit/sessions" 2>/dev/null; then _session_umount fi mutex_unlock "${session_root}/prokit/sessions.lock" trap - ${session_sigs} return 0 } _session_handle_sig() { local sig="${1}" shift 1 _session_es=$((128 + ${sig})) } _session_set_sigs() { local i= local sig= # We need the signal *number* in the signal handler. The only portable # and easy way to get the number of a named signal is to search for it # as in the following loop hack. i=0 session_sigs='' while [ ${i} -lt 127 ]; do i=$((${i} + 1)) sig="$(kill -l ${i} 2>/dev/null)" || continue case "${sig}" in 'HUP' | 'INT' | 'QUIT' | 'ABRT' | 'ALRM' | 'TERM') session_sigs="${session_sigs} ${i}" trap "_session_handle_sig ${i}" ${i} ;; esac done } session_begin() { local root="${1}" local mountdir="${2}" local atexit="${3}" local installing="${4}" shift 4 rand session_id=${rand_x} session_root="${root}" session_arch="$(cat -- "${root}/etc/proteanos_arch")" session_plat="$(cat -- "${root}/etc/proteanos_plat")" session_mountdir="${mountdir}" [ -d "${session_root}/prokit" ] || mkdir -- "${session_root}/prokit" if [ -f "${session_root}/prokit/installing" ] && ! ${installing}; then error "$(get_msg 'install_running')" return 1 fi _session_set_sigs if ! mutex_timedlock "${session_root}/prokit/sessions.lock" 5; then error "$(get_msg 'cant_lock_sessions')" trap - ${session_sigs} return 1 fi # Check for a sessions pool. if [ -d "${session_root}/prokit/sessions" ]; then if ! profile_file_systems_mounted "${session_root}" \ "${session_arch}" "${session_plat}"; then # If a sessions pool exists but the file systems aren't # mounted, clean up the old sessions and mount the file # systems. rmdir -- "${session_root}/prokit/sessions/"* _session_mount fi else # If the sessions pool doesn't exist, create it and mount the # file systems. mkdir -- "${session_root}/prokit/sessions" _session_mount fi # Register the session. mkdir -- "${session_root}/prokit/sessions/${session_id}" mkdir -- "${session_root}/prokit/sessions/${session_id}/wd" profile_bind_mount "${session_arch}" "${session_plat}" \ "${session_mountdir}" \ "${session_root}/prokit/sessions/${session_id}/wd" mutex_unlock "${session_root}/prokit/sessions.lock" return 0 } session_id() { printf '%d\n' ${session_id} return 0 } session_dir() { printf '/prokit/sessions/%d\n' ${session_id} return 0 } session_exec() { local args= local session_dir= _session_es=0 args='' for arg in "${@}"; do arg="'$(printf '%s\n' "${arg}" | sed "s/'/'\\\\''/g")'" args="${args} ${arg}" done session_dir="/prokit/sessions/${session_id}/wd" chroot "${session_root}" /bin/sh -c "cd ${session_dir}; ${args}" || \ return ${?} return ${_session_es} }