#!/bin/bash #------------------------------------------------------------------------------ # cl-builder # Copyright ©2009 Calculate Ltd. # # This program 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. # # This program 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 this program. If not, see . #------------------------------------------------------------------------------ # выбор строки перемонтирования разделов в зависимости от используемого модуля BUILDER=/mnt/builder if [[ -n `mount | grep " / type aufs"` ]]; then REMOUNT="mount -t aufs -o remount,br:/ none /" REMOUNTBUILDER="mount -t aufs -o remount,br:/ none $BUILDER" else REMOUNT="mount -t unionfs -o remount,dirs=/ unionfs /" REMOUNTBUILDER=":" fi TIMERUN=`date +%s` EMERGELOG=${BUILDER}/var/log/emerge.log TAILEMERGELOG="tail -f ${EMERGELOG}" #------------------------------------------------------------------------------ # Обновление Unionfs в течение сборки пакетов #------------------------------------------------------------------------------ watching() { $TAILEMERGELOG | while read line; do if [ `echo "$line" | awk -F: '{print $1;}'` -ge $TIMERUN ] && [ "`echo "$line" | grep -e "unemerge success" -e "completed emerge"`" ] then $REMOUNT &>/dev/null fi done } #------------------------------------------------------------------------------ # Монтируем ресурсы #------------------------------------------------------------------------------ mountres() { mount -o bind /var/calculate/remote ${BUILDER}/var/calculate/remote mount -t proc none ${BUILDER}/proc && mount -o bind /dev ${BUILDER}/dev && mount -t sysfs none ${BUILDER}/sys && mount -o bind /dev/pts ${BUILDER}/dev/pts && return 0 return 1 } #------------------------------------------------------------------------------ # Выполним emerge #------------------------------------------------------------------------------ runchroot() { touch $EMERGELOG watching & 2>/dev/null chroot $BUILDER /bin/bash --rcfile /usr/calculate/install/config/chroot.rc WATCHINGPID=`ps axo pid,cmd | sed -nr "s|^\s*([0-9]+)\s+${TAILEMERGELOG}.*|\1|p"` [ "${WATCHINGPID}" ] && kill -9 $WATCHINGPID &>/dev/null $REMOUNT &>/dev/null } #------------------------------------------------------------------------------ # Отмонтируем ресурсы #------------------------------------------------------------------------------ umountres() { # перебираем строку в обратном порядке MOUNTDIRS=`mount | grep -Po "${BUILDER}/[^ ]+" | sed "{N;s/\n/ /}"` for MOUNTDIR in $( echo $MOUNTDIRS | rev ) do umount $(echo $MOUNTDIR | rev) || exit done } #------------------------------------------------------------------------------ # Выполним проверки #------------------------------------------------------------------------------ checkrun() { if [[ `/usr/bin/id -u` -ne 0 ]] then echo "Only root can perform system building." exit; fi #не запустим если загрузка не в Scrach режиме if ! mount | grep /mnt/scratch &>/dev/null then echo "This program only works in the system, installed by Calculate with the option '--build'." exit; fi #не запустим второй раз if mount | grep "/dev/pts on /mnt/builder/dev/pts " &>/dev/null then if [ `ps ax | grep -v grep | grep -c "/bin/bash /usr/bin/cl-builder"` -gt 3 ]; then echo "This program is already run." exit; else umountres fi fi #не запустим из chroot if [ `mount | grep -c "devpts on /dev/pts "` -ne 1 ]; then echo "This program can't be run from Scratch layer." exit; fi } #------------------------------------------------------------------------------ # Выполним предварительные настройки #------------------------------------------------------------------------------ configure() { # Перенесем resolv.conf if [ -f /etc/resolv.conf ] then mkdir -p ${BUILDER}/etc cp /etc/resolv.conf ${BUILDER}/etc/ fi } checkrun configure $REMOUNTBUILDER &>/dev/null mountres && runchroot umountres ROOTDIR=/ UPDATE_DIRS="/boot /lib/modules /lib/firmware" #------------------------------------------------------------------------------ # Ask: whether to replace the old file #------------------------------------------------------------------------------ ask_replace() { [[ $REPLACE_ANSWER == "yes" ]] && return 0 [[ $REPLACE_ANSWER == "no" ]] && return 1 local destfile=$1 echo "File '$destfile' in builder is newer than in workspace" local line while true do echo -n "Do you want replace old file (Yes/No/All/None):" read line <&1 case $line in All|all) REPLACE_ANSWER=yes;return 0;; None|none) REPLACE_ANSWER=no;return 1;; Y*|y*) return 0 ;; N*|n*) return 1 ;; esac done } #------------------------------------------------------------------------------ # Compare modify time of the first and second file #------------------------------------------------------------------------------ test_newer() { # [[ file1 -nt file2 ]] not correct work with symbolic link, because # get modify time of target file if [[ -L $1 || -L $2 ]] then [[ `stat -c %Y $1` -gt `stat -c %Y $2` ]] else [[ $1 -nt $2 ]] fi } #------------------------------------------------------------------------------ # Compare modify time, ask user for update and update file #------------------------------------------------------------------------------ try_update_file() { [[ -e $2 || -L $2 ]] && test_newer $1 $2 && ask_replace $2 && cp -P $1 $2 } #------------------------------------------------------------------------------ # Find in first directory files and symbolic links with modify time great than # same files in the second directory #------------------------------------------------------------------------------ update_from_builder() { basesrc=${1%/} basedest=${2%/} shift 2 for place in $* do src=$basesrc/${place#/} dest=$basedest/${place#/} find $src -type f -o -type l | while read srcfile; do dstfile=${dest}/${srcfile#${src}/} try_update_file $srcfile $dstfile done done } update_from_builder $BUILDER $ROOTDIR $UPDATE_DIRS