# 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" rmdir -- "${_session_root}/prokit" 2>/dev/null || : 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 installing="${3}" shift 3 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} }