Annotation of loncom/debugging_tools/modify_config_files.pl, revision 1.26
1.1 matthew 1: #!/usr/bin/perl -w
2: #
3: # The LearningOnline Network
4: #
1.26 ! raeburn 5: # $Id: modify_config_files.pl,v 1.25 2024/07/08 23:46:06 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: }
1.26 ! raeburn 396: my $wwwuid = getpwnam('www');
! 397: my $wwwgid = getgrnam('www');
! 398: if ($wwwuid!=$<) {
! 399: chown($wwwuid,$wwwgid,$bash_www_cnf);
! 400: }
1.25 raeburn 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:
1.4 matthew 434: my $exitvalue = 0;
435:
436: if ($mysql_global_status) { $exitvalue = 1; }
437:
438: exit $exitvalue;
1.1 matthew 439:
1.24 raeburn 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:
1.1 matthew 468:
469: sub update_file {
1.13 raeburn 470: my ($file,$newdata,$nobackup) = @_;
1.1 matthew 471: return 1 if (! -e $file);
1.13 raeburn 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: }
1.1 matthew 478: }
479: my ($filedata) = &parse_config_file($file);
1.4 matthew 480: if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
481: my $modified = 0;
1.1 matthew 482: foreach my $data (@$newdata) {
483: my $section = $data->{'section'};
484: my $key = $data->{'key'};
485: my $value = $data->{'value'};
1.4 matthew 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; }
1.1 matthew 492: }
1.4 matthew 493: return $modified;
1.1 matthew 494: }
495:
496: #################################################################
497: #################################################################
498:
499: =pod
500:
1.9 raeburn 501: =over 4
502:
503: =item &parse_config_file()
1.1 matthew 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:
1.9 raeburn 511: =back
512:
1.1 matthew 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)) {
1.4 matthew 530: chomp($line);
1.1 matthew 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:
1.9 raeburn 551: =over 4
552:
1.24 raeburn 553: =item &write_config_file()
1.1 matthew 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:
1.9 raeburn 562: =back
563:
1.1 matthew 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: }
1.18 raeburn 574: open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
1.1 matthew 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:
1.9 raeburn 605: =over 4
606:
607: =item &modify_config_file()
1.1 matthew 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:
1.4 matthew 619: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
620:
1.9 raeburn 621: =back
1.4 matthew 622:
1.1 matthew 623: =cut
624:
625: #################################################################
626: #################################################################
627: sub modify_config_file {
628: my ($filedata,$section,$newkey,$newvalue)=@_;
1.4 matthew 629: my $modified = 0; # returned value - set to true if the file is modified
1.1 matthew 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/) {
1.4 matthew 652: if ($target->[$i] ne $newline) {
653: $target->[$i]=$newline;
654: $modified = 1;
655: }
1.1 matthew 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.
1.2 matthew 665: if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
1.1 matthew 666: $target->[-1] = $newline;
1.4 matthew 667: $modified = 1;
1.1 matthew 668: } else {
669: push(@$target,$newline);
1.4 matthew 670: $modified = 1;
1.1 matthew 671: }
672: }
673: }
1.4 matthew 674: return $modified;
1.1 matthew 675: }
676:
1.9 raeburn 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;
1.18 raeburn 717: if (open($fh,'<',$file)) {
1.9 raeburn 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) {
1.18 raeburn 739: if (open($fh,'>>',$file)) {
1.9 raeburn 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: }
1.1 matthew 756:
757: #################################################################
758: #################################################################
759:
760: =pod
761:
1.9 raeburn 762: =over 4
763:
764: =item &update_apt_source()
765:
1.24 raeburn 766: Modifies either the sources.list or sources.list.d/loncapa.list
767: file which include repositories used by apt-get.
1.9 raeburn 768:
769: Inputs:
1.24 raeburn 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.
1.9 raeburn 775:
776: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
777:
1.1 matthew 778: =back
779:
780: =cut
781:
782: #################################################################
783: #################################################################
1.9 raeburn 784: sub update_apt_source {
1.24 raeburn 785: my ($distname,$distver,$deb_row) = @_;
1.9 raeburn 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';
1.24 raeburn 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: }
1.9 raeburn 795: return 0 if (! -e $file);
1.24 raeburn 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: }
1.9 raeburn 802: }
803: my $result = 0;
804: my $fh;
1.18 raeburn 805: if (open($fh,'<',$file)) {
1.9 raeburn 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) {
1.18 raeburn 816: if (open($fh,'>>',$file)) {
1.9 raeburn 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>