Annotation of loncom/debugging_tools/modify_config_files.pl, revision 1.25
1.1 matthew 1: #!/usr/bin/perl -w
2: #
3: # The LearningOnline Network
4: #
1.25 ! raeburn 5: # $Id: modify_config_files.pl,v 1.24 2024/06/28 12:46: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.24 raeburn 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).
1.1 matthew 51:
1.25 ! raeburn 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:
1.1 matthew 56: =head1 DESCRIPTION
57:
1.24 raeburn 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
1.25 ! raeburn 63: /etc/sysconfig/rhn/sources and /home/www/.inputrc to ensure
! 64: certain parameters are set properly.
1.13 raeburn 65:
66: The LON-CAPA yum repositories are added to /etc/yum.conf,
1.24 raeburn 67: /etc/yum.repos.d/loncapa.repo, or /etc/sysconfig/rhn/sources
1.13 raeburn 68: and the LON-CAPA apt repositories are added to
1.24 raeburn 69: /etc/apt/sources.list or /etc/apt/sources.list.d/loncapa.list.
1.9 raeburn 70:
1.24 raeburn 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.
1.1 matthew 75:
76: =cut
77:
78: use strict;
79: use File::Copy;
1.3 matthew 80: use lib '/home/httpd/lib/perl/';
81: use LONCAPA::Configuration;
82: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
1.1 matthew 83:
1.6 raeburn 84: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
85: my $dist = <DSH>;
86: chomp($dist);
87: close(DSH);
88:
89: my $yum_status;
1.9 raeburn 90: my $loninst = 'http://install.loncapa.org';
91: my $loninst_re = 'http://install\.loncapa\.org';
92: if ($dist =~ /^fedora(\d+)$/) {
1.13 raeburn 93: my $file = '/etc/yum.conf';
1.9 raeburn 94: my $ver = $1;
1.10 raeburn 95: my $gpgchk = '0';
1.9 raeburn 96: my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa";
1.13 raeburn 97: my $nobackup;
1.9 raeburn 98: if ($ver > 6) {
1.10 raeburn 99: $gpgchk = '1';
1.9 raeburn 100: }
1.13 raeburn 101: if ($ver >= 21) {
102: $file = '/etc/yum.repos.d/loncapa.repo';
103: $nobackup = 1;
104: }
1.6 raeburn 105: $yum_status =
1.13 raeburn 106: &update_file($file,
1.10 raeburn 107: [{section => 'loncapa-updates-basearch',
1.1 matthew 108: key => 'name=',
1.6 raeburn 109: value => 'Fedora Core $releasever LON-CAPA $basearch Updates',
1.10 raeburn 110: }, {section => 'loncapa-updates-basearch',
1.1 matthew 111: key => 'baseurl=',
1.9 raeburn 112: value => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
1.10 raeburn 113: }, {section => 'loncapa-updates-basearch',
1.5 matthew 114: key => 'gpgcheck=',
1.9 raeburn 115: value => $gpgchk,
1.10 raeburn 116: }, {section => 'loncapa-updates-basearch',
1.13 raeburn 117: key => 'gpgkey=',
1.9 raeburn 118: value => $gpg,
1.1 matthew 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=',
1.9 raeburn 124: value => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
1.5 matthew 125: }, {section => 'loncapa-updates-noarch',
126: key => 'gpgcheck=',
1.9 raeburn 127: value => $gpgchk,
128: }, {section => 'loncapa-updates-noarch',
1.13 raeburn 129: key => 'gpgkey=',
1.9 raeburn 130: value => $gpg,
1.13 raeburn 131: }],$nobackup);
1.22 raeburn 132: } elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)(|\-stream)$/) {
1.9 raeburn 133: my $type = $1;
134: my $ver = $2;
1.22 raeburn 135: my $stream = $3;
1.9 raeburn 136: my $longver = $ver;
1.16 raeburn 137: my $nobackup;
1.9 raeburn 138: if ($type eq 'rhes') {
139: if ($ver == 4) {
140: $longver = '4ES';
141: } elsif ($ver == 5) {
142: $longver = '5Server';
143: }
1.22 raeburn 144: } elsif ($type eq 'centos') {
145: $type .= $stream;
1.9 raeburn 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: },
1.15 raeburn 166: oracle => {
167: title => 'Oracle Linux',
168: path => 'oracle/loncapa',
169: gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
170: gpgchk => 1,
171: },
1.21 raeburn 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: },
1.23 raeburn 184: 'centos-stream' => {
1.22 raeburn 185: title => 'CentOS Stream',
186: path => 'centos/loncapa',
187: gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
188: gpgchk => 1,
1.23 raeburn 189: },
1.9 raeburn 190: );
191: if (ref($info{$type}) eq 'HASH') {
192: if ($ver > 4) {
1.16 raeburn 193: my $file = '/etc/yum.conf';
1.22 raeburn 194: if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') ||
195: ($type eq 'alma') || ($type eq 'centos-stream')) {
1.16 raeburn 196: $file = '/etc/yum.repos.d/loncapa.repo';
197: $nobackup = 1;
198: }
1.22 raeburn 199: my $release = '$releasever';
200: if ($type eq 'centos-stream') {
201: $release .= '-stream';
202: }
1.9 raeburn 203: $yum_status =
1.16 raeburn 204: &update_file($file,
1.9 raeburn 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=',
1.22 raeburn 210: value => "$loninst/$info{$type}{path}/$release/".'$basearch',
1.9 raeburn 211: }, {section => 'loncapa-updates-basearch',
212: key => 'gpgcheck=',
1.11 raeburn 213: value => $info{$type}{gpgchk},
1.10 raeburn 214: }, {section => 'loncapa-updates-basearch',
1.9 raeburn 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=',
1.22 raeburn 222: value => "$loninst/$info{$type}{path}/$release/noarch",
1.9 raeburn 223: }, {section => 'loncapa-updates-noarch',
224: key => 'gpgcheck=',
1.11 raeburn 225: value => $info{$type}{gpgchk},
1.9 raeburn 226: }, {section => 'loncapa-updates-noarch',
227: key => 'gpgkey=',
228: value => "$loninst/$info{$type}{gpg}",
1.16 raeburn 229: }],$nobackup);
1.9 raeburn 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: }
1.24 raeburn 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: }
1.9 raeburn 251: my %apt_get_source = (
252: debian5 => {
1.18 raeburn 253: regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
254: text => "deb $loninst/debian lenny main",
1.9 raeburn 255: },
1.24 raeburn 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:
1.9 raeburn 273: ubuntu6 => {
1.18 raeburn 274: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+dapper\s+main',
275: text => "deb $loninst/ubuntu dapper main",
1.9 raeburn 276: },
277: ubuntu8 => {
1.18 raeburn 278: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+hardy\s+main',
279: text => "deb $loninst/ubuntu hardy main",
1.9 raeburn 280: },
1.14 raeburn 281: ubuntu10 => {
1.18 raeburn 282: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
283: text => "deb $loninst/ubuntu lucid main",
1.14 raeburn 284: },
285: ubuntu12 => {
1.18 raeburn 286: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
287: text => "deb $loninst/ubuntu precise main",
1.14 raeburn 288: },
289: ubuntu14 => {
1.18 raeburn 290: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
291: text => "deb $loninst/ubuntu trusty main",
1.14 raeburn 292: },
293: ubuntu16 => {
1.18 raeburn 294: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
295: text => "deb $loninst/ubuntu xenial main",
1.14 raeburn 296: },
297: ubuntu18 => {
1.18 raeburn 298: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
299: text => "deb $loninst/ubuntu bionic main",
1.14 raeburn 300: },
1.17 raeburn 301: ubuntu20 => {
1.18 raeburn 302: regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
303: text => "deb $loninst/ubuntu focal main",
1.17 raeburn 304: },
1.24 raeburn 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: },
1.9 raeburn 313: );
314: my $apt_status;
315: if (defined($apt_get_source{$dist})) {
1.24 raeburn 316: $apt_status = &update_apt_source($distname,$distver,$apt_get_source{$dist});
1.6 raeburn 317: }
318: }
1.1 matthew 319:
1.19 raeburn 320: my $mysqlfile = '/etc/my.cnf';
1.20 raeburn 321: my $mysqlconf = [{section =>'mysqld',
322: key =>'wait_timeout=',
323: value =>'31536000'}];
1.24 raeburn 324: my $nomysqlbackup;
1.19 raeburn 325: if ($dist =~ /^ubuntu(\d+)$/) {
326: my $version = $1;
327: $mysqlfile = '/etc/mysql/my.cnf';
328: if ($version > 14) {
1.24 raeburn 329: $nomysqlbackup = 1;
1.19 raeburn 330: $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
1.20 raeburn 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: }
1.19 raeburn 342: }
1.24 raeburn 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: }
1.19 raeburn 349: }
350:
1.24 raeburn 351: my $mysql_global_status = &update_file($mysqlfile,$mysqlconf,$nomysqlbackup);
1.1 matthew 352:
1.3 matthew 353: my $local_my_cnf = '/home/www/.my.cnf';
354: if (! -e $local_my_cnf) {
1.4 matthew 355: # Create a file so we can do something with it...
1.3 matthew 356: system("touch $local_my_cnf");
357: }
1.4 matthew 358: my $mysql_www_status =
359: &update_file($local_my_cnf,
1.3 matthew 360: [{section =>'client',
361: key =>'user=',
362: value =>'www',},
363: {section =>'client',
364: key =>'password=',
365: value =>$loncapa_config->{'lonSqlAccess'}},]);
366:
1.25 ! raeburn 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: } else {
! 397: my ($bracketed_paste_on,$bracketed_paste_off,@preserve);
! 398: if (open(my $fh,'<',$bash_www_cnf)) {
! 399: while (my $line=<$fh>) {
! 400: chomp($line);
! 401: if ($line =~ /^\s*set\s+enable\-bracketed\-paste\s+(off|on)\s*$/) {
! 402: if ($1 eq 'off') {
! 403: $bracketed_paste_off = 1;
! 404: } else {
! 405: $bracketed_paste_on = 1;
! 406: }
! 407: } else {
! 408: push(@preserve,$line);
! 409: }
! 410: }
! 411: close($fh);
! 412: }
! 413: if ($bracketed_paste_on || !$bracketed_paste_off) {
! 414: if (open(my $fh,'>',$bash_www_cnf)) {
! 415: print $fh "set enable-bracketed-paste off\n";
! 416: if (@preserve) {
! 417: foreach my $entry (@preserve) {
! 418: print $fh "$entry\n";
! 419: }
! 420: }
! 421: close($fh);
! 422: } else {
! 423: warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
! 424: }
! 425: }
! 426: }
! 427: }
! 428:
1.4 matthew 429: my $exitvalue = 0;
430:
431: if ($mysql_global_status) { $exitvalue = 1; }
432:
433: exit $exitvalue;
1.1 matthew 434:
1.24 raeburn 435: #################################################################
436: #################################################################
437:
438: =pod
439:
440: =over 4
441:
442: =item &update_file()
443:
444: Calls &parse_config_file for a file and then sends the
445: retrieved data to &modify_config_file, and checks if
446: modificatione were made.
447:
448: Inputs: filename, newdata (reference to an array of hashed),
449: nobackup 1, if no backup of existing file (.backup
450: appended to filename) should be made.
451:
452: Output: 0 or 1; o if no modifications exist (and hence no file
453: needed to be saved, or 1 if modifications made, and call to
454: &write_config_file to save file, or if filename does not exist.
455:
456: =back
457:
458: =cut
459:
460: #################################################################
461: #################################################################
462:
1.1 matthew 463:
464: sub update_file {
1.13 raeburn 465: my ($file,$newdata,$nobackup) = @_;
1.1 matthew 466: return 1 if (! -e $file);
1.13 raeburn 467: unless ($nobackup) {
468: my $backup = $file.'.backup';
469: if (! copy($file,$backup)) {
470: warn "**** Error: Unable to make backup of $file";
471: return 0;
472: }
1.1 matthew 473: }
474: my ($filedata) = &parse_config_file($file);
1.4 matthew 475: if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
476: my $modified = 0;
1.1 matthew 477: foreach my $data (@$newdata) {
478: my $section = $data->{'section'};
479: my $key = $data->{'key'};
480: my $value = $data->{'value'};
1.4 matthew 481: my $result = &modify_config_file($filedata,$section,$key,$value);
482: if ($result) { $modified = 1; }
483: }
484: if ($modified) {
485: my $result = &write_config_file($file,$filedata);
486: if (defined($result)) { warn 'Error:'.$result; return 0; }
1.1 matthew 487: }
1.4 matthew 488: return $modified;
1.1 matthew 489: }
490:
491: #################################################################
492: #################################################################
493:
494: =pod
495:
1.9 raeburn 496: =over 4
497:
498: =item &parse_config_file()
1.1 matthew 499:
500: Read a configuration file in and parse it into an internal data structure.
501:
502: Input: filename
503:
504: Output: array ref $filedata OR scalar error message
505:
1.9 raeburn 506: =back
507:
1.1 matthew 508: =cut
509:
510: #################################################################
511: #################################################################
512: sub parse_config_file {
513: my ($file) = @_;
514: open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
515: my @Input = <INFILE>;
516: close(INFILE);
517: my @Structure;
518: my %Sections;
519: while (my $line = shift(@Input)) {
520: chomp($line);
521: if ($line =~ /^\[([^\]]*)\]/) {
522: my $section_id = $1;
523: push(@Structure,'__section__'.$section_id);
524: while ($line = shift(@Input)) {
1.4 matthew 525: chomp($line);
1.1 matthew 526: if ($line =~ /^\[([^\]]*)\]/) {
527: unshift(@Input,$line);
528: last;
529: } else {
530: push(@{$Sections{$section_id}},$line);
531: }
532: }
533: } else {
534: push(@Structure,$line);
535: }
536: }
537: my $filedata = [\@Structure,\%Sections];
538: return $filedata;
539: }
540:
541: #################################################################
542: #################################################################
543:
544: =pod
545:
1.9 raeburn 546: =over 4
547:
1.24 raeburn 548: =item &write_config_file()
1.1 matthew 549:
550: Write a configuration file out based on the internal data structure returned
551: by &parse_config_file
552:
553: Inputs: filename, $filedata (the return value of &parse_config_file
554:
555: Returns: undef on success, scalar error message on failure.
556:
1.9 raeburn 557: =back
558:
1.1 matthew 559: =cut
560:
561: #################################################################
562: #################################################################
563: sub write_config_file {
564: my ($file,$filedata) = @_;
565: my ($structure,$sections) = @$filedata;
566: if (! defined($structure) || ! ref($structure)) {
567: return 'Bad subroutine inputs';
568: }
1.18 raeburn 569: open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
1.1 matthew 570: for (my $i=0;$i<scalar(@$structure);$i++) {
571: my $line = $structure->[$i];
572: chomp($line);
573: if ($line =~ /^__section__(.*)$/) {
574: my $section_id = $1;
575: print OUTPUT ('['.$section_id.']'.$/);
576: foreach my $section_line (@{$sections->{$section_id}}) {
577: chomp($section_line);
578: print OUTPUT $section_line.$/;
579: }
580: # Deal with blank lines
581: if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
582: # No need to output a blank line at the end if there is one
583: # already
584: } else {
585: print OUTPUT $/;
586: }
587: } else {
588: print OUTPUT $line.$/;
589: }
590: }
591: close OUTPUT;
592: return undef;
593: }
594:
595: #################################################################
596: #################################################################
597:
598: =pod
599:
1.9 raeburn 600: =over 4
601:
602: =item &modify_config_file()
1.1 matthew 603:
604: Modifies the internal data structure of a configuration file to include new
605: sections and/or new configuration directives.
606:
607: Inputs: $filedata (see &parse_config_file
608: $section, the [section] the new entry is to reside in. A value of undef will
609: cause the "outer" section (as in yum.conf) to be updated (or have the new
610: value prepended).
611: $newkey: A line which matches this will be replaced with $newkey.$newvalue
612: $newvalue: The new value to be placed with the new key.
613:
1.4 matthew 614: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
615:
1.9 raeburn 616: =back
1.4 matthew 617:
1.1 matthew 618: =cut
619:
620: #################################################################
621: #################################################################
622: sub modify_config_file {
623: my ($filedata,$section,$newkey,$newvalue)=@_;
1.4 matthew 624: my $modified = 0; # returned value - set to true if the file is modified
1.1 matthew 625: my ($structure,$sections) = @$filedata;
626: if (! defined($newvalue)) {
627: $newvalue = '';
628: }
629: my $newline = $newkey.$newvalue;
630: #
631: # Determine which array ref gets the item
632: my $target;
633: if (defined($section)) {
634: if (! exists($sections->{$section})) {
635: push(@$structure,'__section__'.$section);
636: $sections->{$section}=[];
637: }
638: $target = $sections->{$section};
639: } else {
640: $target = $structure;
641: }
642: #
643: # Put the item in or update it.
644: my $key_is_new = 1;
645: for (my $i=0;$i<scalar(@$target);$i++) {
646: if ($target->[$i] =~/^$newkey/) {
1.4 matthew 647: if ($target->[$i] ne $newline) {
648: $target->[$i]=$newline;
649: $modified = 1;
650: }
1.1 matthew 651: $key_is_new = 0;
652: last;
653: }
654: }
655: if ($key_is_new) {
656: if (! defined($section)) {
657: unshift(@$target,$newline);
658: } else {
659: # No need to put things after a blank line.
1.2 matthew 660: if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
1.1 matthew 661: $target->[-1] = $newline;
1.4 matthew 662: $modified = 1;
1.1 matthew 663: } else {
664: push(@$target,$newline);
1.4 matthew 665: $modified = 1;
1.1 matthew 666: }
667: }
668: }
1.4 matthew 669: return $modified;
1.1 matthew 670: }
671:
1.9 raeburn 672: #################################################################
673: #################################################################
674:
675: =pod
676:
677: =over 4
678:
679: =item &update_rhn_source()
680:
681: Modifies the Red Hat 4 sources file which includes repositories used by up2date
682:
683: Inputs:
684: $rhn_items - a reference to hash of a hash containing the regular expression
685: to test for, and the text string to append to the file, if an entry for the
686: LON-CAPA RHEL repository is missing for two cases:
687:
688: (a) basearch
689: (b) noarch
690:
691: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
692:
693: =back
694:
695: =cut
696:
697: #################################################################
698: #################################################################
699: sub update_rhn_source {
700: my ($rhn_items) = @_;
701: return 0 if (ref($rhn_items) ne 'HASH');
702: return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
703: my $file = '/etc/sysconfig/rhn/sources';
704: return 0 if (! -e $file);
705: my $backup = $file.'.backup';
706: if (! copy($file,$backup)) {
707: warn "**** Error: Unable to make backup of $file";
708: return 0;
709: }
710: my $result = 0;
711: my $fh;
1.18 raeburn 712: if (open($fh,'<',$file)) {
1.9 raeburn 713: my $total = 0;
714: my %found;
715: foreach my $item (keys(%{$rhn_items})) {
716: $found{$item} = 0;
717: }
718: while(<$fh>) {
719: foreach my $item (keys(%{$rhn_items})) {
720: if (ref($rhn_items->{$item}) eq 'HASH') {
721: my $pattern = $rhn_items->{$item}->{regexp};
722: if ($pattern ne '') {
723: if (m{^$pattern}) {
724: $found{$item} = 1;
725: $total ++;
726: }
727: }
728: }
729: }
730: last if $total == 2;
731: }
732: close($fh);
733: if ($total < 2) {
1.18 raeburn 734: if (open($fh,'>>',$file)) {
1.9 raeburn 735: foreach my $item (keys(%{$rhn_items})) {
736: unless ($found{$item}) {
737: if (ref($rhn_items->{$item}) eq 'HASH') {
738: if ($rhn_items->{$item}->{text} ne '') {
739: print $fh "\n".$rhn_items->{$item}->{text}."\n";
740: $result = 1;
741: }
742: }
743: }
744: }
745: close($fh);
746: }
747: }
748: }
749: return $result;
750: }
1.1 matthew 751:
752: #################################################################
753: #################################################################
754:
755: =pod
756:
1.9 raeburn 757: =over 4
758:
759: =item &update_apt_source()
760:
1.24 raeburn 761: Modifies either the sources.list or sources.list.d/loncapa.list
762: file which include repositories used by apt-get.
1.9 raeburn 763:
764: Inputs:
1.24 raeburn 765: $distname - distro (without version): debian or ubuntu
766: $distver - distro version, e.g., 12 or 24
767: $deb_row - a reference to a hash containing the regular expression
768: to test for, and the text string to append to the file, if an entry
769: for the LON-CAPA Debian/ or Ubuntu repository is missing.
1.9 raeburn 770:
771: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
772:
1.1 matthew 773: =back
774:
775: =cut
776:
777: #################################################################
778: #################################################################
1.9 raeburn 779: sub update_apt_source {
1.24 raeburn 780: my ($distname,$distver,$deb_row) = @_;
1.9 raeburn 781: return 0 if (ref($deb_row) ne 'HASH');
782: return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
783: my $file = '/etc/apt/sources.list';
1.24 raeburn 784: my $nobackup;
785: if ((($distname eq 'ubuntu') && ($distver > 20)) ||
786: (($distname eq 'debian') && ($distver >= 10))) {
787: $file = '/etc/apt/sources.list.d/loncapa.list';
788: $nobackup = 1;
789: }
1.9 raeburn 790: return 0 if (! -e $file);
1.24 raeburn 791: unless ($nobackup) {
792: my $backup = $file.'.backup';
793: if (! copy($file,$backup)) {
794: warn "**** Error: Unable to make backup of $file";
795: return 0;
796: }
1.9 raeburn 797: }
798: my $result = 0;
799: my $fh;
1.18 raeburn 800: if (open($fh,'<',$file)) {
1.9 raeburn 801: my $found = 0;
802: my $pattern = $deb_row->{regexp};
803: while(<$fh>) {
804: if (m{^$pattern}) {
805: $found = 1;
806: last;
807: }
808: }
809: close($fh);
810: if (!$found) {
1.18 raeburn 811: if (open($fh,'>>',$file)) {
1.9 raeburn 812: print $fh "\n".$deb_row->{text}."\n";
813: close($fh);
814: $result = 1;
815: }
816: }
817: }
818: return $result;
819: }
820:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>