Annotation of loncom/debugging_tools/modify_config_files.pl, revision 1.9

1.1       matthew     1: #!/usr/bin/perl -w
                      2: #
                      3: # The LearningOnline Network
                      4: #
1.9     ! raeburn     5: # $Id: modify_config_files.pl,v 1.8 2008/01/12 21:15:00 raeburn Exp $
1.1       matthew     6: #
                      7: # Copyright Michigan State University Board of Trustees
                      8: #
                      9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     10: #
                     11: # LON-CAPA is free software; you can redistribute it and/or modify
                     12: # it under the terms of the GNU General Public License as published by
                     13: # the Free Software Foundation; either version 2 of the License, or
                     14: # (at your option) any later version.
                     15: #
                     16: # LON-CAPA is distributed in the hope that it will be useful,
                     17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19: # GNU General Public License for more details.
                     20: #
                     21: # You should have received a copy of the GNU General Public License
                     22: # along with LON-CAPA; if not, write to the Free Software
                     23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24: #
                     25: # /home/httpd/html/adm/gpl.txt
                     26: #
                     27: # http://www.lon-capa.org/
                     28: #
                     29: ###
                     30: 
                     31: =pod
                     32: 
                     33: =head1 NAME
                     34: 
                     35: B<modify_config_files.pl>
                     36: 
                     37: =head1 SYNOPSIS
                     38: 
1.9     ! raeburn    39: This script modifies /etc/my.cnf and one of: /etc/yum.conf 
        !            40: (for Fedora/CentOS/Scientific Linux/RHEL5), /etc/apt/sources.list
        !            41: (for Debian/Ubuntu) and /etc/sysconfig/rhn/sources (for RHEL4). 
1.1       matthew    42: 
                     43: =head1 DESCRIPTION
                     44: 
1.9     ! raeburn    45: This script modifies /etc/my.cnf and /etc/yum.conf or /etc/apt/sources
        !            46: or /etc/sysconfig/rhn/sources to ensure certain parameters are set
        !            47: properly.  The LON-CAPA yum repositories are added to /etc/yum.conf or
        !            48: /etc/sysconfig/rhn/sources and the LON-CAPA apt repositories are added to 
        !            49: /etc/apt/sources.list.
        !            50: 
1.1       matthew    51: The /etc/my.cnf file is modified to set the wait_timeout to 1 year.  Backup
1.9     ! raeburn    52: copies of each file are made in /etc, /etc/apt, and /etc/sysconfig/rhn, as 
        !            53: appropriate.
1.1       matthew    54: 
                     55: =cut
                     56: 
                     57: use strict;
                     58: use File::Copy;
1.3       matthew    59: use lib '/home/httpd/lib/perl/';
                     60: use LONCAPA::Configuration;
                     61: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
1.1       matthew    62: 
1.6       raeburn    63: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
                     64: my $dist = <DSH>;
                     65: chomp($dist);
                     66: close(DSH);
                     67: 
                     68: my $yum_status;
1.9     ! raeburn    69: my $loninst = 'http://install.loncapa.org';
        !            70: my $loninst_re = 'http://install\.loncapa\.org';
        !            71: if ($dist =~ /^fedora(\d+)$/) {
        !            72:     my $ver = $1;
        !            73:     my $gpgchk = 0;
        !            74:     my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa"; 
        !            75:     if ($ver > 6) {
        !            76:         $gpgchk = 1;
        !            77:     }
1.6       raeburn    78:     $yum_status =  
                     79:         &update_file('/etc/yum.conf',
                     80:              [{section => 'loncapa-updates-$basearch',
1.1       matthew    81:                key     => 'name=',
1.6       raeburn    82:                value   => 'Fedora Core $releasever LON-CAPA $basearch Updates',
                     83:            }, {section => 'loncapa-updates-$basearch',
1.1       matthew    84:                key     => 'baseurl=',
1.9     ! raeburn    85:                value   => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
1.6       raeburn    86:            }, {section => 'loncapa-updates-$basearch',
1.5       matthew    87:                key     => 'gpgcheck=',
1.9     ! raeburn    88:                value   =>  $gpgchk,
        !            89:            }, {section => 'loncapa-updates-$basearch',
        !            90:                key     => 'gpg=',
        !            91:                value   => $gpg,
1.1       matthew    92:            }, {section => 'loncapa-updates-noarch',
                     93:                key     => 'name=',
                     94:                value   => 'Fedora Core $releasever LON-CAPA noarch Updates',
                     95:            }, {section => 'loncapa-updates-noarch',
                     96:                key     => 'baseurl=',
1.9     ! raeburn    97:                value   => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
1.5       matthew    98:            }, {section => 'loncapa-updates-noarch',
                     99:                key     => 'gpgcheck=',
1.9     ! raeburn   100:                value   => $gpgchk,
        !           101:            }, {section => 'loncapa-updates-noarch',
        !           102:                key     => 'gpg=',
        !           103:                value   => $gpg,
1.1       matthew   104:            }]);
1.9     ! raeburn   105: } elsif ($dist =~ /^(rhes|centos|scientific)(\d+)$/) {
        !           106:     my $type = $1;
        !           107:     my $ver = $2;
        !           108:     my $longver = $ver;
        !           109:     if ($type eq 'rhes') {
        !           110:         if ($ver == 4) {
        !           111:             $longver = '4ES';
        !           112:         } elsif ($ver == 5) {
        !           113:             $longver = '5Server';
        !           114:         }
        !           115:     }
        !           116:     my %info = (
        !           117:                  rhes => {
        !           118:                            title => 'RHEL',
        !           119:                            path => 'redhat/linux/enterprise/loncapa',
        !           120:                            gpg => 'versions/redhat/RPM-GPG-KEY-loncapa',
        !           121:                            gpgchk => 1,
        !           122:                          },
        !           123:                  centos => {
        !           124:                              title => 'CentOS',
        !           125:                              path => 'centos/loncapa',
        !           126:                              gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
        !           127:                              gpgchk => 1,
        !           128:                            },
        !           129:                  scientific => {
        !           130:                                  title => 'Scientific Linux',
        !           131:                                  path => 'scientific/loncapa',
        !           132:                                  gpg => 'versions/scientific/RPM-GPG-KEY-loncapa',
        !           133:                                  gpgchk => 1,
        !           134:                                },
        !           135:                );
        !           136:     if (ref($info{$type}) eq 'HASH') {
        !           137:         if ($ver > 4) {
        !           138:             $yum_status =
        !           139:                 &update_file('/etc/yum.conf',
        !           140:                      [{section => 'loncapa-updates-basearch',
        !           141:                        key     => 'name=',
        !           142:                        value   => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates',
        !           143:                       }, {section => "loncapa-updates-basearch",
        !           144:                           key     => 'baseurl=',
        !           145:                           value   => "$loninst/$info{$type}{path}/".'$releasever/$basearch',
        !           146:                       }, {section => 'loncapa-updates-basearch',
        !           147:                           key     => 'gpgcheck=',
        !           148:                           value   => $info{$type}{gpchk},
        !           149:                       }, {section => 'loncapa-updates-$basearch',
        !           150:                           key     => 'gpgkey=',
        !           151:                           value   => "$loninst/$info{$type}{gpg}",
        !           152:                       }, {section => 'loncapa-updates-noarch',
        !           153:                           key     => 'name=',
        !           154:                           value   => $info{$type}{title}.' $releasever LON-CAPA noarch Updates',
        !           155:                       }, {section => 'loncapa-updates-noarch',
        !           156:                           key     => 'baseurl=',
        !           157:                           value   => "$loninst/$info{$type}{path}/".'$releasever/noarch',
        !           158:                       }, {section => 'loncapa-updates-noarch',
        !           159:                           key     => 'gpgcheck=',
        !           160:                           value   => $info{$type}{gpchk},
        !           161:                       }, {section => 'loncapa-updates-noarch',
        !           162:                           key     => 'gpgkey=',
        !           163:                           value   => "$loninst/$info{$type}{gpg}",
        !           164:                       }]);
        !           165:         } elsif (($type eq 'rhes') && ($ver == 4)) {
        !           166:             my %rhn = (
        !           167:                         basearch => { 
        !           168:                             regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH',
        !           169:                             text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH',
        !           170:                                     },
        !           171:                         noarch =>  {
        !           172:                             regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch',
        !           173:                             text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch",
        !           174:                                    },
        !           175:                       );
        !           176:             $yum_status = &update_rhn_source(\%rhn); 
        !           177:         }
        !           178:     }
        !           179: } elsif ($dist =~ /^(debian|ubuntu)\d+$/) {
        !           180:     my %apt_get_source = (
        !           181:                            debian5 => {
        !           182:                                         regexp => '\s*deb\s+'.$loninst_re.'/debian/\s+lenny\s+main',
        !           183:                                         text   => "deb $loninst/debian/ lenny main",
        !           184:                                       },
        !           185:                            ubuntu6 => {
        !           186:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+dapper\s+main',
        !           187:                                         text   => "deb $loninst/ubuntu/ dapper main",
        !           188:                                       },
        !           189:                            ubuntu8 => {
        !           190:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+hardy\s+main',
        !           191:                                         text   => "deb $loninst/ubuntu/ hardy main",
        !           192:                                       },
        !           193:                          );
        !           194:     my $apt_status;
        !           195:     if (defined($apt_get_source{$dist})) {
        !           196:         $apt_status = &update_apt_source($apt_get_source{$dist},);
1.6       raeburn   197:     }
                    198: }
1.1       matthew   199: 
1.4       matthew   200: my $mysql_global_status =
                    201:     &update_file('/etc/my.cnf',
1.1       matthew   202:              [{section =>'mysqld',
                    203:                key     =>'set-variable=wait_timeout=',
                    204:                value   =>'31536000', }]);
                    205: 
1.3       matthew   206: my $local_my_cnf = '/home/www/.my.cnf';
                    207: if (! -e $local_my_cnf) {
1.4       matthew   208:     # Create a file so we can do something with it...
1.3       matthew   209:     system("touch $local_my_cnf");
                    210: }
1.4       matthew   211: my $mysql_www_status =
                    212:     &update_file($local_my_cnf,
1.3       matthew   213:              [{section =>'client',
                    214:                key     =>'user=',
                    215:                value   =>'www',},
                    216:               {section =>'client',
                    217:                key     =>'password=',
                    218:                value   =>$loncapa_config->{'lonSqlAccess'}},]);
                    219: 
1.4       matthew   220: my $exitvalue = 0;
                    221: 
                    222: if ($mysql_global_status) { $exitvalue = 1; }
                    223: 
                    224: exit $exitvalue;
1.1       matthew   225: 
                    226: 
                    227: sub update_file {
                    228:     my ($file,$newdata) = @_;
                    229:     return 1 if (! -e $file);
                    230:     my $backup = $file.'.backup';
                    231:     if (! copy($file,$backup)) {
1.4       matthew   232:         warn "**** Error: Unable to make backup of $file";
1.1       matthew   233:         return 0;
                    234:     }
                    235:     my ($filedata) = &parse_config_file($file);
1.4       matthew   236:     if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
                    237:     my $modified = 0;
1.1       matthew   238:     foreach my $data (@$newdata) {
                    239:         my $section = $data->{'section'};
                    240:         my $key = $data->{'key'};
                    241:         my $value = $data->{'value'};
1.4       matthew   242:         my $result = &modify_config_file($filedata,$section,$key,$value);
                    243:         if ($result) { $modified = 1; }
                    244:     }
                    245:     if ($modified) {
                    246:         my $result = &write_config_file($file,$filedata);
                    247:         if (defined($result)) { warn 'Error:'.$result; return 0; }
1.1       matthew   248:     }
1.4       matthew   249:     return $modified;
1.1       matthew   250: }
                    251: 
                    252: #################################################################
                    253: #################################################################
                    254: 
                    255: =pod
                    256: 
1.9     ! raeburn   257: =over 4
        !           258: 
        !           259: =item &parse_config_file()
1.1       matthew   260: 
                    261: Read a configuration file in and parse it into an internal data structure.
                    262: 
                    263: Input: filename
                    264: 
                    265: Output: array ref $filedata  OR  scalar error message
                    266: 
1.9     ! raeburn   267: =back 
        !           268: 
1.1       matthew   269: =cut
                    270: 
                    271: #################################################################
                    272: #################################################################
                    273: sub parse_config_file {
                    274:     my ($file) = @_;
                    275:     open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
                    276:     my @Input = <INFILE>;
                    277:     close(INFILE);
                    278:     my @Structure;
                    279:     my %Sections;
                    280:     while (my $line = shift(@Input)) {
                    281:         chomp($line);
                    282:         if ($line =~ /^\[([^\]]*)\]/) {
                    283:             my $section_id = $1;
                    284:             push(@Structure,'__section__'.$section_id);
                    285:             while ($line = shift(@Input)) {
1.4       matthew   286:                 chomp($line);
1.1       matthew   287:                 if ($line =~ /^\[([^\]]*)\]/) {
                    288:                     unshift(@Input,$line);
                    289:                     last;
                    290:                 } else {
                    291:                     push(@{$Sections{$section_id}},$line);
                    292:                 }
                    293:             }
                    294:         } else {
                    295:             push(@Structure,$line);
                    296:         }
                    297:     }
                    298:     my $filedata = [\@Structure,\%Sections];
                    299:     return $filedata;
                    300: }
                    301: 
                    302: #################################################################
                    303: #################################################################
                    304: 
                    305: =pod
                    306: 
1.9     ! raeburn   307: =over 4
        !           308: 
1.1       matthew   309: =item
                    310: 
                    311: Write a configuration file out based on the internal data structure returned
                    312: by &parse_config_file
                    313: 
                    314: Inputs: filename, $filedata (the return value of &parse_config_file
                    315: 
                    316: Returns: undef on success, scalar error message on failure.
                    317: 
1.9     ! raeburn   318: =back
        !           319: 
1.1       matthew   320: =cut
                    321: 
                    322: #################################################################
                    323: #################################################################
                    324: sub write_config_file {
                    325:     my ($file,$filedata) = @_;
                    326:     my ($structure,$sections) = @$filedata;
                    327:     if (! defined($structure) || ! ref($structure)) {
                    328:         return 'Bad subroutine inputs';
                    329:     }
                    330:     open(OUTPUT,'>'.$file) || return('Unable to open '.$file.' for writing');
                    331:     for (my $i=0;$i<scalar(@$structure);$i++) {
                    332:         my $line = $structure->[$i];
                    333:         chomp($line);
                    334:         if ($line =~ /^__section__(.*)$/) {
                    335:             my $section_id = $1;
                    336:             print OUTPUT ('['.$section_id.']'.$/);
                    337:             foreach my $section_line (@{$sections->{$section_id}}) {
                    338:                 chomp($section_line);
                    339:                 print OUTPUT $section_line.$/;
                    340:             }
                    341:             # Deal with blank lines
                    342:             if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
                    343:                 # No need to output a blank line at the end if there is one 
                    344:                 # already
                    345:             } else {
                    346:                 print OUTPUT $/;
                    347:             }
                    348:         } else {
                    349:             print OUTPUT $line.$/;
                    350:         }
                    351:     }
                    352:     close OUTPUT;
                    353:     return undef;
                    354: }
                    355: 
                    356: #################################################################
                    357: #################################################################
                    358: 
                    359: =pod
                    360: 
1.9     ! raeburn   361: =over 4
        !           362: 
        !           363: =item &modify_config_file()
1.1       matthew   364: 
                    365: Modifies the internal data structure of a configuration file to include new
                    366: sections and/or new configuration directives.
                    367: 
                    368: Inputs: $filedata (see &parse_config_file
                    369: $section, the [section] the new entry is to reside in.  A value of undef will
                    370: cause the "outer" section (as in yum.conf) to be updated (or have the new
                    371: value prepended).
                    372: $newkey: A line which matches this will be replaced with $newkey.$newvalue
                    373: $newvalue: The new value to be placed with the new key.
                    374: 
1.4       matthew   375: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
                    376: 
1.9     ! raeburn   377: =back 
1.4       matthew   378: 
1.1       matthew   379: =cut
                    380: 
                    381: #################################################################
                    382: #################################################################
                    383: sub modify_config_file {
                    384:     my ($filedata,$section,$newkey,$newvalue)=@_;
1.4       matthew   385:     my $modified = 0;    # returned value - set to true if the file is modified
1.1       matthew   386:     my ($structure,$sections) = @$filedata;
                    387:     if (! defined($newvalue)) {
                    388:         $newvalue = '';
                    389:     }
                    390:     my $newline = $newkey.$newvalue;
                    391:     #
                    392:     # Determine which array ref gets the item
                    393:     my $target;
                    394:     if (defined($section)) {
                    395:         if (! exists($sections->{$section})) {
                    396:             push(@$structure,'__section__'.$section);
                    397:             $sections->{$section}=[];
                    398:         }
                    399:         $target = $sections->{$section};
                    400:     } else {
                    401:         $target = $structure;
                    402:     }
                    403:     #
                    404:     # Put the item in or update it.
                    405:     my $key_is_new = 1;
                    406:     for (my $i=0;$i<scalar(@$target);$i++) {
                    407:         if ($target->[$i] =~/^$newkey/) {
1.4       matthew   408:             if ($target->[$i] ne $newline) {
                    409:                 $target->[$i]=$newline;
                    410:                 $modified = 1;
                    411:             }
1.1       matthew   412:             $key_is_new = 0;
                    413:             last;
                    414:         }
                    415:     }
                    416:     if ($key_is_new) {
                    417:         if (! defined($section)) {
                    418:             unshift(@$target,$newline);
                    419:         } else {
                    420:             # No need to put things after a blank line.
1.2       matthew   421:             if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
1.1       matthew   422:                 $target->[-1] = $newline;
1.4       matthew   423:                 $modified = 1;
1.1       matthew   424:             } else {
                    425:                 push(@$target,$newline);
1.4       matthew   426:                 $modified = 1;
1.1       matthew   427:             }
                    428:         }
                    429:     }
1.4       matthew   430:     return $modified;
1.1       matthew   431: }
                    432: 
1.9     ! raeburn   433: #################################################################
        !           434: #################################################################
        !           435: 
        !           436: =pod
        !           437: 
        !           438: =over 4
        !           439: 
        !           440: =item &update_rhn_source()
        !           441: 
        !           442: Modifies the Red Hat 4 sources file which includes repositories used by up2date 
        !           443: 
        !           444: Inputs: 
        !           445: $rhn_items - a reference to hash of a hash containing the regular expression
        !           446: to test for, and the text string to append to the file, if an entry for the 
        !           447: LON-CAPA RHEL repository is missing for two cases:
        !           448: 
        !           449: (a) basearch
        !           450: (b) noarch 
        !           451: 
        !           452: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
        !           453: 
        !           454: =back
        !           455: 
        !           456: =cut
        !           457: 
        !           458: #################################################################
        !           459: #################################################################
        !           460: sub update_rhn_source {
        !           461:     my ($rhn_items) = @_;
        !           462:     return 0 if (ref($rhn_items) ne 'HASH');
        !           463:     return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
        !           464:     my $file = '/etc/sysconfig/rhn/sources';
        !           465:     return 0 if (! -e $file);
        !           466:     my $backup = $file.'.backup';
        !           467:     if (! copy($file,$backup)) {
        !           468:         warn "**** Error: Unable to make backup of $file";
        !           469:         return 0;
        !           470:     }
        !           471:     my $result = 0;
        !           472:     my $fh;
        !           473:     if (open($fh,"<$file")) {
        !           474:         my $total = 0;
        !           475:         my %found;
        !           476:         foreach my $item (keys(%{$rhn_items})) {
        !           477:             $found{$item} = 0;
        !           478:         }
        !           479:         while(<$fh>) {
        !           480:             foreach my $item (keys(%{$rhn_items})) {
        !           481:                 if (ref($rhn_items->{$item}) eq 'HASH') {
        !           482:                     my $pattern = $rhn_items->{$item}->{regexp};
        !           483:                     if ($pattern ne '') { 
        !           484:                         if (m{^$pattern}) {
        !           485:                             $found{$item} = 1;
        !           486:                             $total ++;
        !           487:                         }
        !           488:                     }
        !           489:                 }
        !           490:             }
        !           491:             last if $total == 2;
        !           492:         }
        !           493:         close($fh);
        !           494:         if ($total < 2) {
        !           495:             if (open($fh,">>$file")) {
        !           496:                 foreach my $item (keys(%{$rhn_items})) {
        !           497:                     unless ($found{$item}) {
        !           498:                         if (ref($rhn_items->{$item}) eq 'HASH') {
        !           499:                             if ($rhn_items->{$item}->{text} ne '') {
        !           500:                                 print $fh "\n".$rhn_items->{$item}->{text}."\n";
        !           501:                                 $result = 1;
        !           502:                             }
        !           503:                         }
        !           504:                     }
        !           505:                 }
        !           506:                 close($fh);
        !           507:             }
        !           508:         }
        !           509:     }
        !           510:     return $result;
        !           511: }
1.1       matthew   512: 
                    513: #################################################################
                    514: #################################################################
                    515: 
                    516: =pod
                    517: 
1.9     ! raeburn   518: =over 4
        !           519: 
        !           520: =item &update_apt_source()
        !           521: 
        !           522: Modifies the source.list file which includes repositories used by apt-get
        !           523: 
        !           524: Inputs:
        !           525: $deb_row - a reference to containing the regular expression
        !           526: to test for, and the text string to append to the file, if an entry for the
        !           527: LON-CAPA Debian/ or Ubuntu repository is missing.
        !           528: 
        !           529: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
        !           530: 
1.1       matthew   531: =back
                    532: 
                    533: =cut
                    534: 
                    535: #################################################################
                    536: #################################################################
1.9     ! raeburn   537: sub update_apt_source {
        !           538:     my ($deb_row) = @_;
        !           539:     return 0 if (ref($deb_row) ne 'HASH');
        !           540:     return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
        !           541:     my $file = '/etc/apt/sources.list';
        !           542:     return 0 if (! -e $file);
        !           543:     my $backup = $file.'.backup';
        !           544:     if (! copy($file,$backup)) {
        !           545:         warn "**** Error: Unable to make backup of $file";
        !           546:         return 0;
        !           547:     }
        !           548:     my $result = 0;
        !           549:     my $fh;
        !           550:     if (open($fh,"<$file")) {
        !           551:         my $found = 0;
        !           552:         my $pattern = $deb_row->{regexp};
        !           553:         while(<$fh>) {
        !           554:             if (m{^$pattern}) {
        !           555:                 $found = 1;
        !           556:                 last;
        !           557:             }
        !           558:         }
        !           559:         close($fh);
        !           560:         if (!$found) {
        !           561:             if (open($fh,">>$file")) {
        !           562:                 print $fh "\n".$deb_row->{text}."\n";
        !           563:                 close($fh);
        !           564:                 $result = 1;
        !           565:             }
        !           566:         }
        !           567:     }
        !           568:     return $result;
        !           569: }
        !           570: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>