3 # taskd - Clone repositories on request
5 # taskd is Girocco mirroring servant; it processes requests for clones
6 # of given URLs received over its socket.
8 # When a request is received, new process is spawned that sets up
9 # the repository and reports further progress
10 # to .clonelog within the repository. In case the clone fails,
11 # .clone_failed is touched and .clone_in_progress is removed.
14 # Alice sets up repository and touches .cloning
15 # Alice opens connection to Bob
16 # Alice sends project name through the connection
17 # Bob opens the repository and sends error code if there is a problem
18 # Bob closes connection
19 # Alice polls .clonelog in case of success.
20 # If Alice reads "@OVER@" from .clonelog, it stops polling.
22 # Ref-change protocol:
23 # Alice opens connection to Bob
24 # Alice sends ref-change command for each changed ref
25 # Alice closes connection
26 # Bob sends out notifications
28 # Based on perlipc example.
35 use POSIX
":sys_wait_h";
46 my $progname = basename
($0);
48 sub logmsg
{ print '['.(scalar localtime)."] $progname $$: @_\n" }
50 my $NAME = $Girocco::Config
::chroot.'/etc/taskd.socket';
51 my $uaddr = sockaddr_un
($NAME);
53 socket(Server
, PF_UNIX
, SOCK_STREAM
, 0) or die "socket: $!";
55 bind(Server
, $uaddr) or die "bind: $!";
56 listen(Server
, SOMAXCONN
) or die "listen: $!";
57 chmod 0666, $NAME or die "chmod: $!";
63 while (($waitedpid = waitpid(-1, WNOHANG
)) > 0) {
64 logmsg
"reaped $waitedpid" . ($? ?
" with exit $?" : '');
66 $SIG{CHLD
} = \
&REAPER
; # loathe sysV
69 $SIG{CHLD
} = \
&REAPER
; # Apollo 440
75 if (not defined $pid) {
76 logmsg
"cannot fork: $!";
80 return; # I'm the parent
83 $SIG{CHLD
} = 'DEFAULT';
85 open STDIN
, "<&Client" or die "can't dup client to stdin";
86 open STDOUT
, ">&Client" or die "can't dup client to stdout";
92 my $proj = Girocco
::Project
->load($name);
93 $proj or die "failed to load project $name";
94 $proj->{clone_in_progress
} or die "project $name is not marked for cloning";
95 $proj->{clone_logged
} and die "project $name is already being cloned";
96 print STDERR
"cloning $name\n";
97 open STDOUT
, '>', "$Girocco::Config::reporoot/$name.git/.clonelog" or die "cannot open clonelog: $!";
98 open STDERR
, ">&STDOUT";
99 open STDIN
, '<', '/dev/null';
100 exec "$Girocco::Config::basedir/taskd/clone.sh", "$name.git" or die "exec failed: $!";
105 my ($username, $name, $oldrev, $newrev, $ref) = split(/\s+/, $arg);
107 my $proj = Girocco
::Project
->load($name);
108 $proj or die "failed to load project $name";
111 if ($username && $username !~ /^%.*%$/) {
112 $user = Girocco
::User
->load($username);
113 $user or die "failed to load user $username";
116 print STDERR
"ref-change $username $name ($ref: $oldrev -> $newrev)\n";
117 open STDIN
, '<', '/dev/null';
118 Girocco
::Notify
::ref_change
($proj, $user, $ref, $oldrev, $newrev);
123 unless (accept(Client
, Server
)) {
124 logmsg
"accept failed: $!" unless $!{EINTR
};
127 logmsg
"connection on $NAME";
131 $inp or exit 0; # ignore empty connects
132 my ($cmd, $arg) = $inp =~ /^([a-zA-Z0-9-]+)\s+(.*)$/;
133 if ($cmd eq 'clone') {
135 } elsif ($cmd eq 'ref-change') {
138 die "unknown command: $cmd";