Annotation of loncom/debugging_tools/modify_config_files.pl, revision 1.21
1.1 matthew 1: #!/usr/bin/perl -w
2: #
3: # The LearningOnline Network
4: #
1.21 ! raeburn 5: # $Id: modify_config_files.pl,v 1.20 2021/03/25 13:23:07 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
1.16 raeburn 40: (for CentOS/Scientific Linux/RHEL >=5 and <8), /etc/apt/sources.list
1.13 raeburn 41: (for Debian/Ubuntu), /etc/sysconfig/rhn/sources (for RHEL4),
1.16 raeburn 42: and /etc/yum.repos.d/loncapa.repo (Fedora >= 21; Oracle Linux;
43: CentOS/RHEL >= 8).
1.1 matthew 44:
45: =head1 DESCRIPTION
46:
1.13 raeburn 47: This script modifies /etc/my.cnf, /etc/yum.conf, /etc/yum.repos.d/loncapa.repo,
48: /etc/apt/sources, or /etc/sysconfig/rhn/sources to ensure certain
49: parameters are set properly.
50:
51: The LON-CAPA yum repositories are added to /etc/yum.conf,
52: /etc/yum.repos.d/loncapa.repo, /etc/sysconfig/rhn/sources
53: and the LON-CAPA apt repositories are added to
1.9 raeburn 54: /etc/apt/sources.list.
55:
1.1 matthew 56: The /etc/my.cnf file is modified to set the wait_timeout to 1 year. Backup
1.9 raeburn 57: copies of each file are made in /etc, /etc/apt, and /etc/sysconfig/rhn, as
58: appropriate.
1.1 matthew 59:
60: =cut
61:
62: use strict;
63: use File::Copy;
1.3 matthew 64: use lib '/home/httpd/lib/perl/';
65: use LONCAPA::Configuration;
66: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
1.1 matthew 67:
1.6 raeburn 68: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
69: my $dist = <DSH>;
70: chomp($dist);
71: close(DSH);
72:
73: my $yum_status;
1.9 raeburn 74: my $loninst = 'http://install.loncapa.org';
75: my $loninst_re = 'http://install\.loncapa\.org';
76: if ($dist =~ /^fedora(\d+)$/) {
1.13 raeburn 77: my $file = '/etc/yum.conf';
1.9 raeburn 78: my $ver = $1;
1.10 raeburn 79: my $gpgchk = '0';
1.9 raeburn 80: my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa";
1.13 raeburn 81: my $nobackup;
1.9 raeburn 82: if ($ver > 6) {
1.10 raeburn 83: $gpgchk = '1';
1.9 raeburn 84: }
1.13 raeburn 85: if ($ver >= 21) {
86: $file = '/etc/yum.repos.d/loncapa.repo';
87: $nobackup = 1;
88: }
1.6 raeburn 89: $yum_status =
1.13 raeburn 90: &update_file($file,
1.10 raeburn 91: [{section => 'loncapa-updates-basearch',
1.1 matthew 92: key => 'name=',
1.6 raeburn 93: value => 'Fedora Core $releasever LON-CAPA $basearch Updates',
1.10 raeburn 94: }, {section => 'loncapa-updates-basearch',
1.1 matthew 95: key => 'baseurl=',
1.9 raeburn 96: value => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
1.10 raeburn 97: }, {section => 'loncapa-updates-basearch',
1.5 matthew 98: key => 'gpgcheck=',
1.9 raeburn 99: value => $gpgchk,
1.10 raeburn 100: }, {section => 'loncapa-updates-basearch',
1.13 raeburn 101: key => 'gpgkey=',
1.9 raeburn 102: value => $gpg,
1.1 matthew 103: }, {section => 'loncapa-updates-noarch',
104: key => 'name=',
105: value => 'Fedora Core $releasever LON-CAPA noarch Updates',
106: }, {section => 'loncapa-updates-noarch',
107: key => 'baseurl=',
1.9 raeburn 108: value => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
1.5 matthew 109: }, {section => 'loncapa-updates-noarch',
110: key => 'gpgcheck=',
1.9 raeburn 111: value => $gpgchk,
112: }, {section => 'loncapa-updates-noarch',
1.13 raeburn 113: key => 'gpgkey=',
1.9 raeburn 114: value => $gpg,
1.13 raeburn 115: }],$nobackup);
1.21 ! raeburn 116: } elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)$/) {
1.9 raeburn 117: my $type = $1;
118: my $ver = $2;
119: my $longver = $ver;
1.16 raeburn 120: my $nobackup;
1.9 raeburn 121: if ($type eq 'rhes') {
122: if ($ver == 4) {
123: $longver = '4ES';
124: } elsif ($ver == 5) {
125: $longver = '5Server';
126: }
127: }
128: my %info = (
129: rhes => {
130: title => 'RHEL',
131: path => 'redhat/linux/enterprise/loncapa',
132: gpg => 'versions/redhat/RPM-GPG-KEY-loncapa',
133: gpgchk => 1,
134: },
135: centos => {
136: title => 'CentOS',
137: path => 'centos/loncapa',
138: gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
139: gpgchk => 1,
140: },
141: scientific => {
142: title => 'Scientific Linux',
143: path => 'scientific/loncapa',
144: gpg => 'versions/scientific/RPM-GPG-KEY-loncapa',
145: gpgchk => 1,
146: },
1.15 raeburn 147: oracle => {
148: title => 'Oracle Linux',
149: path => 'oracle/loncapa',
150: gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
151: gpgchk => 1,
152: },
1.21 ! raeburn 153: rocky => {
! 154: title => 'Rocky Linux',
! 155: path => 'rocky/loncapa',
! 156: gpg => 'versions/rocky/RPM-GPG-KEY-loncapa',
! 157: gpgchk => 1,
! 158: },
! 159: alma => {
! 160: title => 'AlmaLinux',
! 161: path => 'alma/loncapa',
! 162: gpg => 'versions/alma/RPM-GPG-KEY-loncapa',
! 163: gpgchk => 1,
! 164: },
1.9 raeburn 165: );
166: if (ref($info{$type}) eq 'HASH') {
167: if ($ver > 4) {
1.16 raeburn 168: my $file = '/etc/yum.conf';
1.21 ! raeburn 169: if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') || ($type eq 'alma')) {
1.16 raeburn 170: $file = '/etc/yum.repos.d/loncapa.repo';
171: $nobackup = 1;
172: }
1.9 raeburn 173: $yum_status =
1.16 raeburn 174: &update_file($file,
1.9 raeburn 175: [{section => 'loncapa-updates-basearch',
176: key => 'name=',
177: value => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates',
178: }, {section => "loncapa-updates-basearch",
179: key => 'baseurl=',
180: value => "$loninst/$info{$type}{path}/".'$releasever/$basearch',
181: }, {section => 'loncapa-updates-basearch',
182: key => 'gpgcheck=',
1.11 raeburn 183: value => $info{$type}{gpgchk},
1.10 raeburn 184: }, {section => 'loncapa-updates-basearch',
1.9 raeburn 185: key => 'gpgkey=',
186: value => "$loninst/$info{$type}{gpg}",
187: }, {section => 'loncapa-updates-noarch',
188: key => 'name=',
189: value => $info{$type}{title}.' $releasever LON-CAPA noarch Updates',
190: }, {section => 'loncapa-updates-noarch',
191: key => 'baseurl=',
192: value => "$loninst/$info{$type}{path}/".'$releasever/noarch',
193: }, {section => 'loncapa-updates-noarch',
194: key => 'gpgcheck=',
1.11 raeburn 195: value => $info{$type}{gpgchk},
1.9 raeburn 196: }, {section => 'loncapa-updates-noarch',
197: key => 'gpgkey=',
198: value => "$loninst/$info{$type}{gpg}",
1.16 raeburn 199: }],$nobackup);
1.9 raeburn 200: } elsif (($type eq 'rhes') && ($ver == 4)) {
201: my %rhn = (
202: basearch => {
203: regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH',
204: text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH',
205: },
206: noarch => {
207: regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch',
208: text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch",
209: },
210: );
211: $yum_status = &update_rhn_source(\%rhn);
212: }
213: }
214: } elsif ($dist =~ /^(debian|ubuntu)\d+$/) {
215: my %apt_get_source = (
216: debian5 => {
1.18 raeburn 217: regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
218: text => "deb $loninst/debian lenny main",
1.9 raeburn 219: },
220: ubuntu6 => {
1.18 raeburn 221: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+dapper\s+main',
222: text => "deb $loninst/ubuntu dapper main",
1.9 raeburn 223: },
224: ubuntu8 => {
1.18 raeburn 225: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+hardy\s+main',
226: text => "deb $loninst/ubuntu hardy main",
1.9 raeburn 227: },
1.14 raeburn 228: ubuntu10 => {
1.18 raeburn 229: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
230: text => "deb $loninst/ubuntu lucid main",
1.14 raeburn 231: },
232: ubuntu12 => {
1.18 raeburn 233: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
234: text => "deb $loninst/ubuntu precise main",
1.14 raeburn 235: },
236: ubuntu14 => {
1.18 raeburn 237: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
238: text => "deb $loninst/ubuntu trusty main",
1.14 raeburn 239: },
240: ubuntu16 => {
1.18 raeburn 241: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
242: text => "deb $loninst/ubuntu xenial main",
1.14 raeburn 243: },
244: ubuntu18 => {
1.18 raeburn 245: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
246: text => "deb $loninst/ubuntu bionic main",
1.14 raeburn 247: },
1.17 raeburn 248: ubuntu20 => {
1.18 raeburn 249: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
250: text => "deb $loninst/ubuntu focal main",
1.17 raeburn 251: },
1.9 raeburn 252: );
253: my $apt_status;
254: if (defined($apt_get_source{$dist})) {
255: $apt_status = &update_apt_source($apt_get_source{$dist},);
1.6 raeburn 256: }
257: }
1.1 matthew 258:
1.19 raeburn 259: my $mysqlfile = '/etc/my.cnf';
1.20 raeburn 260: my $mysqlconf = [{section =>'mysqld',
261: key =>'wait_timeout=',
262: value =>'31536000'}];
1.19 raeburn 263: if ($dist =~ /^ubuntu(\d+)$/) {
264: my $version = $1;
265: $mysqlfile = '/etc/mysql/my.cnf';
266: if ($version > 14) {
267: $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
1.20 raeburn 268: if ($version < 20) {
269: push(@{$mysqlconf},
270: {section =>'mysqld',
271: key =>'sql_mode=',
272: value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"'});
273: } else {
274: push(@{$mysqlconf},
275: {section =>'mysqld',
276: key =>'sql_mode=',
277: value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'});
278: }
1.19 raeburn 279: }
280: }
281:
1.20 raeburn 282: my $mysql_global_status = &update_file($mysqlfile,$mysqlconf);
1.1 matthew 283:
1.3 matthew 284: my $local_my_cnf = '/home/www/.my.cnf';
285: if (! -e $local_my_cnf) {
1.4 matthew 286: # Create a file so we can do something with it...
1.3 matthew 287: system("touch $local_my_cnf");
288: }
1.4 matthew 289: my $mysql_www_status =
290: &update_file($local_my_cnf,
1.3 matthew 291: [{section =>'client',
292: key =>'user=',
293: value =>'www',},
294: {section =>'client',
295: key =>'password=',
296: value =>$loncapa_config->{'lonSqlAccess'}},]);
297:
1.4 matthew 298: my $exitvalue = 0;
299:
300: if ($mysql_global_status) { $exitvalue = 1; }
301:
302: exit $exitvalue;
1.1 matthew 303:
304:
305: sub update_file {
1.13 raeburn 306: my ($file,$newdata,$nobackup) = @_;
1.1 matthew 307: return 1 if (! -e $file);
1.13 raeburn 308: unless ($nobackup) {
309: my $backup = $file.'.backup';
310: if (! copy($file,$backup)) {
311: warn "**** Error: Unable to make backup of $file";
312: return 0;
313: }
1.1 matthew 314: }
315: my ($filedata) = &parse_config_file($file);
1.4 matthew 316: if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
317: my $modified = 0;
1.1 matthew 318: foreach my $data (@$newdata) {
319: my $section = $data->{'section'};
320: my $key = $data->{'key'};
321: my $value = $data->{'value'};
1.4 matthew 322: my $result = &modify_config_file($filedata,$section,$key,$value);
323: if ($result) { $modified = 1; }
324: }
325: if ($modified) {
326: my $result = &write_config_file($file,$filedata);
327: if (defined($result)) { warn 'Error:'.$result; return 0; }
1.1 matthew 328: }
1.4 matthew 329: return $modified;
1.1 matthew 330: }
331:
332: #################################################################
333: #################################################################
334:
335: =pod
336:
1.9 raeburn 337: =over 4
338:
339: =item &parse_config_file()
1.1 matthew 340:
341: Read a configuration file in and parse it into an internal data structure.
342:
343: Input: filename
344:
345: Output: array ref $filedata OR scalar error message
346:
1.9 raeburn 347: =back
348:
1.1 matthew 349: =cut
350:
351: #################################################################
352: #################################################################
353: sub parse_config_file {
354: my ($file) = @_;
355: open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
356: my @Input = <INFILE>;
357: close(INFILE);
358: my @Structure;
359: my %Sections;
360: while (my $line = shift(@Input)) {
361: chomp($line);
362: if ($line =~ /^\[([^\]]*)\]/) {
363: my $section_id = $1;
364: push(@Structure,'__section__'.$section_id);
365: while ($line = shift(@Input)) {
1.4 matthew 366: chomp($line);
1.1 matthew 367: if ($line =~ /^\[([^\]]*)\]/) {
368: unshift(@Input,$line);
369: last;
370: } else {
371: push(@{$Sections{$section_id}},$line);
372: }
373: }
374: } else {
375: push(@Structure,$line);
376: }
377: }
378: my $filedata = [\@Structure,\%Sections];
379: return $filedata;
380: }
381:
382: #################################################################
383: #################################################################
384:
385: =pod
386:
1.9 raeburn 387: =over 4
388:
1.1 matthew 389: =item
390:
391: Write a configuration file out based on the internal data structure returned
392: by &parse_config_file
393:
394: Inputs: filename, $filedata (the return value of &parse_config_file
395:
396: Returns: undef on success, scalar error message on failure.
397:
1.9 raeburn 398: =back
399:
1.1 matthew 400: =cut
401:
402: #################################################################
403: #################################################################
404: sub write_config_file {
405: my ($file,$filedata) = @_;
406: my ($structure,$sections) = @$filedata;
407: if (! defined($structure) || ! ref($structure)) {
408: return 'Bad subroutine inputs';
409: }
1.18 raeburn 410: open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
1.1 matthew 411: for (my $i=0;$i<scalar(@$structure);$i++) {
412: my $line = $structure->[$i];
413: chomp($line);
414: if ($line =~ /^__section__(.*)$/) {
415: my $section_id = $1;
416: print OUTPUT ('['.$section_id.']'.$/);
417: foreach my $section_line (@{$sections->{$section_id}}) {
418: chomp($section_line);
419: print OUTPUT $section_line.$/;
420: }
421: # Deal with blank lines
422: if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
423: # No need to output a blank line at the end if there is one
424: # already
425: } else {
426: print OUTPUT $/;
427: }
428: } else {
429: print OUTPUT $line.$/;
430: }
431: }
432: close OUTPUT;
433: return undef;
434: }
435:
436: #################################################################
437: #################################################################
438:
439: =pod
440:
1.9 raeburn 441: =over 4
442:
443: =item &modify_config_file()
1.1 matthew 444:
445: Modifies the internal data structure of a configuration file to include new
446: sections and/or new configuration directives.
447:
448: Inputs: $filedata (see &parse_config_file
449: $section, the [section] the new entry is to reside in. A value of undef will
450: cause the "outer" section (as in yum.conf) to be updated (or have the new
451: value prepended).
452: $newkey: A line which matches this will be replaced with $newkey.$newvalue
453: $newvalue: The new value to be placed with the new key.
454:
1.4 matthew 455: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
456:
1.9 raeburn 457: =back
1.4 matthew 458:
1.1 matthew 459: =cut
460:
461: #################################################################
462: #################################################################
463: sub modify_config_file {
464: my ($filedata,$section,$newkey,$newvalue)=@_;
1.4 matthew 465: my $modified = 0; # returned value - set to true if the file is modified
1.1 matthew 466: my ($structure,$sections) = @$filedata;
467: if (! defined($newvalue)) {
468: $newvalue = '';
469: }
470: my $newline = $newkey.$newvalue;
471: #
472: # Determine which array ref gets the item
473: my $target;
474: if (defined($section)) {
475: if (! exists($sections->{$section})) {
476: push(@$structure,'__section__'.$section);
477: $sections->{$section}=[];
478: }
479: $target = $sections->{$section};
480: } else {
481: $target = $structure;
482: }
483: #
484: # Put the item in or update it.
485: my $key_is_new = 1;
486: for (my $i=0;$i<scalar(@$target);$i++) {
487: if ($target->[$i] =~/^$newkey/) {
1.4 matthew 488: if ($target->[$i] ne $newline) {
489: $target->[$i]=$newline;
490: $modified = 1;
491: }
1.1 matthew 492: $key_is_new = 0;
493: last;
494: }
495: }
496: if ($key_is_new) {
497: if (! defined($section)) {
498: unshift(@$target,$newline);
499: } else {
500: # No need to put things after a blank line.
1.2 matthew 501: if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
1.1 matthew 502: $target->[-1] = $newline;
1.4 matthew 503: $modified = 1;
1.1 matthew 504: } else {
505: push(@$target,$newline);
1.4 matthew 506: $modified = 1;
1.1 matthew 507: }
508: }
509: }
1.4 matthew 510: return $modified;
1.1 matthew 511: }
512:
1.9 raeburn 513: #################################################################
514: #################################################################
515:
516: =pod
517:
518: =over 4
519:
520: =item &update_rhn_source()
521:
522: Modifies the Red Hat 4 sources file which includes repositories used by up2date
523:
524: Inputs:
525: $rhn_items - a reference to hash of a hash 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 RHEL repository is missing for two cases:
528:
529: (a) basearch
530: (b) noarch
531:
532: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
533:
534: =back
535:
536: =cut
537:
538: #################################################################
539: #################################################################
540: sub update_rhn_source {
541: my ($rhn_items) = @_;
542: return 0 if (ref($rhn_items) ne 'HASH');
543: return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
544: my $file = '/etc/sysconfig/rhn/sources';
545: return 0 if (! -e $file);
546: my $backup = $file.'.backup';
547: if (! copy($file,$backup)) {
548: warn "**** Error: Unable to make backup of $file";
549: return 0;
550: }
551: my $result = 0;
552: my $fh;
1.18 raeburn 553: if (open($fh,'<',$file)) {
1.9 raeburn 554: my $total = 0;
555: my %found;
556: foreach my $item (keys(%{$rhn_items})) {
557: $found{$item} = 0;
558: }
559: while(<$fh>) {
560: foreach my $item (keys(%{$rhn_items})) {
561: if (ref($rhn_items->{$item}) eq 'HASH') {
562: my $pattern = $rhn_items->{$item}->{regexp};
563: if ($pattern ne '') {
564: if (m{^$pattern}) {
565: $found{$item} = 1;
566: $total ++;
567: }
568: }
569: }
570: }
571: last if $total == 2;
572: }
573: close($fh);
574: if ($total < 2) {
1.18 raeburn 575: if (open($fh,'>>',$file)) {
1.9 raeburn 576: foreach my $item (keys(%{$rhn_items})) {
577: unless ($found{$item}) {
578: if (ref($rhn_items->{$item}) eq 'HASH') {
579: if ($rhn_items->{$item}->{text} ne '') {
580: print $fh "\n".$rhn_items->{$item}->{text}."\n";
581: $result = 1;
582: }
583: }
584: }
585: }
586: close($fh);
587: }
588: }
589: }
590: return $result;
591: }
1.1 matthew 592:
593: #################################################################
594: #################################################################
595:
596: =pod
597:
1.9 raeburn 598: =over 4
599:
600: =item &update_apt_source()
601:
602: Modifies the source.list file which includes repositories used by apt-get
603:
604: Inputs:
605: $deb_row - a reference to containing the regular expression
606: to test for, and the text string to append to the file, if an entry for the
607: LON-CAPA Debian/ or Ubuntu repository is missing.
608:
609: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
610:
1.1 matthew 611: =back
612:
613: =cut
614:
615: #################################################################
616: #################################################################
1.9 raeburn 617: sub update_apt_source {
618: my ($deb_row) = @_;
619: return 0 if (ref($deb_row) ne 'HASH');
620: return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
621: my $file = '/etc/apt/sources.list';
622: return 0 if (! -e $file);
623: my $backup = $file.'.backup';
624: if (! copy($file,$backup)) {
625: warn "**** Error: Unable to make backup of $file";
626: return 0;
627: }
628: my $result = 0;
629: my $fh;
1.18 raeburn 630: if (open($fh,'<',$file)) {
1.9 raeburn 631: my $found = 0;
632: my $pattern = $deb_row->{regexp};
633: while(<$fh>) {
634: if (m{^$pattern}) {
635: $found = 1;
636: last;
637: }
638: }
639: close($fh);
640: if (!$found) {
1.18 raeburn 641: if (open($fh,'>>',$file)) {
1.9 raeburn 642: print $fh "\n".$deb_row->{text}."\n";
643: close($fh);
644: $result = 1;
645: }
646: }
647: }
648: return $result;
649: }
650:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>