home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / rescue / sbin / chkconfig < prev    next >
Text File  |  2006-11-29  |  17KB  |  737 lines

  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use Getopt::Long;
  5. use File::Temp 'tempfile';
  6.  
  7. my $initdir = '/etc/init.d';
  8. my $inetddir = '/etc/inetd.d';
  9. my $xinetddir = '/etc/xinetd.d';
  10.  
  11. my %to_d = (
  12.   '0' => 'rc0.d', '1' => 'rc1.d', '2' => 'rc2.d', '3' => 'rc3.d',
  13.   '4' => 'rc4.d', '5' => 'rc5.d', 'S' => 'rcS.d', 'B' => 'boot.d'
  14. );
  15.  
  16. # which files to skip in $initdir
  17. my %skips_rc = map {$_ => 1} qw {rc rx skeleton powerfail boot halt reboot single boot.local halt.local};
  18.  
  19. # which services are known
  20. my %known_rc = ();
  21. my %known_inetd = ();
  22. my %known_xinetd = ();
  23. my %known_all = ();
  24.  
  25. #
  26. # get the contents of a directory
  27. #
  28. sub ls {
  29.   my $dir = shift;
  30.  
  31.   local *D;
  32.   return () unless opendir(D, $dir);
  33.   my @ret = grep {$_ ne '.' && $_ ne '..'} readdir(D);
  34.   closedir D;
  35.   return @ret;
  36. }
  37.  
  38. #
  39. # unify an array
  40. #
  41. sub unify {
  42.   my %h = map {$_ => 1} @_;
  43.   return grep {delete $h{$_}} @_;
  44. }
  45.  
  46.  
  47. ##################################################################
  48. #                         runlevel part
  49. ##################################################################
  50.  
  51. # which services are currently on? this is a cache to speed things up
  52. # initialized by initlinks_rc(), used in getreal_rc()
  53. my %links = ();
  54. my %links_unknown = ();
  55.  
  56. #
  57. #
  58. # calculate the default runlevels of a service by reading the
  59. # insserv header. regexes taken from insserv.c
  60. #
  61. my %getdef_rc_cache = ();
  62.  
  63. sub getdef_rc {
  64.   my $s = shift;
  65.  
  66.   return $getdef_rc_cache{$s} if exists $getdef_rc_cache{$s};
  67.   my $file = "$initdir/$s";
  68.   local *F;
  69.   if (!open(F, "<$file")) {
  70.     print STDERR "$file: $!\n";
  71.     $getdef_rc_cache{$s} = undef;
  72.     return undef;
  73.   }
  74.   while (<F>) {
  75.     chomp;
  76.     if (/^#[[:blank:]]*default[-_]?start:[[:blank:]]*([[:print:][:blank:]]*)/i) {
  77.       my $ret = $1;
  78.       close F;
  79.       $ret =~ s/[[:blank:]]+//g;
  80.       my @ret = split('', $ret);
  81.       $ret = '';
  82.       for (sort @ret) {
  83.     $_ = uc($_);
  84.     $ret .= $_ if /[0123456SB]/;
  85.       }
  86.       $getdef_rc_cache{$s} = $ret;
  87.       return $ret;
  88.     }
  89.   }
  90.   $getdef_rc_cache{$s} = '35';
  91.   return '35';
  92. }
  93.  
  94. #
  95. # calculate the required services by reading the insserv header.
  96. # regexes taken from insserv.c
  97. #
  98. sub getdeps_rc {
  99.   my $s = shift;
  100.  
  101.   my $file = "$initdir/$s";
  102.   local *F;
  103.   open(F, "<$file") || return undef;
  104.   while (<F>) {
  105.     chomp;
  106.     if (/^#[[:blank:]]*required[-_]?start:[[:blank:]]*([[:print:][:blank:]]*)/i) {
  107.       my $ret = $1;
  108.       close F;
  109.       $ret =~ s/\s+$//;
  110.       return $ret;
  111.     }
  112.   }
  113.   return '';
  114. }
  115.  
  116. #
  117. # calculate the active runlevels of a service. Uses global %links
  118. # hash.
  119. #
  120. sub getreal_rc {
  121.   my $s = shift;
  122.  
  123.   my $start = '';
  124.   my $l;
  125.   initlinks_rc() if $links_unknown{$s};
  126.   for $l (sort keys %links) {
  127.     $start .= $l if $links{$l}->{$s};
  128.   }
  129.   return $start;
  130. }
  131.  
  132. #
  133. # initializes global %links hash by scanning the link directories
  134. # for each runlevel.
  135. #
  136. sub initlinks_rc {
  137.   my $l;
  138.   for $l (keys %to_d) {
  139.     my @links = grep {s/^S\d\d//} ls("$initdir/$to_d{$l}");
  140.     $links{$l} = { map {$_ => 1} @links };
  141.   }
  142.   %links_unknown = ();
  143. }
  144.  
  145. #
  146. # set the state of a service. 'on' is interpreted as default
  147. #
  148. sub set_rc {
  149.   my $s = shift;
  150.   my $want = shift;
  151.   my $ret = 1;
  152.  
  153.   if (!$known_rc{$s}) {
  154.     print STDERR "$s: not a runlevel service\n";
  155.     return;
  156.   }
  157.   if ($want eq '') {
  158.     $ret = insserv('-r', '-d', "$initdir/$s");
  159.   } elsif ($want eq getdef_rc($s)) {
  160.     $ret = insserv('-d', "$initdir/$s");
  161.   } else {
  162.     $ret = insserv('-r', '-d', "$initdir/$s");
  163.     $ret = undef unless insserv("$initdir/$s,start=".join(',', split('', $want)));
  164.   }
  165.   $links_unknown{$s} = 1;    # check again for this service
  166.   return $ret;
  167. }
  168.  
  169. my $force;
  170. my $allservices;
  171.  
  172. #
  173. # run insserv
  174. #
  175. sub insserv {
  176.   my @i = ("/sbin/insserv");
  177.   push @i, "-f" if $force;
  178.   my $r = system(@i, @_);
  179.   if ($r == -1) {
  180.     printf STDERR "/sbin/insserv: $!\n";
  181.     return undef;
  182.   } elsif ($r) {
  183.     printf STDERR "/sbin/insserv failed, exit code %d\n", $? >> 8;
  184.     return undef;
  185.   }
  186.   return 1;
  187. }
  188.  
  189.  
  190. ##################################################################
  191. #                         xinetd part
  192. ##################################################################
  193.  
  194. #
  195. # get the state of a xinetd service
  196. #
  197. sub getreal_xinetd {
  198.   my $s = shift;
  199.  
  200.   my $file = "$xinetddir/$s";
  201.   local *F;
  202.   open(F, "<$file") || return undef;
  203.   my $dis = 1;
  204.   while (<F>) {
  205.     if (/^\s*service\s*\S/) {
  206.       if (!$dis) {
  207.     close F;
  208.     return 'X';
  209.       }
  210.       $dis = 0;
  211.     }
  212.     if (/^\s*disable\s*=\s*yes/) {
  213.       $dis = 1;
  214.       next;
  215.     }
  216.   }
  217.   close F;
  218.   return $dis ? '' : 'X';
  219. }
  220.  
  221. #
  222. # change the state of a xinetd service
  223. #
  224. sub set_xinetd {
  225.   my $s = shift;
  226.   my $state = shift;
  227.  
  228.   if (!$known_xinetd{$s}) {
  229.     print STDERR "$s: not a xinetd service\n";
  230.     return;
  231.   }
  232.   local *F;
  233.   local *N;
  234.   my $file = "$xinetddir/$s";
  235.   if (!open(F, "<$file")) {
  236.     print STDERR "$file: $!\n";
  237.     return;
  238.   }
  239.   if (!open(N, ">$file.chkconfig~")) {
  240.     print STDERR "$file.chkconfig~: $!\n";
  241.     return;
  242.   }
  243.   while (<F>) {
  244.     if (/^\s*service\s*\S/) {
  245.       if (!/{/) {    #}
  246.         print N $_;
  247.     $_ = <F>;
  248.       }
  249.       print N $_;
  250.       print N "\tdisable     = yes\n" unless $state;
  251.       next;
  252.     }
  253.     print N $_ unless /^\s*disable\s*=\s*yes/;
  254.   }
  255.   close F;
  256.   if (!close N) {
  257.     print STDERR "$file.chkconfig~: $!\n";
  258.     unlink("$file.chkconfig~");
  259.     return;
  260.   }
  261.   if (!rename("$file.chkconfig~", "$file")) {
  262.     print STDERR "rename $file.chkconfig~ $file: $!\n";
  263.     unlink("$file.chkconfig~");
  264.     return;
  265.   }
  266.   return 1;
  267. }
  268.  
  269.  
  270. ##################################################################
  271. #                         inetd part
  272. ##################################################################
  273.  
  274. #
  275. # get the state of a inetd service
  276. #
  277. sub getreal_inetd {
  278.   my $s = shift;
  279.  
  280.   my $file = "$inetddir/$s";
  281.   local *F;
  282.   open(F, "<$file") || return undef;
  283.   while (<F>) {
  284.     chomp;
  285.     next if /^\s*#/;
  286.     next if /^\s*$/;
  287.     close F;
  288.     return 'T';
  289.   }
  290.   close F;
  291.   return '';
  292. }
  293.  
  294. #
  295. # does the line look like a inetd service?
  296. #
  297. sub looks_ok_inetd {
  298.   return 1 if $_[0] =~ /^![\|<]/;
  299.   my @x = split(' ', $_[0]);
  300.   my %oktype = map {$_ => 1} qw{stream dgram raw rdm seqpacket};
  301.   return 0 unless $oktype{$x[1]};
  302.   return 0 unless $x[3] =~ /^(no)?wait/;
  303.   return 1;
  304. }
  305.  
  306. #
  307. # change the state of a inetd service
  308. #
  309. sub set_inetd {
  310.   my $s = shift;
  311.   my $state = shift;
  312.  
  313.   if (!$known_inetd{$s}) {
  314.     print STDERR "$s: not an inetd service\n";
  315.     return;
  316.   }
  317.   local *F;
  318.   local *N;
  319.   my $file = "$inetddir/$s";
  320.   if (!open(F, "<$file")) {
  321.     print STDERR "$file: $!\n";
  322.     return;
  323.   }
  324.   if (!open(N, ">$file.chkconfig~")) {
  325.     print STDERR "$file.chkconfig~: $!\n";
  326.     return;
  327.   }
  328.   while (<F>) {
  329.     chomp;
  330.     if (/^#\s*(.*)/) {
  331.       my $l = $1;
  332.       if (looks_ok_inetd($l)) {
  333.         print N $state ? "$l\n" : "## $l\n";
  334.         next;
  335.       }
  336.     }
  337.     if (!$state && looks_ok_inetd($_)) {
  338.       print N "# $_\n";
  339.       next;
  340.     }
  341.     print N "$_\n";
  342.   }
  343.   if (!close N) {
  344.     print STDERR "$file.chkconfig~: $!\n";
  345.     unlink("$file.chkconfig~");
  346.     return;
  347.   }
  348.   if (!rename("$file.chkconfig~", "$file")) {
  349.     print STDERR "rename $file.chkconfig~ $file: $!\n";
  350.     unlink("$file.chkconfig~");
  351.     return;
  352.   }
  353.   return 1;
  354. }
  355.  
  356.  
  357. ##################################################################
  358. #                     common functions
  359. ##################################################################
  360.  
  361. #
  362. # calculate current status
  363. #
  364. sub getcurrent {
  365.   my $s = shift;
  366.  
  367.   if (!$known_all{$s}) {
  368.     print STDERR "$s: unknown service\n";
  369.     return undef;
  370.   }
  371.   my $start = '';
  372.   $start .= getreal_rc($s) if $known_rc{$s};
  373.   $start .= getreal_inetd($s) if $known_inetd{$s};
  374.   $start .= getreal_xinetd($s) if $known_xinetd{$s};
  375.   return $start;
  376. }
  377.  
  378.  
  379. #
  380. # return all services we know about by scanning $initdir for init
  381. # scripts.
  382. #
  383. sub findknown {
  384.   for (ls($initdir)) {
  385.     next unless -f "$initdir/$_";
  386.     next if /^README/ || /^core/;
  387.     next if /~$/ || /^[\d\$\.#_\-\\\*]/ || /\.(rpm|ba|old|new|save|swp|core)/;
  388.     $known_rc{$_} = 1;
  389.     $known_all{$_} = 1;
  390.   }
  391.   for (ls($xinetddir)) {
  392.     next unless -f "$xinetddir/$_";
  393.     next if /~$/ || /\./;
  394.     $known_xinetd{$_} = 1;
  395.     $known_all{$_} = 1;
  396.   }
  397.   return unless -d $inetddir;
  398.   return unless -f "/etc/inetd.conf";
  399.   local *F;
  400.   my $gotinetd = 0;
  401.   if (!open(F, "</etc/inetd.conf")) {
  402.     print STDERR "/etc/inetd.conf: $!\n";
  403.     return;
  404.   }
  405.   while (<F>) {
  406.     chomp;
  407.     if (/^!\|\s*\/usr\/lib\/inetd\/includedir\s+\Q$inetddir\E\s*$/) {
  408.       $gotinetd = 1;
  409.       last;
  410.     }
  411.   }
  412.   close F;
  413.   return unless $gotinetd;
  414.   for (ls($inetddir)) {
  415.     next unless -f "$inetddir/$_";
  416.     next if /~$/ || /\./;
  417.     $known_inetd{$_} = 1;
  418.     $known_all{$_} = 1;
  419.   }
  420. }
  421.  
  422. #
  423. # normalize runlevel
  424. #
  425. my $level;    # overwrite on with $level
  426.  
  427. sub normalize {
  428.   my $s = shift;
  429.   my $rl = shift;
  430.  
  431.   $rl = lc($rl);
  432.   return '' if $rl eq 'off' || $rl eq '';
  433.   my $def = '35';
  434.   $def = 'inetd' if $known_inetd{$s};
  435.   $def = 'xinetd' if $known_xinetd{$s};
  436.   $def = getdef_rc($s) if $known_rc{$s};
  437.   return undef unless defined $def;
  438.   $rl = ",$rl,";
  439.   $rl =~ s/,on,/,$level,/g if defined $level;
  440.   $rl =~ s/,on,/,$def,/g;
  441.   $rl =~ s/,xinetd,/,X,/g;
  442.   $rl =~ s/,inetd,/,T,/g;
  443.   $rl =~ s/s/S/g;
  444.   $rl =~ s/b/B/g;
  445.   $rl =~ s/,//g;
  446.   $rl = join('', sort unify(split('', $rl)));
  447.   if ($rl =~ /([^0123456SBTX])/) {
  448.     print STDERR "illegal runlevel specified for $s: $1\n";
  449.     return undef;
  450.   }
  451.   return $rl;
  452. }
  453.  
  454. #
  455. # convert runlevels into a nice human readable form
  456. #
  457. sub readable {
  458.   my $s = shift;
  459.   my $rl = shift;
  460.  
  461.   return 'off' if $rl eq '';
  462.   my $def = '';
  463.   $def = getdef_rc($s) if $known_rc{$s};
  464.   return undef unless defined $def;
  465.   $rl = ",$rl,";
  466.   $rl =~ s/T/,inetd,/g;
  467.   $rl =~ s/X/,xinetd,/g;
  468.   $rl =~ s/,\Q$def\E,/,on,/ if $def ne '';
  469.   $rl =~ s/,,+/,/g;
  470.   $rl =~ s/^,//;
  471.   $rl =~ s/,$//;
  472.   return $rl;
  473. }
  474.  
  475.  
  476. ##################################################################
  477. #                     main program
  478. ##################################################################
  479.  
  480. my $mode = '';
  481. my $printdeps;
  482.  
  483.  
  484. sub addmode {
  485.   die("Please specify only one mode.\n") if $mode;
  486.   $mode = substr($_[0], 0, 1);
  487. }
  488.  
  489. sub usage {
  490.   print <<EOF;
  491. usage:
  492.         chkconfig -t|--terse [names]            (shows the links)
  493.         chkconfig -e|--edit  [names]            (configure services)
  494.         chkconfig -s|--set   [name state]...    (configure services)
  495.         chkconfig -l|--list [--deps] [names]    (shows the links)
  496.         chkconfig -c|--check name [state]       (check state)
  497.         chkconfig -a|--add   [names]            (runs insserv)
  498.         chkconfig -d|--del   [names]            (runs insserv -r)
  499.         chkconfig -h|--help                     (print usage)
  500.         chkconfig -f|--force ...                (call insserv with -f)
  501.  
  502.         chkconfig [name]           same as chkconfig -t
  503.         chkconfig name state...    same as chkconfig -s name state
  504. EOF
  505. }
  506.  
  507. Getopt::Long::Configure('no_ignore_case');
  508.  
  509. if (!GetOptions('list|l'   => \&addmode,
  510.                 'terse|t'  => \&addmode,
  511.                 'add|a'    => \&addmode,
  512.                 'del|d'    => \&addmode,
  513.                 'edit|e'   => \&addmode,
  514.                 'help|h'   => \&addmode,
  515.                 'set|s'    => \&addmode,
  516.                 'check|c'  => \&addmode,
  517.                 'level=s'  => \$level,
  518.                 'force|f'  => \$force,
  519.                 'allservices|A'  => \$allservices,
  520.                 'deps'     => \$printdeps
  521.    )) {
  522.   usage();
  523.   exit 1;
  524. }
  525. if ($mode eq 'h') {
  526.   usage();
  527.   exit 0;
  528. }
  529. my (@services, $s);
  530.  
  531. findknown();
  532.  
  533. if (@ARGV) {
  534.   @services = @ARGV;
  535.   $mode = @services == 1 ? 't' : 's' if $mode eq '';
  536. } else {
  537.   die("Please specify a service\n") if $mode eq 'c' || $mode eq 'a' || $mode eq 'd';
  538.   @services = sort grep {!$skips_rc{$_}} keys %known_all if $mode ne 's';
  539. }
  540. $mode = 't' if $mode eq '';
  541.  
  542. initlinks_rc() if $mode eq 'e' || $mode eq 't' || $mode eq 's' || $mode eq 'c' || $mode eq 'l';
  543.  
  544. if (!@ARGV && !$allservices) {
  545.   my $l;
  546.   my %ison;
  547.   for $l (0, 1, 2, 3, 4, 5, 6) {
  548.     $ison{$_} = 1 for keys %{$links{$l}};
  549.   }
  550.   @services = grep {!/^boot\./ || $ison{$_}} @services;
  551. }
  552.  
  553. my %current = ();
  554.  
  555. if ($mode eq 'c') {
  556.   die("Please specify only one service to check\n") if @services > 2;
  557.   $s = $services[0];
  558.   my $want;
  559.   if (@services == 1) {
  560.     $want = `/sbin/runlevel`;
  561.     chomp($want);
  562.     die("Can't determine current runlevel\n") unless $want =~ s/^. (.)$/$1/;
  563.   } else {
  564.     $want = $services[1];
  565.   }
  566.   $want = normalize($s, $want);
  567.   exit 1 unless defined $want;
  568.   exit 0 if $want eq '';
  569.   my $l;
  570.   for $l (split('', $want)) {
  571.     if ($l eq 'T') {
  572.       exit 1 unless getreal_inetd($s) ne '';
  573.       next;
  574.     }
  575.     if ($l eq 'X') {
  576.       exit 1 unless getreal_xinetd($s) ne '';
  577.       next;
  578.     }
  579.     exit 1 unless $links{$l}->{$s};
  580.   }
  581.   exit 0;
  582. }
  583.  
  584. if ($mode eq 'e' || $mode eq 't') {
  585.   my ($fh, $tmpname);
  586.   my $maxlen = 0;
  587.   $maxlen >= length($_) or $maxlen = length($_) for @services;
  588.   if ($mode eq 'e') {
  589.     ($fh, $tmpname) = tempfile("chkconfig.XXXXX", DIR => '/tmp', UNLINK => 1);
  590.     die("Could not create temporary file\n") unless $tmpname ne '';
  591.   } else {
  592.     $fh = *STDOUT;
  593.   }
  594.   for $s (@services) {
  595.     $current{$s} = getcurrent($s);
  596.     next unless defined $current{$s};
  597.     my $r = readable($s, $current{$s});
  598.     next unless defined $r;
  599.     printf $fh "%-*s  %s\n", $maxlen, $s, $r;
  600.   }
  601.   exit 0 unless $mode eq 'e';
  602.   close $fh;
  603.   system("\${VISUAL:-vi} $tmpname");
  604.   open(STDIN, "<$tmpname") or die("Could not open temporary file\n");
  605.   $mode = 's';
  606.   @services = ();
  607. }
  608.  
  609. if ($mode eq 's') {
  610.   my $status = 0;
  611.   my $usestdin = !@services;
  612.   my $ln = 0;
  613.   $force = 1 if @services != 2;        # stupid hack
  614.   do {
  615.     if ($usestdin) {
  616.       while (<STDIN>) {
  617.     $ln++;
  618.     chomp;
  619.     next if /^\s*#/;
  620.     next if /^\s*$/;
  621.     my @line = split(' ', $_);
  622.     if (@line != 2) {
  623.       print STDERR "parse error line $ln: $_\n";
  624.       $status = 1;
  625.       next;
  626.     }
  627.     @services = @line;
  628.     last;
  629.       }
  630.       exit 1 unless @services;
  631.     }
  632.     if (@services & 1) {
  633.       printf("Usage: chkconfig -s service on|off|runlevels\n");
  634.       exit 1;
  635.     }
  636.     while (@services) {
  637.       $s = shift @services;
  638.       my $want = shift @services;
  639.       $want = normalize($s, $want);
  640.       $status = 1, next unless defined $want;
  641.       $current{$s} = getcurrent($s) unless defined $current{$s};
  642.       $status = 1, next unless defined $current{$s};
  643.       my $current = $current{$s};
  644.       next if $want eq $current;
  645.       delete $current{$s};
  646.       if (($want =~ /T/) && ($current !~ /T/)) {
  647.         $status = 1 unless set_inetd($s, 1);
  648.       } elsif (($want !~ /T/) && ($current =~ /T/)) {
  649.         $status = 1 unless set_inetd($s, 0);
  650.       }
  651.       if (($want =~ /X/) && ($current !~ /X/)) {
  652.         $status = 1 unless set_xinetd($s, 1);
  653.       } elsif (($want !~ /X/) && ($current =~ /X/)) {
  654.         $status = 1 unless set_xinetd($s, 0);
  655.       }
  656.       $want =~ s/[TX]//g;
  657.       $current =~ s/[TX]//g;
  658.       next if $want eq $current;
  659.       $status = 1 unless set_rc($s, $want);
  660.     }
  661.   } while ($usestdin);
  662.   exit $status;
  663. }
  664.  
  665. #
  666. # compatibility section
  667. #
  668. my $status = 0;
  669. if ($mode eq 'a' || $mode eq 'd') {
  670.   for $s (splice @services) {
  671.     if (!$known_all{$s}) {
  672.       print STDERR "$s: unknown service\n";
  673.       $status = 1;
  674.       next;
  675.     }
  676.     if (!$known_rc{$s}) {
  677.       print STDERR "$s: not a runlevel service\n";
  678.       $status = 1;
  679.       next;
  680.     }
  681.     push @services, $s;
  682.     if ($mode eq 'a') {
  683.       insserv("$initdir/$s") or $status = 1;
  684.     } else {
  685.       insserv('-r', "$initdir/$s") or $status = 1;
  686.     }
  687.   }
  688.   $mode = 'l';
  689.   initlinks_rc();
  690. }
  691. if ($mode eq 'l') {
  692.   my $usecolor = -t STDOUT;
  693.   for $s (@services) {
  694.     if (!$known_rc{$s}) {
  695.       print STDERR "$s: unknown service\n" unless $known_all{$s};
  696.       next;
  697.     }
  698.     printf "%-24s", $s;
  699.     my $l;
  700.     for $l (0, 1, 2, 3, 4, 5, 6, 'B', 'S') {
  701.       next if ($l eq 'B' || $l eq 'S') && !$links{$l}->{$s};
  702.       if ($usecolor) {
  703.     print $links{$l}->{$s} ? "  \e[0;1;32m$l:on\e[m " : "  $l:off";
  704.       } else {
  705.     print $links{$l}->{$s} ? "  $l:on " : "  $l:off";
  706.       }
  707.     }
  708.     print getdeps_rc($s) if $printdeps;
  709.     print "\n";
  710.   }
  711.   my @inetd_services = grep {$known_inetd{$_}} @services;
  712.   if (@inetd_services) {
  713.     print "inetd based services:\n";
  714.     for $s (@inetd_services) {
  715.       printf "        %-19s ", "$s:";
  716.       if (getreal_inetd($s) ne '') {
  717.     print $usecolor ? "\e[0;1;32mon\e[m\n" : "on\n";
  718.       } else {
  719.     print "off\n";
  720.       }
  721.     }
  722.   }
  723.   my @xinetd_services = grep {$known_xinetd{$_}} @services;
  724.   if (@xinetd_services) {
  725.     print "xinetd based services:\n";
  726.     for $s (@xinetd_services) {
  727.       printf "        %-19s ", "$s:";
  728.       if (getreal_xinetd($s) ne '') {
  729.     print $usecolor ? "\e[0;1;32mon\e[m\n" : "on\n";
  730.       } else {
  731.     print "off\n";
  732.       }
  733.     }
  734.   }
  735.   exit($status);
  736. }
  737.