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