1: #!/usr/bin/perl -w
2: #
3: # The LearningOnline Network
4: #
5: # $Id: modify_config_files.pl,v 1.26 2024/07/09 14:18:16 raeburn Exp $
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:
39: This script modifies local MySQL configuration file(s), which will be:
40: /home/www/.my.cnf and, depending on distro/version also one of:
41: /etc/my.cnf, /etc/mysql/my.cnf, /etc/mysql/mysql.conf.d/mysqld.cnf,
42: or /etc/mysql/mariadb.conf.d/50-server.cnf, and also the file used to
43: store information about the LON-CAPA package repositories located at
44: install.loncapa.org. which provide rpm or deb packages created for the
45: Linux distro/version being used. The file to modify will be one of:
46: /etc/yum.conf (for CentOS/Scientific Linux/RHEL >=5 and <8),
47: /etc/apt/sources.list (for Debian < 10 and Ubuntu < 22), or
48: /etc/apt/sources.list.d/loncapa.list (for Debian >= 10 and Ubuntu > 20),
49: /etc/sysconfig/rhn/sources (for RHEL4), or /etc/yum.repos.d/loncapa.repo
50: (for Fedora >= 21; Oracle Linux; AlmaLinux; RockyLinux; CentOS/RHEL >= 8).
51:
52: The script also modifies /home/www/.inputrc on Linux distros which have
53: readline 8.1 or newer, i.e., CentOS/Scientific Linux/RHEL >= 9,
54: Ubuntu >= 22, Debian >= 12, and Fedora >= 34.
55:
56: =head1 DESCRIPTION
57:
58: This script will modify /etc/my.cnf, /etc/mysql/my.cnf,
59: /etc/mysql/mysql.conf.d/mysqld.cnf, or
60: /etc/mysql/mariadb.conf.d/50-server.cnf,
61: and /etc/yum.conf, /etc/yum.repos.d/loncapa.repo,
62: /etc/apt/sources.list, /etc/apt/sources.list.d/loncapa.list or
63: /etc/sysconfig/rhn/sources and /home/www/.inputrc to ensure
64: certain parameters are set properly.
65:
66: The LON-CAPA yum repositories are added to /etc/yum.conf,
67: /etc/yum.repos.d/loncapa.repo, or /etc/sysconfig/rhn/sources
68: and the LON-CAPA apt repositories are added to
69: /etc/apt/sources.list or /etc/apt/sources.list.d/loncapa.list.
70:
71: The /etc/my.cnf, /etc/mysql/my.cnf /etc/mysql/mysql.conf.d/mysqld.cnf
72: or /etc/mysql/mariadb.conf.d/50-server.cnf file is modified to set the
73: wait_timeout to 1 year. Backup copies of each file are made in
74: /etc, /etc/apt, and /etc/sysconfig/rhn, as appropriate.
75:
76: =cut
77:
78: use strict;
79: use File::Copy;
80: use lib '/home/httpd/lib/perl/';
81: use LONCAPA::Configuration;
82: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
83:
84: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
85: my $dist = <DSH>;
86: chomp($dist);
87: close(DSH);
88:
89: my $yum_status;
90: my $loninst = 'http://install.loncapa.org';
91: my $loninst_re = 'http://install\.loncapa\.org';
92: if ($dist =~ /^fedora(\d+)$/) {
93: my $file = '/etc/yum.conf';
94: my $ver = $1;
95: my $gpgchk = '0';
96: my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa";
97: my $nobackup;
98: if ($ver > 6) {
99: $gpgchk = '1';
100: }
101: if ($ver >= 21) {
102: $file = '/etc/yum.repos.d/loncapa.repo';
103: $nobackup = 1;
104: }
105: $yum_status =
106: &update_file($file,
107: [{section => 'loncapa-updates-basearch',
108: key => 'name=',
109: value => 'Fedora Core $releasever LON-CAPA $basearch Updates',
110: }, {section => 'loncapa-updates-basearch',
111: key => 'baseurl=',
112: value => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
113: }, {section => 'loncapa-updates-basearch',
114: key => 'gpgcheck=',
115: value => $gpgchk,
116: }, {section => 'loncapa-updates-basearch',
117: key => 'gpgkey=',
118: value => $gpg,
119: }, {section => 'loncapa-updates-noarch',
120: key => 'name=',
121: value => 'Fedora Core $releasever LON-CAPA noarch Updates',
122: }, {section => 'loncapa-updates-noarch',
123: key => 'baseurl=',
124: value => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
125: }, {section => 'loncapa-updates-noarch',
126: key => 'gpgcheck=',
127: value => $gpgchk,
128: }, {section => 'loncapa-updates-noarch',
129: key => 'gpgkey=',
130: value => $gpg,
131: }],$nobackup);
132: } elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)(|\-stream)$/) {
133: my $type = $1;
134: my $ver = $2;
135: my $stream = $3;
136: my $longver = $ver;
137: my $nobackup;
138: if ($type eq 'rhes') {
139: if ($ver == 4) {
140: $longver = '4ES';
141: } elsif ($ver == 5) {
142: $longver = '5Server';
143: }
144: } elsif ($type eq 'centos') {
145: $type .= $stream;
146: }
147: my %info = (
148: rhes => {
149: title => 'RHEL',
150: path => 'redhat/linux/enterprise/loncapa',
151: gpg => 'versions/redhat/RPM-GPG-KEY-loncapa',
152: gpgchk => 1,
153: },
154: centos => {
155: title => 'CentOS',
156: path => 'centos/loncapa',
157: gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
158: gpgchk => 1,
159: },
160: scientific => {
161: title => 'Scientific Linux',
162: path => 'scientific/loncapa',
163: gpg => 'versions/scientific/RPM-GPG-KEY-loncapa',
164: gpgchk => 1,
165: },
166: oracle => {
167: title => 'Oracle Linux',
168: path => 'oracle/loncapa',
169: gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
170: gpgchk => 1,
171: },
172: rocky => {
173: title => 'Rocky Linux',
174: path => 'rocky/loncapa',
175: gpg => 'versions/rocky/RPM-GPG-KEY-loncapa',
176: gpgchk => 1,
177: },
178: alma => {
179: title => 'AlmaLinux',
180: path => 'alma/loncapa',
181: gpg => 'versions/alma/RPM-GPG-KEY-loncapa',
182: gpgchk => 1,
183: },
184: 'centos-stream' => {
185: title => 'CentOS Stream',
186: path => 'centos/loncapa',
187: gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
188: gpgchk => 1,
189: },
190: );
191: if (ref($info{$type}) eq 'HASH') {
192: if ($ver > 4) {
193: my $file = '/etc/yum.conf';
194: if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') ||
195: ($type eq 'alma') || ($type eq 'centos-stream')) {
196: $file = '/etc/yum.repos.d/loncapa.repo';
197: $nobackup = 1;
198: }
199: my $release = '$releasever';
200: if ($type eq 'centos-stream') {
201: $release .= '-stream';
202: }
203: $yum_status =
204: &update_file($file,
205: [{section => 'loncapa-updates-basearch',
206: key => 'name=',
207: value => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates',
208: }, {section => "loncapa-updates-basearch",
209: key => 'baseurl=',
210: value => "$loninst/$info{$type}{path}/$release/".'$basearch',
211: }, {section => 'loncapa-updates-basearch',
212: key => 'gpgcheck=',
213: value => $info{$type}{gpgchk},
214: }, {section => 'loncapa-updates-basearch',
215: key => 'gpgkey=',
216: value => "$loninst/$info{$type}{gpg}",
217: }, {section => 'loncapa-updates-noarch',
218: key => 'name=',
219: value => $info{$type}{title}.' $releasever LON-CAPA noarch Updates',
220: }, {section => 'loncapa-updates-noarch',
221: key => 'baseurl=',
222: value => "$loninst/$info{$type}{path}/$release/noarch",
223: }, {section => 'loncapa-updates-noarch',
224: key => 'gpgcheck=',
225: value => $info{$type}{gpgchk},
226: }, {section => 'loncapa-updates-noarch',
227: key => 'gpgkey=',
228: value => "$loninst/$info{$type}{gpg}",
229: }],$nobackup);
230: } elsif (($type eq 'rhes') && ($ver == 4)) {
231: my %rhn = (
232: basearch => {
233: regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH',
234: text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH',
235: },
236: noarch => {
237: regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch',
238: text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch",
239: },
240: );
241: $yum_status = &update_rhn_source(\%rhn);
242: }
243: }
244: } elsif ($dist =~ /^(debian|ubuntu)(\d+)$/) {
245: my ($distname,$distver) = ($1,$2);
246: if ((($distname eq 'ubuntu') && ($distver > 20)) ||
247: (($distname eq 'debian') && ($distver >= 10))) {
248: $loninst = 'https://install.loncapa.org';
249: $loninst_re = 'https://install\.loncapa\.org';
250: }
251: my %apt_get_source = (
252: debian5 => {
253: regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
254: text => "deb $loninst/debian lenny main",
255: },
256: debian6 => {
257: regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+squeeze\s+main',
258: text => "deb $loninst/debian squeeze main",
259: },
260: debian10 => {
261: regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+buster\s+main',
262: text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian buster main",
263: },
264: debian11 => {
265: regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+bullseye\s+main',
266: text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian bullseye main",
267: },
268: debian12 => {
269: regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+bookworm\s+main',
270: text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian bookworm main",
271: },
272:
273: ubuntu6 => {
274: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+dapper\s+main',
275: text => "deb $loninst/ubuntu dapper main",
276: },
277: ubuntu8 => {
278: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+hardy\s+main',
279: text => "deb $loninst/ubuntu hardy main",
280: },
281: ubuntu10 => {
282: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
283: text => "deb $loninst/ubuntu lucid main",
284: },
285: ubuntu12 => {
286: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
287: text => "deb $loninst/ubuntu precise main",
288: },
289: ubuntu14 => {
290: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
291: text => "deb $loninst/ubuntu trusty main",
292: },
293: ubuntu16 => {
294: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
295: text => "deb $loninst/ubuntu xenial main",
296: },
297: ubuntu18 => {
298: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
299: text => "deb $loninst/ubuntu bionic main",
300: },
301: ubuntu20 => {
302: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
303: text => "deb $loninst/ubuntu focal main",
304: },
305: ubuntu22 => {
306: regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/ubuntu/?\s+jammy\s+main',
307: text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/ubuntu jammy main",
308: },
309: ubuntu24 => {
310: regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/ubuntu/?\s+noble\s+main',
311: text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/ubuntu noble main",
312: },
313: );
314: my $apt_status;
315: if (defined($apt_get_source{$dist})) {
316: $apt_status = &update_apt_source($distname,$distver,$apt_get_source{$dist});
317: }
318: }
319:
320: my $mysqlfile = '/etc/my.cnf';
321: my $mysqlconf = [{section =>'mysqld',
322: key =>'wait_timeout=',
323: value =>'31536000'}];
324: my $nomysqlbackup;
325: if ($dist =~ /^ubuntu(\d+)$/) {
326: my $version = $1;
327: $mysqlfile = '/etc/mysql/my.cnf';
328: if ($version > 14) {
329: $nomysqlbackup = 1;
330: $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
331: if ($version < 20) {
332: push(@{$mysqlconf},
333: {section =>'mysqld',
334: key =>'sql_mode=',
335: value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"'});
336: } else {
337: push(@{$mysqlconf},
338: {section =>'mysqld',
339: key =>'sql_mode=',
340: value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'});
341: }
342: }
343: } elsif ($dist =~ /^debian(\d+)$/) {
344: my $version = $1;
345: if ($version >= 10) {
346: $mysqlfile = '/etc/mysql/mariadb.conf.d/50-server.cnf';
347: $nomysqlbackup = 1;
348: }
349: }
350:
351: my $mysql_global_status = &update_file($mysqlfile,$mysqlconf,$nomysqlbackup);
352:
353: my $local_my_cnf = '/home/www/.my.cnf';
354: if (! -e $local_my_cnf) {
355: # Create a file so we can do something with it...
356: system("touch $local_my_cnf");
357: }
358: my $mysql_www_status =
359: &update_file($local_my_cnf,
360: [{section =>'client',
361: key =>'user=',
362: value =>'www',},
363: {section =>'client',
364: key =>'password=',
365: value =>$loncapa_config->{'lonSqlAccess'}},]);
366:
367: my $needs_inputrc_check;
368: if ($dist =~ /^debian(\d+)$/) {
369: if ($1 >= 12) {
370: $needs_inputrc_check = 1;
371: }
372: } elsif ($dist =~ /^ubuntu(\d+)$/) {
373: if ($1 >= 22) {
374: $needs_inputrc_check = 1;
375: }
376: } elsif ($dist =~ /^(?:redhat|oracle|alma|rocky|centos-stream)(\d+)$/) {
377: if ($1 >= 9) {
378: $needs_inputrc_check = 1;
379: }
380: } elsif ($dist =~ /^fedora(\d+)$/) {
381: if ($1 >= 34) {
382: $needs_inputrc_check = 1;
383: }
384: }
385:
386: if ($needs_inputrc_check) {
387: my $bash_www_cnf = '/home/www/.inputrc';
388: if (!-e $bash_www_cnf) {
389: system("touch $bash_www_cnf");
390: if (open(my $fh,'>',$bash_www_cnf)) {
391: print $fh "set enable-bracketed-paste off\n";
392: close($fh);
393: } else {
394: warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
395: }
396: my $wwwuid = getpwnam('www');
397: my $wwwgid = getgrnam('www');
398: if ($wwwuid!=$<) {
399: chown($wwwuid,$wwwgid,$bash_www_cnf);
400: }
401: } else {
402: my ($bracketed_paste_on,$bracketed_paste_off,@preserve);
403: if (open(my $fh,'<',$bash_www_cnf)) {
404: while (my $line=<$fh>) {
405: chomp($line);
406: if ($line =~ /^\s*set\s+enable\-bracketed\-paste\s+(off|on)\s*$/) {
407: if ($1 eq 'off') {
408: $bracketed_paste_off = 1;
409: } else {
410: $bracketed_paste_on = 1;
411: }
412: } else {
413: push(@preserve,$line);
414: }
415: }
416: close($fh);
417: }
418: if ($bracketed_paste_on || !$bracketed_paste_off) {
419: if (open(my $fh,'>',$bash_www_cnf)) {
420: print $fh "set enable-bracketed-paste off\n";
421: if (@preserve) {
422: foreach my $entry (@preserve) {
423: print $fh "$entry\n";
424: }
425: }
426: close($fh);
427: } else {
428: warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
429: }
430: }
431: }
432: }
433:
434: my $exitvalue = 0;
435:
436: if ($mysql_global_status) { $exitvalue = 1; }
437:
438: exit $exitvalue;
439:
440: #################################################################
441: #################################################################
442:
443: =pod
444:
445: =over 4
446:
447: =item &update_file()
448:
449: Calls &parse_config_file for a file and then sends the
450: retrieved data to &modify_config_file, and checks if
451: modificatione were made.
452:
453: Inputs: filename, newdata (reference to an array of hashed),
454: nobackup 1, if no backup of existing file (.backup
455: appended to filename) should be made.
456:
457: Output: 0 or 1; o if no modifications exist (and hence no file
458: needed to be saved, or 1 if modifications made, and call to
459: &write_config_file to save file, or if filename does not exist.
460:
461: =back
462:
463: =cut
464:
465: #################################################################
466: #################################################################
467:
468:
469: sub update_file {
470: my ($file,$newdata,$nobackup) = @_;
471: return 1 if (! -e $file);
472: unless ($nobackup) {
473: my $backup = $file.'.backup';
474: if (! copy($file,$backup)) {
475: warn "**** Error: Unable to make backup of $file";
476: return 0;
477: }
478: }
479: my ($filedata) = &parse_config_file($file);
480: if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
481: my $modified = 0;
482: foreach my $data (@$newdata) {
483: my $section = $data->{'section'};
484: my $key = $data->{'key'};
485: my $value = $data->{'value'};
486: my $result = &modify_config_file($filedata,$section,$key,$value);
487: if ($result) { $modified = 1; }
488: }
489: if ($modified) {
490: my $result = &write_config_file($file,$filedata);
491: if (defined($result)) { warn 'Error:'.$result; return 0; }
492: }
493: return $modified;
494: }
495:
496: #################################################################
497: #################################################################
498:
499: =pod
500:
501: =over 4
502:
503: =item &parse_config_file()
504:
505: Read a configuration file in and parse it into an internal data structure.
506:
507: Input: filename
508:
509: Output: array ref $filedata OR scalar error message
510:
511: =back
512:
513: =cut
514:
515: #################################################################
516: #################################################################
517: sub parse_config_file {
518: my ($file) = @_;
519: open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
520: my @Input = <INFILE>;
521: close(INFILE);
522: my @Structure;
523: my %Sections;
524: while (my $line = shift(@Input)) {
525: chomp($line);
526: if ($line =~ /^\[([^\]]*)\]/) {
527: my $section_id = $1;
528: push(@Structure,'__section__'.$section_id);
529: while ($line = shift(@Input)) {
530: chomp($line);
531: if ($line =~ /^\[([^\]]*)\]/) {
532: unshift(@Input,$line);
533: last;
534: } else {
535: push(@{$Sections{$section_id}},$line);
536: }
537: }
538: } else {
539: push(@Structure,$line);
540: }
541: }
542: my $filedata = [\@Structure,\%Sections];
543: return $filedata;
544: }
545:
546: #################################################################
547: #################################################################
548:
549: =pod
550:
551: =over 4
552:
553: =item &write_config_file()
554:
555: Write a configuration file out based on the internal data structure returned
556: by &parse_config_file
557:
558: Inputs: filename, $filedata (the return value of &parse_config_file
559:
560: Returns: undef on success, scalar error message on failure.
561:
562: =back
563:
564: =cut
565:
566: #################################################################
567: #################################################################
568: sub write_config_file {
569: my ($file,$filedata) = @_;
570: my ($structure,$sections) = @$filedata;
571: if (! defined($structure) || ! ref($structure)) {
572: return 'Bad subroutine inputs';
573: }
574: open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
575: for (my $i=0;$i<scalar(@$structure);$i++) {
576: my $line = $structure->[$i];
577: chomp($line);
578: if ($line =~ /^__section__(.*)$/) {
579: my $section_id = $1;
580: print OUTPUT ('['.$section_id.']'.$/);
581: foreach my $section_line (@{$sections->{$section_id}}) {
582: chomp($section_line);
583: print OUTPUT $section_line.$/;
584: }
585: # Deal with blank lines
586: if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
587: # No need to output a blank line at the end if there is one
588: # already
589: } else {
590: print OUTPUT $/;
591: }
592: } else {
593: print OUTPUT $line.$/;
594: }
595: }
596: close OUTPUT;
597: return undef;
598: }
599:
600: #################################################################
601: #################################################################
602:
603: =pod
604:
605: =over 4
606:
607: =item &modify_config_file()
608:
609: Modifies the internal data structure of a configuration file to include new
610: sections and/or new configuration directives.
611:
612: Inputs: $filedata (see &parse_config_file
613: $section, the [section] the new entry is to reside in. A value of undef will
614: cause the "outer" section (as in yum.conf) to be updated (or have the new
615: value prepended).
616: $newkey: A line which matches this will be replaced with $newkey.$newvalue
617: $newvalue: The new value to be placed with the new key.
618:
619: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
620:
621: =back
622:
623: =cut
624:
625: #################################################################
626: #################################################################
627: sub modify_config_file {
628: my ($filedata,$section,$newkey,$newvalue)=@_;
629: my $modified = 0; # returned value - set to true if the file is modified
630: my ($structure,$sections) = @$filedata;
631: if (! defined($newvalue)) {
632: $newvalue = '';
633: }
634: my $newline = $newkey.$newvalue;
635: #
636: # Determine which array ref gets the item
637: my $target;
638: if (defined($section)) {
639: if (! exists($sections->{$section})) {
640: push(@$structure,'__section__'.$section);
641: $sections->{$section}=[];
642: }
643: $target = $sections->{$section};
644: } else {
645: $target = $structure;
646: }
647: #
648: # Put the item in or update it.
649: my $key_is_new = 1;
650: for (my $i=0;$i<scalar(@$target);$i++) {
651: if ($target->[$i] =~/^$newkey/) {
652: if ($target->[$i] ne $newline) {
653: $target->[$i]=$newline;
654: $modified = 1;
655: }
656: $key_is_new = 0;
657: last;
658: }
659: }
660: if ($key_is_new) {
661: if (! defined($section)) {
662: unshift(@$target,$newline);
663: } else {
664: # No need to put things after a blank line.
665: if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
666: $target->[-1] = $newline;
667: $modified = 1;
668: } else {
669: push(@$target,$newline);
670: $modified = 1;
671: }
672: }
673: }
674: return $modified;
675: }
676:
677: #################################################################
678: #################################################################
679:
680: =pod
681:
682: =over 4
683:
684: =item &update_rhn_source()
685:
686: Modifies the Red Hat 4 sources file which includes repositories used by up2date
687:
688: Inputs:
689: $rhn_items - a reference to hash of a hash containing the regular expression
690: to test for, and the text string to append to the file, if an entry for the
691: LON-CAPA RHEL repository is missing for two cases:
692:
693: (a) basearch
694: (b) noarch
695:
696: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
697:
698: =back
699:
700: =cut
701:
702: #################################################################
703: #################################################################
704: sub update_rhn_source {
705: my ($rhn_items) = @_;
706: return 0 if (ref($rhn_items) ne 'HASH');
707: return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
708: my $file = '/etc/sysconfig/rhn/sources';
709: return 0 if (! -e $file);
710: my $backup = $file.'.backup';
711: if (! copy($file,$backup)) {
712: warn "**** Error: Unable to make backup of $file";
713: return 0;
714: }
715: my $result = 0;
716: my $fh;
717: if (open($fh,'<',$file)) {
718: my $total = 0;
719: my %found;
720: foreach my $item (keys(%{$rhn_items})) {
721: $found{$item} = 0;
722: }
723: while(<$fh>) {
724: foreach my $item (keys(%{$rhn_items})) {
725: if (ref($rhn_items->{$item}) eq 'HASH') {
726: my $pattern = $rhn_items->{$item}->{regexp};
727: if ($pattern ne '') {
728: if (m{^$pattern}) {
729: $found{$item} = 1;
730: $total ++;
731: }
732: }
733: }
734: }
735: last if $total == 2;
736: }
737: close($fh);
738: if ($total < 2) {
739: if (open($fh,'>>',$file)) {
740: foreach my $item (keys(%{$rhn_items})) {
741: unless ($found{$item}) {
742: if (ref($rhn_items->{$item}) eq 'HASH') {
743: if ($rhn_items->{$item}->{text} ne '') {
744: print $fh "\n".$rhn_items->{$item}->{text}."\n";
745: $result = 1;
746: }
747: }
748: }
749: }
750: close($fh);
751: }
752: }
753: }
754: return $result;
755: }
756:
757: #################################################################
758: #################################################################
759:
760: =pod
761:
762: =over 4
763:
764: =item &update_apt_source()
765:
766: Modifies either the sources.list or sources.list.d/loncapa.list
767: file which include repositories used by apt-get.
768:
769: Inputs:
770: $distname - distro (without version): debian or ubuntu
771: $distver - distro version, e.g., 12 or 24
772: $deb_row - a reference to a hash containing the regular expression
773: to test for, and the text string to append to the file, if an entry
774: for the LON-CAPA Debian/ or Ubuntu repository is missing.
775:
776: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
777:
778: =back
779:
780: =cut
781:
782: #################################################################
783: #################################################################
784: sub update_apt_source {
785: my ($distname,$distver,$deb_row) = @_;
786: return 0 if (ref($deb_row) ne 'HASH');
787: return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
788: my $file = '/etc/apt/sources.list';
789: my $nobackup;
790: if ((($distname eq 'ubuntu') && ($distver > 20)) ||
791: (($distname eq 'debian') && ($distver >= 10))) {
792: $file = '/etc/apt/sources.list.d/loncapa.list';
793: $nobackup = 1;
794: }
795: return 0 if (! -e $file);
796: unless ($nobackup) {
797: my $backup = $file.'.backup';
798: if (! copy($file,$backup)) {
799: warn "**** Error: Unable to make backup of $file";
800: return 0;
801: }
802: }
803: my $result = 0;
804: my $fh;
805: if (open($fh,'<',$file)) {
806: my $found = 0;
807: my $pattern = $deb_row->{regexp};
808: while(<$fh>) {
809: if (m{^$pattern}) {
810: $found = 1;
811: last;
812: }
813: }
814: close($fh);
815: if (!$found) {
816: if (open($fh,'>>',$file)) {
817: print $fh "\n".$deb_row->{text}."\n";
818: close($fh);
819: $result = 1;
820: }
821: }
822: }
823: return $result;
824: }
825:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>