diff --git a/clusterd b/clusterd index 5a0d3a7..e657052 100755 --- a/clusterd +++ b/clusterd @@ -302,6 +302,7 @@ our ($udp_peer_addr,$udp_peer_port); # ('141.14.12.12',1234) our %UDP_HANDLER= ( 'filedata' => \&udp_rx_filedata, + 'filedata.2' => \&udp_rx_filedata, 'amdtardata' => \&udp_rx_amdtardata, 'loadavg.2' => \&udp_rx_loadavg2, 'restart' => \&udp_rx_restart, @@ -381,23 +382,32 @@ sub push_file { my $st=Donald::FileInfo->lstat($filename); defined $st or return warn "$filename: $!\n"; - $st->type eq 'F' or die "$filename: not a plain file\n"; - $st->size<=65536 or die "$filename: to big for broadcast (max 65536 bytes)\n"; + my $rpc; + if ($st->type eq 'F') { + $rpc='filedata'; + $st->size<=65536 or die "$filename: to big for broadcast (max 65536 bytes)\n"; + if ($st->size==0) { + udp_broadcast_message($donald_s,$rpc,$st,0,''); + return; + } - if ($st->size==0) { - udp_broadcast_message($donald_s,'filedata',$st,0,''); + my $fh=new IO::File $filename,'<' or return warn "$filename: $!\n"; + my $i=0; + for (my $pos=0;$pos<$st->size;$pos+=1024) { + my $data; + defined $fh->sysread($data,1024) or return warn "$filename: $!\n"; + # warn "send bytes $pos to ",$pos+length($data),"\n"; + udp_broadcast_message($donald_s,$rpc,$st,$pos,$data); + ++$i % $BC_RATE or sleep 1; + } + } elsif ($st->type eq 'L') { + $rpc='filedata.2'; + udp_broadcast_message($donald_s,$rpc,$st,0,''); return; + } else { + die "file type not supported\n"; } - my $fh=new IO::File $filename,'<' or return warn "$filename: $!\n"; - my $i=0; - for (my $pos=0;$pos<$st->size;$pos+=1024) { - my $data; - defined $fh->sysread($data,1024) or return warn "$filename: $!\n"; - # warn "send bytes $pos to ",$pos+length($data),"\n"; - udp_broadcast_message($donald_s,'filedata',$st,$pos,$data); - ++$i % $BC_RATE or sleep 1; - } } our %CMD=( @@ -511,6 +521,54 @@ sub udp_rx_amdtardata { system '/sbin/make-automaps'; } +our ($machine,$SYS_lchown,$SYS_mknod,$lmtime_sub); +chomp($machine=`uname -m`); +if ($machine eq 'i686') { + $SYS_lchown=198; # __NR_lchown32 in /usr/include/asm/unistd.h + $SYS_mknod=14; # __NR_mknod +} elsif ($machine eq 'x86_64') { + $SYS_lchown=94; # __NR_lchown in /usr/include/asm-x86_64/unistd.h + $SYS_mknod=133; # __NR_mknod +} elsif ($machine eq 'alpha') { + $SYS_lchown=208; # SYS_lchown in /usr/include/syscall.h + $SYS_mknod=14; # SYS_mknod +} elsif ($machine eq 'amd64') { + $SYS_lchown=254; # SYS_lchown in /usr/include/syscall.h + $SYS_mknod=14; # SYS_mknod +} else { + warn "unknown machine type $machine: symlink ownership can't be set.\n"; + warn "unknown machine type $machine: named pipes,character and block devices can't be created\n"; +} +if ($machine eq 'x86_64') { + our $SYS_utimensat=280; # /usr/include/asm/unistd_64.h + our $AT_FDCWD=-100; # /usr/include/fcntl.h + our $UTIME_OMIT=(1<<30)-2; # /usr/include/bits/stat.h + our $AT_SYMLINK_NOFOLLOW=0x100; # /usr/include/fcntl.h + + $lmtime_sub=sub { + my ($path,$mtime)=@_; + my $tsa=pack 'qqqq',0,$UTIME_OMIT,$mtime,0; + syscall($SYS_utimensat,$AT_FDCWD,$path,$tsa,$AT_SYMLINK_NOFOLLOW)==0 or return warn "$path: failed to lmtime: $!\n"; + } +} else { + $lmtime_sub=sub { + my ($path,$mtime)=@_; + warn "$path: don't known how to change symlink mtime on target architecture\n"; + } +} + +sub lchown { + my ($uid,$gid,$path)=@_; + $SYS_lchown or return; + syscall($SYS_lchown,$path,$uid+0,$gid+0)==0 or return warn "$path: failed to lchown: $!\n"; +} + +sub lmtime { + my ($mtime,$path)=@_; + $lmtime_sub or return; + $lmtime_sub->($path,$mtime); +} + sub udp_rx_filedata { # set rx_filedata_done as a side effect @@ -530,6 +588,24 @@ sub udp_rx_filedata { return; } + if ($st_want->type eq 'L') { + if (!$st_is || $st_is->type ne 'L' || $st_is->target ne $st_want->target) { + $st_is and (unlink($filename) or return warn "$filename: failed to unlink: $!\n"); + symlink($st_want->target,$filename) or return warn "$filename: failed to create symlink: $!\n"; + lchown($st_want->uid,$st_want->gid,$filename); + lmtime($st_want->mtime,$filename); + warn "installed $filename -> ".$st_want->target."\n"; + } else { + if ($st_is->uid != $st_want->uid || $st_is->gid != $st_want->gid) { + lchown($st_want->uid,$st_want->gid,$filename); + } + if ($st_is->mtime != $st_want->mtime) { + lmtime($st_want->mtime,$filename); + } + } + return; + } + if (length($data) == $st_want->size) { # complete file in one broadcast my $fh=IO::File->new($tmp_filename,O_WRONLY|O_CREAT,0);