1#!/usr/bin/perl
2#
3# Interface between our config files and the debconf database.
4#
5# Usage:
6#
7#   manage_debconf.pl <action>
8#
9# where <action> can be:
10#
11#   read:    read the configuration from the yaml into debconf
12#   update:  update the yaml config according to the debconf database
13use strict;
14use warnings;
15
16use Debconf::Client::ConfModule (qw/get set/);
17
18# map from the name of a setting in our .yaml file to the relevant debconf
19# setting.
20my %MAPPINGS=(
21    server_name => 'matrix-synapse/server-name',
22    report_stats => 'matrix-synapse/report-stats',
23);
24
25# enable debug if dpkg --debug
26my $DEBUG = $ENV{DPKG_MAINTSCRIPT_DEBUG};
27
28sub read_config {
29    my @files = @_;
30
31    foreach my $file (@files)  {
32        print STDERR "reading $file\n" if $DEBUG;
33
34        open my $FH, "<", $file or next;
35
36        # rudimentary parsing which (a) avoids having to depend on a yaml library,
37        # and (b) is tolerant of yaml errors
38        while($_ = <$FH>) {
39            while (my ($setting, $debconf) = each %MAPPINGS) {
40                $setting = quotemeta $setting;
41                if(/^${setting}\s*:(.*)$/) {
42                    my $val = $1;
43
44                    # remove leading/trailing whitespace
45                    $val =~ s/^\s*//;
46                    $val =~ s/\s*$//;
47
48                    # remove surrounding quotes
49                    if ($val =~ /^"(.*)"$/ || $val =~ /^'(.*)'$/) {
50                        $val = $1;
51                    }
52
53                    print STDERR ">> $debconf = $val\n" if $DEBUG;
54                    set($debconf, $val);
55                }
56            }
57        }
58        close $FH;
59    }
60}
61
62sub update_config {
63    my @files = @_;
64
65    my %substs = ();
66    while (my ($setting, $debconf) = each %MAPPINGS) {
67        my @res = get($debconf);
68        $substs{$setting} = $res[1] if $res[0] == 0;
69    }
70
71    foreach my $file (@files) {
72        print STDERR "checking $file\n" if $DEBUG;
73
74        open my $FH, "<", $file or next;
75
76        my $updated = 0;
77
78        # read the whole file into memory
79        my @lines = <$FH>;
80
81        while (my ($setting, $val) = each %substs) {
82            $setting = quotemeta $setting;
83
84            map {
85                if (/^${setting}\s*:\s*(.*)\s*$/) {
86                    my $current = $1;
87                    if ($val ne $current) {
88                        $_ = "${setting}: $val\n";
89                        $updated = 1;
90                    }
91                }
92            } @lines;
93        }
94        close $FH;
95
96        next unless $updated;
97
98        print STDERR "updating $file\n" if $DEBUG;
99        open $FH, ">", $file or die "unable to update $file";
100        print $FH @lines;
101        close $FH;
102    }
103}
104
105
106my $cmd = $ARGV[0];
107
108my $read = 0;
109my $update = 0;
110
111if (not $cmd) {
112    die "must specify a command to perform\n";
113} elsif ($cmd eq 'read') {
114    $read = 1;
115} elsif ($cmd eq 'update') {
116    $update = 1;
117} else {
118    die "unknown command '$cmd'\n";
119}
120
121my @files = (
122    "/etc/matrix-synapse/homeserver.yaml",
123    glob("/etc/matrix-synapse/conf.d/*.yaml"),
124);
125
126if ($read) {
127    read_config(@files);
128} elsif ($update) {
129    update_config(@files);
130}
131