home *** CD-ROM | disk | FTP | other *** search
/ ftp.cse.unsw.edu.au / 2014.06.ftp.cse.unsw.edu.au.tar / ftp.cse.unsw.edu.au / pub / doc / languages / perl / nutshell / ch6 / receptionist < prev    next >
Encoding:
Text File  |  1992-10-18  |  4.9 KB  |  231 lines

  1. #!/usr/bin/perl
  2.  
  3. # Usage:
  4. #       receptionist [-d] [conf file]
  5. #       -d: debug
  6. #       conf file: configuration file
  7. #               (default file is /etc/recept.conf)
  8.  
  9. require 'sys/socket.ph';
  10. require 'sys/errno.ph';
  11. require 'sys/wait.ph';
  12. require 'getopts.pl';
  13.  
  14. $SIG{'CHLD'} = 'reapchild';
  15. $WNOHANG = defined &WNOHANG ? &WNOHANG : 1;
  16.  
  17. $sockaddr = 'S n a4 x8';
  18. $fileDescs = '';
  19. do Getopts('d');
  20. $debug = $opt_d;
  21.  
  22. ($conf) = @ARGV;
  23. $conf = "/etc/recept.conf" unless $conf;
  24.  
  25.     # Read the entries from the configuration file.
  26.  
  27. open(CONF, "<$conf") || die "open: $conf: $!";
  28. while (<CONF>) {
  29.     next if (/^#/ || /^$/);
  30.     ($service, $sockettype, $proto, 
  31.         $waitstatus, $uid, $server, @commandlist) = split;
  32.     $tmp = (getpwnam($uid))[2];
  33.     $uid = $tmp if defined $tmp;
  34.     $service .= "/$proto";
  35.     push (@services, $service);
  36.     $sockettype{$service} = $sockettype;
  37.     $proto{$service} = $proto;
  38.     $waitstatus{$service} = $waitstatus;
  39.     $uid{$service} = $uid;
  40.     $server{$service} = $server;
  41.     $commandlist[0] = $server unless @commandlist;
  42.     $command{$service} = "@commandlist";
  43. }
  44. close(CONF);
  45.  
  46.     # Begin each service in the conf file.
  47.  
  48. foreach $service (@services) {
  49.     &addBits(&startService($service));
  50. }
  51.  
  52.     # Main loop (never exits)
  53.  
  54. $| = 1;
  55. for (;;) {
  56.     print "fileDescs:  ", &printVec($fileDescs), "\n"
  57.     if $debug;
  58.     $nfound = select($rout = $fileDescs, undef, undef, undef);
  59.     if ($nfound == -1) {
  60.     if ($! == &EINTR) {
  61.         next;
  62.     }
  63.     else {
  64.         die "select: $!";
  65.     }
  66.     }
  67.  
  68.     print "rout:  ", &printVec($rout), ", " if $debug;
  69.     foreach $service (@services) {
  70.     if (vec($rout, $fileno{$service}, 1)) {
  71.         print "$service ready\n" if $debug;
  72.         &spawn($service);
  73.     }
  74.     }
  75. }
  76. die "Shouldn't ever get here!!!  Stopped";
  77.  
  78.     # Start an individual service.
  79.  
  80. sub startService {
  81.     local($serviceName) = @_;
  82.  
  83.     print "starting service $serviceName...\n" if ($debug);
  84.  
  85.     $protoName = $proto{$serviceName};
  86.     local($serv) = split(m#/#, $serviceName);
  87.     (($pname, $paliases, $proto) = getprotobyname($protoName))
  88.       || die "Couldn't get proto by name $protoName: $!";
  89.  
  90.     if ($serviceName =~ /\d+/) {
  91.     $port = $serviceName;
  92.     }
  93.     else {
  94.     print "Getting service from ($serv, $proto)\n"
  95.         if $debug;
  96.     (($name, $aliases, $port)
  97.         = getservbyname($serv, $protoName))
  98.       || die "Couldn't get by name $serviceName: $!";
  99.     }
  100.  
  101.     if ($sockettype{$serviceName} eq "stream") {
  102.     $socktype = &SOCK_STREAM;
  103.     }
  104.     elsif ($sockettype{$serviceName} eq "dgram") {
  105.     $socktype = &SOCK_DGRAM;
  106.     }
  107.     else {
  108.     $socktype = -1;
  109.     }
  110.  
  111.     $name = pack($sockaddr, &AF_INET, $port, "\0\0\0\0");
  112.     socket($service, &PF_INET, $socktype, $proto) || 
  113.         die "socket ($serviceName): $!";
  114.     print "binding to port $port.\n" if $debug;
  115.     bind($service, $name) || die "bind($serviceName): $!";
  116.     if ($socktype == &SOCK_STREAM) {
  117.     listen($service, 10) || die "listen($serviceName): $!";
  118.     }
  119.     $fileno{$service} = fileno($service);
  120. }
  121.  
  122.     # Utility functions to deal with select() bits.
  123.  
  124. sub addBits {
  125.     local($fd) = @_;
  126.     vec($fileDescs, $fd, 1) = 1;
  127. }
  128.  
  129. sub delBits {
  130.     local($fd) = @_;
  131.     vec($fileDescs, $fd, 1) = 0;
  132. }
  133.  
  134.     # Start a new server.
  135.  
  136. sub spawn {
  137.     local($service) = @_;
  138.     local($stream) = ($sockettype{$service} eq "stream");
  139.     local($fd);
  140.  
  141.     # Only datagram sockets can be 'wait'.
  142.  
  143.     local($wait)
  144.     = ($waitstatus{$service} eq "wait" && (! $stream));
  145.  
  146.     if ($wait) {
  147.     $fd = $service;
  148.     }
  149.     else {
  150.     accept($fd, $service) || die "accept: $!";
  151.     }
  152.  
  153.     print "Running: ", $command{$service}, "\n";
  154.     for (;;) {
  155.     $pid = fork;
  156.     last if defined $pid;
  157.     sleep 5;
  158.     }
  159.     if (! $pid) {
  160.     select($fd);
  161.     $| = 1;
  162.  
  163.     $inputStr = "<&" . fileno($fd);
  164.     $outputStr = ">&" . fileno($fd);
  165.  
  166.     close(STDIN);
  167.     open(STDIN, $inputStr) || die "open STDIN: $!";
  168.  
  169.     close(STDOUT);
  170.     open(STDOUT, $outputStr) || die "open STDOUT: $!";
  171.  
  172.     # Die can't print an error, since STDERR is closed.
  173.  
  174.     close(STDERR);
  175.     open(STDERR, $outputStr) || die;
  176.  
  177.     # Change uid, even on machines that only do setuid().
  178.  
  179.     $uid = $uid{$service};
  180.     ($<, $>) = ($uid,$uid) unless $>;
  181.  
  182.     # Insulate against any signals coming from above.
  183.  
  184.     setpgrp(0,$$);
  185.  
  186.     # Exec the daemon, lying to it about its name.
  187.     #  (Is it wrong to lie to a daemon?  Beats me.)
  188.  
  189.     $realname = $server{$service};
  190.     exec $realname split(' ', $command{$service});
  191.     exit 255;
  192.     }
  193.     else {
  194.     if ($wait) {
  195.         $serviceof{$pid} = $service;
  196.         &delBits($fileno{$service});
  197.     }
  198.     else {
  199.         close($fd);
  200.     }
  201.     }
  202. }
  203.  
  204.     # When a child dies, if it's a "wait" server, put the
  205.     # file descriptor for the child back in select mask.
  206.  
  207. sub reapchild {
  208.     while (1) {
  209.     print "Reaping child\n";
  210.     $pid = waitpid(-1,$WNOHANG);
  211.     last if ($pid < 1);
  212.     $service = $serviceof{$pid};
  213.     last unless $service;
  214.     print "$service restored\n" if $debug;
  215.     &addBits($fileno{$service});
  216.     }
  217. }
  218.  
  219.     # Debugging subroutine.
  220.  
  221. sub printVec {
  222.     local($v) = @_;
  223.     local($i, $result);
  224.  
  225.     for ($i = (8*length($v)) - 1; $i >= 0; $i--) {
  226.     $result .= (vec($v, $i, 1)) ? "1" : "0";
  227.     }
  228.     $result;
  229. }
  230.  
  231.