portbuilder

Check-in [e14e6e7adf]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Import first portbuild2 code
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA1:e14e6e7adfbd51590c6d0e4d4d0fa4e8aee54064
User & Date: bapt 2012-07-07 14:12:37
Context
2012-07-07
14:12
Import first portbuild2 code Leaf check-in: e14e6e7adf user: bapt tags: trunk
2012-06-08
11:51
initial empty check-in check-in: cb113d9671 user: bapt tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Added cli.sh.





>
>
1
2
#!/bin/sh
echo "$@" | nc localhost 4444

Added nscripts/minitor.sh.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/sh

version=1

myself=$0
mtime=$(stat -f "%m" $myself)
nbcpus=$(/sbin/sysctl -n hw.ncpu)
osreldate=$(/sbin/sysctl -n kern.osreldate)
arch=$(/sbin/sysctl -n hw.machine)
hostname=$(hostname)
jobdir="/usr2/portbuild/pids"
builddir="/usr3/pkgbuild/builds"

[ -d ${jobdir} ] || mkdir -p ${jobdir}
[ -d ${builddir} ] || mkdir -p ${builddir}
logger -t monitor "Starting"
while :; do
        new=$(stat -f "%m" $myself)
        [ "$new" != "$mtime" ] && exec $myself
        newver=$(echo "code version" | nc localhost 4444)
        [ "$newver" != "$version" ] && echo "code get ${hostname}" | nc localhost 4444
#       jot ${nbcpus} | while read id; do
#               daemon -f -p ${jobdir}/${id}.pid \
#               /usr2/build/scripts/worker.sh ${builddir}
#       done
        sleep 30
done

Added nscripts/worker.sh.

















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/bin/sh

myself=$0
mtime=$(stat -f "%m" $myself)
myarch=$(/sbin/sysctl -n hw.machine)
hostname=$(hostname)
builddir=$1
# 30 min
timeout=1800

run_job() {
        logger -t worker "running job $1"
        logger -t worker "job $1 done"
}

setup_build() {
        logger -t worker "setting up $1"
        mkdir -p ${builddir}/$1
        echo "build setup $hostname $1" | nc localhost 4444
        local timer=0
        while ! test -f /usr/pkgbuild/builds/$1/done; do
                sleep 5
                timer=$((timer + 5))
                if [ $timer -gt $timerout ]; then
                        logger -t worker "aborting $1 setup"
                        echo "build abort $hostname $1" | nc localhost 4444
                        rm -rf ${builddir}/$1/
                        return
                fi
        done
        logger -t worker "setup $1 successful"
}

logger -t worker "Starting"
while :; do
        local activity=0
        new=$(stat -f "%m" $myself)
        [ "$new" != "$mtime" ] && exec $myself
        # cleanup old builds no longer available upstream
        for b in ${builddir}/*; do
                [ -f ${b}/keep ] && continue
                touch ${b}/keep
                res=$(echo "build exists ${b%%*/}" | nc localhost 4444)
                if [ "$res" = "no" ]; then
                        logger -t worker "Destroying old build"
                        activity=1
                        rm -rf $b
                fi
                [ -f ${b}/keep ] && rm -f ${b}/keep
        done
        [ ${activity} -eq 1 ] && continue
        # check if there are new builds to setup
        echo "build list ${myarch}" | while read a; do
                if [ ! -d ${builddir}/builds/$a ]; then
                        activity=1
                        setup_build $a
                        break;
                fi
        done
        [ ${activity} -eq 1 ] && continue
        echo "job list ${hostname} ${myarch}" | while read j; do
                res=$(echo "job take ${hostname} $j" | nc localhost 4444)
                if [ "$res" = "OK" ]; then
                        activity=1
                        run_job $j
                        break;
                fi
        done
        [ ${activity} -eq 1 ] && continue
        sleep 10
done

Added portbuild.conf.













>
>
>
>
>
>
1
2
3
4
5
6
mountbase=/a/build/
pool=a
codebase=/home/bapt/pb/com/scripts/
nodebase=/home/bapt/pb/com/nodescripts/
portsfs=a/snap/ports-head
srcfsbase=a/snap/

Added qmanager/phmgr.sh.





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
#!/bin/sh

# no command should get longer than 3 hours
timeout=10800

/usr/sbin/daemon -u ports-amd64 -f -c /usr/local/bin/socat -ly -lp "com" \
	-t ${timeout} -d -d \
	-L ~ports-amd64/com.lock \
	-d TCP-LISTEN:4444,fork,reuseaddr,retry \
	EXEC:/home/bapt/pb/com/scripts/dispatch.sh,stderr

Added scripts/common.shlib.















































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#!/bin/sh

zfsns="org.freebsd.portbuild"
tunneldir=${mountbase}/tunnels

[ -d ${tunneldir} ] || mkdir -p ${tunneldir}

if [ ! -f ${mountbase}/sql ]; then
        echo ".timeout 100
CREATE TABLE IF NOT EXISTS nodes (name TEXT NOT NULL UNIQUE, osversion INTEGER, arch TEXT, online INTEGER DEFAULT 0,  ncpu INTEGER);
CREATE TABLE IF NOT EXISTS builds (id TEXT NOT NULL UNIQUE, state TEXT NOT NULL DEFAULT 'creating', arch TEXT NOT NULL, starttime INTEGER DEFAULT 0);
" > ${mountbase}/sql
fi

# Error functions

err() {
        echo "$@"
        exit 0
}

enosuch() { err "No such $1 $2"; }
eexists() { err "$1 $2 already exists"; }

eargs() {
        case $# in
        0) err "No arguments expected" ;;
        1) err "1 argument expected: $1" ;;
        *) err "$# arguments expected: $@" ;;
        esac
}

# helpers

sql() {
        [ $# -eq 0 ] && eargs sql_code
        sqlite3 -init ${mountbase}/sql ${mountbase}/db.sqlite "$@"
}

sshopts="-q -o StrictHostKeyChecking=no -o HashKnownHosts=no -o PreferredAuthentications=publickey -o ServerAliveInterval=60 -o ServerAliveCountMax=3"

# All the build environment code
env_get_fs() {
        zfs list -t filesystem -H -o ${zfsns}:type,${zfsns}:name,name | \
                awk '/^env[[:space:]]'$1'/ { print $3 }'
}

fs_exists() {
        [ $# -ne 1 ] && eargs fs
        zfs list -Ht filesystem -o name $1 >/dev/null 2>&1 && return 0
        return 1
}

env_exists() {
        local name=$1
        zfs list -t filesystem -H \
                -o ${zfsns}:type,${zfsns}:name | \
                egrep -q "^env[[:space:]]$name$" && return 0
        return 1
} 

env_list() {
        [ $# -eq 0 ] || eargs
        printf "%-20s %-s\n" "NAME" "MAIL"
        zfs list -t filesystem -H \
                -o ${zfsns}:type,${zfsns}:name,${zfsns}:mail | \
                awk '/^env/ { printf("%-20s %s\n", $2, $3) }'
}

env_create() {
        [ $# -lt 2 ] && eargs name mail
        local name="$1"
        local mail="$2"
        shift 2
        env_exists ${name} && eexists Env $name
        sudo zfs create -p \
                -o ${zfsns}:type="env" \
                -o ${zfsns}:name="$name" \
                -o ${zfsns}:mail="$mail" \
                -o mountpoint=${mountbase}/${name} a/build/${name} || err "Not able to create FS"
        echo "build created"
}
        
env_destroy() {
        [ $# -ne 1 ] && eargs name
        local name=$1
        env_exists ${name} || enosuch env ${name}
        local base=$(env_get_fs ${name})
        [ -z ${base} ] && err "Could not get zfs base"
        sudo zfs destroy -R ${base} || err "Enable to destroy build"
        echo "build destroyed sucessfully"
}
 
# All the run environment code

run_get_fs() {
        zfs list -t filesystem -H -o ${zfsns}:type,${zfsns}:name,name | \
                awk '/^run[[:space:]]'$1'/ { print $3 }'
}

run_exists() {
        local name=$1
        zfs list -t filesystem -H \
                -o ${zfsns}:type,${zfsns}:id | \
                egrep -q "^run[[:space:]]$name$" && return 0
        return 1
} 

run_list() {
        local envname=$1
        if [ -n "${envname}" ]; then
                printf "%-20s %-15s %7s %s\n" "RUNNAME" "ID" "STATUS" "PATH"
                zfs list -t filesystem -H \
                        -o ${zfsns}:type,${zfsns}:env,${zfsns}:name,${zfsns}:id,${zfsns}:status,mountpoint  | \
                        awk '/^run[[:space:]]'$envname'/ { printf("%-20s %-15s %-7s %s\n", $3, $4, $5, $6) }'
        else
                printf "%-20s %-20s %-15s %-7s %s\n" "ENVNAME" "RUNNAME" "ID" "STATUS" "PATH"
                zfs list -t filesystem -H \
                        -o ${zfsns}:type,${zfsns}:env,${zfsns}:name,${zfsns}:id,${zfsns}:status,mountpoint | \
                        awk '/^run/ { printf("%-20s %-20s %-15s %-7s %s\n", $2, $3, $4, $5, $6) }'
        fi
}

run_create() {
        [ $# -ne 3 ] && eargs env_name src_version arch
        local envname=$1
        local version=$2
        local arch=$3
        local id=$(date +%Y%m%d%H%M%S)
        env_exists ${envname} || enosuch env ${envname}
        local srcfs=$(echo ${srcfsbase}/src-${version}/src | sed -e "s,//,/,g")
        fs_exists ${srcfs} || enosuch version ${version}
        sudo zfs create -p \
                -o ${zfsns}:type="run" \
                -o ${zfsns}:name="${version}-${arch}" \
                -o ${zfsns}:id="${id}" \
                -o ${zfsns}:env="${envname}" \
                -o ${zfsns}:status="new" \
                -o ${zfsns}:arch="${arch}" \
                -o ${zfsns}:version="${version}" \
                a/build/${envname}/${version}-${arch}-${id} || err "Not able to create FS"
        sudo zfs snapshot ${srcfs}@${id}
        sudo zfs clone  \
                -o ${zfsns}:type="src" \
                ${srcfs}@${id} \
                a/build/${envname}/${version}-${arch}-${id}/src
        sudo zfs snapshot ${portsfs}@${id}
        sudo zfs clone \
                -o ${zfsns}:type="ports" \
                ${portsfs}@${id} \
                a/build/${envname}/${version}-${arch}-${id}/ports                                                                                                        
        echo "run portsupdate ${envname} ${version} ${arch} to update the ports tree snapshot"
        echo "run srcupdate ${envname} ${vervion} ${arch} to update the srcs snapshot"
        echo "run makeworld ${envname} ${version} ${arch} to create a new world"
        echo "run makebindist ${envname} ${version} ${arch} to create a new world"
        echo "run prepare ${envname} ${version} ${arch} to create the src and ports archives"
        echo "run start ${envname} ${version} ${arch} to start building packages"
}
                
run_makeworld() {
        [ $# -ne 2 ] && eargs envname runname
        local envname=$1
        local runname=$2
        shift 2
        eval `zfs list -rHd1 -t filesystem \
                -o ${zfsns}:type,${zfsns}:env,${zfsns}:name,mountpoint,name -s ${zfsns}:id \
                a/build/${envname} | \
                awk -v env=${envname} -v run=${runname} '($1 == "run" && $2 == env && $3 == run) { mnt=$4; fs=$5 } END { print "mnt="mnt"\nfs="fs }'`
        [ -z ${mnt} ] && err "Enable to determine mountpoint for ${runname} in env ${envname}"
        [ -z ${fs} ] && err "Enable to determine filesystem for ${runname} in env ${envname}"
        [ -d ${mnt}/src ] || err "No source tree installed"
        arch=$(zfs get -H -o value ${zfsns}:arch ${fs})
        sudo ${codebase}/makeworld.sh ${mnt} ${arch} || err "Failed to make world"
        echo "World successfully build and installed you have a last chance to modify it"
}
        
run_packall() {
        [ $# -ne 2 ] && eargs envname runname
        local envname=$1
        local runname=$2
        shift 2
        mnt=`zfs list -rHd1 -t filesystem \
                -o ${zfsns}:type,${zfsns}:env,${zfsns}:name,mountpoint,name -s ${zfsns}:id \                                                                             
                a/build/${envname} | \
                awk -v env=${envname} -v run=${runname} '($1 == "run" && $2 == env && $3 == run) { mnt=$4; fs=$5 } END { print mnt }'`
        [ -d ${mnt} ] || err "Enable to determine mountpoint for ${runname} in env ${envname}"
        [ -d ${mnt}/world ] || err "Enable to determine mountpoint for ${runname} in env ${envname}"
        [ -d ${mnt}/src ] || err "Enable to determine mountpoint for ${runname} in env ${envname}"
        [ -d ${mnt}/ports ] || err "Enable to determine mountpoint for ${runname} in env ${envname}"
        rm -f ${mnt}/bindist.tbz ${mnt}/ports.tbz ${mnt}/src.tbz
        sudo tar cfCj ${mnt}/.bindist.tbz ${mnt}/world . &
        tar cfCj ${mnt}/.ports.tbz ${mnt} ports &
        tar cfCj ${mnt}/.src.tbz ${mnt} &
        wait
        wait
        wait
}
                
run_destroy() {
        [ $# -ne 1 ] && eargs name
        local name=$1
        run_exists ${name} || enosuch run ${name}
        local base=$(run_get_fs ${name})
        [ -z ${base} ] && err "Could not get zfs base"
        sudo zfs destroy -R ${base} || err "Enable to destroy run"
        echo "run destroyed sucessfully"
}
        
online() {
        printf "%-40s %-7s %-7s %s\n" "NAME" "ARCH" "VERSION" "LAST SEEN"
        sql "select name, arch, osversion, online from nodes" | \
                awk -F\| '{ printf("%-40s %-7s %-7s %s\n", $1, $2, $3, $4) }'
}
                
# Code for ssh tunnels
tunnel_running() {
        [ $# -ne 1 ] && eargs hostname
        if [ -f ${tunneldir}/${host}.pid ]; then
                pgrep -q -F ${tunneldir}/${host}.pid && return 0
        fi
        return 1
}
        
tunnel_start() {
        [ $# -ne 1 ] && eargs hostname                                                                                                                                   
        local host=$1                                                                                                                                                    
        tunnel_running ${host} && err "${host} tunnel already running"
        echo "Starting tunnel ${host}"
        daemon -f -p ${tunneldir}/${host}.pid -c ${codebase}/runssh.sh ${host}
#       ${codebase}/runssh.sh ${1} ${tunneldir}
}
                
tunnel_stop() {
        [ $# -ne 1 ] && eargs hostname
        local host=$1
        tunnel_running ${host} || err "${host} tunnel is not running"
        echo "Stopping tunnel ${host}"
        pkill -SIGINT -F ${tunneldir}/${host}.pid
        sql "update nodes set online=0 where name='${host}'"
}
            
tunnel_list() {
        [ $# -ne 0 ] && eargs
        [ ! -f ${tunneldir}/hosts ] && return
        while read host; do
                local state="off"
                echo -n "tunnel $host: "
                tunnel_running ${host} && echo "running" || echo "not running"
        done < ${tunneldir}/hosts
}
        
tunnel_add() {
        [ $# -ne 1 ] && eargs hostname  
        local name=$1
        if [ -f ${tunneldir}/hosts ]; then                                                                                                                               
                egrep -q "^${name}$" ${tunneldir}/hosts && err "${name} already added"
        fi
        echo "${name}" >> ${tunneldir}/hosts
}
        
tunnel_startall() {
        [ $# -ne 0 ] && eargs
        [ ! -f ${tunneldir}/hosts ] && return                                                                                                                            
        while read host; do
                tunnel_running ${host} || tunnel_start ${host}
        done < ${tunneldir}/hosts
}

tunnel_stopall() {
        [ $# -ne 0 ] && eargs
        [ ! -f ${tunneldir}/hosts ] && return
        while read host; do
                tunnel_running ${host} && tunnel_stop ${host}
        done < ${tunneldir}/hosts
}
        
tunnel_del() {
        [ $# -ne 1 ] && eargs hostname
        [ ! -f ${tunneldir}/hosts ] && return
        local name=$1
        egrep -q "^${name}$" ${tunneldir}/hosts || enosuch hostname ${name}
        tunnel_running ${name} && tunnel_stop ${name}
        sed -i '' -e "/^${name}$/d" ${tunneldir}/hosts
}
code_version() {
        [ $# -ne 0 ] && eargs
        sed -n -e "s/^version=\(.*\)/\1/p" ${nodebase}/monitor.sh
}

code_get() {
        [ $# -ne 1 ] && eargs hostname
        local name=$1
        rsync -rtl -e ssh ${nodebase}/ ${name}:/usr2/build/scripts
}

Added scripts/dispatch.sh.





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/sh

read data

set -- ${data}

. /usr/local/etc/portbuild.conf
. ${codebase}/common.shlib

cmd=$1
shift
test -x /home/bapt/pb/com/scripts/$cmd.sh && {
        /home/bapt/pb/com/scripts/$cmd.sh $@
        exit 0
}

case ${cmd} in
        ping)
                ping $@
                ;;
        online)
                online
                ;;
        *)
                subcmd=$1
                shift
                ${cmd}_${subcmd} $@ || err "No such command"
                ;;
esac

Added scripts/makeworld.sh.















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/sh

if [ `id -u` -ne 0 ]; then
        echo "needs to be run as root"
        exit 1
fi
if [ $# -ne 2 ]; then
        echo "needs to arguments: <path> <arch>"
        exit 1
fi
mnt=$1
arch=$2
shift 2
if [ ! -d ${mnt} ]; then
        echo "path not found ${mnt}"
        exit 1
fi
if [ ! -d ${mnt}/src ]; then
        echo "no sources found"
        exit 1
fi
export TARGET_ARCH=${arch}
# Workaround needed for zfs - 20090321 erwin (XXXbapt: unusure this is still needed)
export NO_FSCHG=1
__MAKE_CONF=/dev/null
[ -f ${mnt}/make.conf ] && __MAKE_CONF=${mnt}/make.conf
export __MAKE_CONF
SRCCONF=/dev/null
[ -f ${mnt}/src.conf ] && SRCCONF=${mnt}/make.conf
cd ${mnt}/src && make -j8 buildworld || exit 1
DESTDIR=${mnt}/world
[ -d ${mnt}/world ] && rm -rf ${mnt}/world
mkdir -p ${DESTDIR}
export NEWSPARC_TIMETYPE=__int64_t
make installworld DESTDIR=${DESTDIR} || exit 1

make DESTDIR=${DESTDIR} distrib-dirs && \
        make DESTDIR=${DESTDIR} distribution || exit 1

Added scripts/runssh.sh.









































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/sh

. /usr/local/etc/portbuild.conf
. ${codebase}/common.shlib

norestart=0
sshpid="-1"

die() {
        trap SIGCHLD
        logger -t tunnelssh "Stopping ${name}"
        # disabling trap
        trap SIGINT
        trap SIGTERM
        trap SIGKILL
        trap EXIT
        [ $sshpid != -1 ] && kill -15 $sshpid
        exit 0
}

startssh() {
        logger -t tunnelssh "Starting tunnel ${name}"
        sql "insert or ignore into nodes (name) values ('$name')"
        ssh ${sshopts} ${name} "${updatecmd}" | \
                sed -e 's/^M//g' | while read osversion ncpu arch; do
                        sql "update nodes set ncpu=${ncpu}, osversion=${osversion}, arch=trim('arch'), online=datetime('now') where name='${name}'"
                done
        ssh ${sshopts} ${name} "mkdir -p /usr2/portbuild/pids"
        ssh ${sshopts} ${name} "pgrep -q -F /usr2/portbuild/pids/monitor.pid >/dev/null 2>&1" || \
                rsync -rtl -e ssh ${nodebase}/ ${name}:/usr2/portbuild/nscripts
        ssh ${sshopts} ${name} "/usr/sbin/daemon -f -c -p /usr2/portbuild/pids/monitor.pid /usr2/portbuild/nscripts/monitor.sh"
        trap sshdead SIGCHLD
        ssh ${sshopts} -N -R 4444:localhost:4444 ${name} &
        sshpid=$!
}

sshdead() {
        trap SIGCHLD
        sql "update nodes set online=0 where name='${name}'"
        logger -t tunnelssh "tunnel ${name} dead"
        sleep 5
        trap sshdead SIGCHLD
        startssh
}

trap die SIGINT SIGTERM SIGKILL EXIT

name=$1
startssh
while :; do
        wait
done