Handle hostnames with upper-case letters
[webmin.git] / xinetd / xinetd-lib.pl
1 # xinetd-lib.pl
2 # Functions for parsing xinetd config files
3
4 BEGIN { push(@INC, ".."); };
5 use WebminCore;
6 &init_config();
7
8 # get_xinetd_config()
9 sub get_xinetd_config
10 {
11 return &parse_xinetd($config{'xinetd_conf'});
12 }
13
14 # parse_xinetd(file, [offset])
15 # Parses the xinetd config file into directives
16 sub parse_xinetd
17 {
18 local @rv;
19 open(INET, $_[0]);
20 local @lines = <INET>;
21 close(INET);
22 local $lnum = 0;
23 local $section;
24 foreach (@lines) {
25         s/\r|\n//g; s/#.*$//g; s/\s+$//;  # remove newlines, comments and spaces
26         if (/^\s*\{/) {
27                 # put subsequent directives into a section
28                 $section = $rv[$#rv];
29                 $section->{'members'} = [ ];
30                 }
31         elsif (/^\s*\}/) {
32                 # finished the section
33                 $section->{'eline'} = $lnum;
34                 $section = undef;
35                 }
36         elsif (/^\s*include\s+(\S+)/) {
37                 # include directives from a file
38                 push(@rv, &parse_xinetd($1, scalar(@rv)));
39                 }
40         elsif (/^\s*includedir\s+(\S+)/) {
41                 # include directives from every file in a directory
42                 local $d = $1;
43                 opendir(DIR, $d);
44                 foreach $f (readdir(DIR)) {
45                         next if ($f =~ /^\./);
46                         push(@rv, &parse_xinetd("$d/$f", scalar(@rv)));
47                         }
48                 closedir(DIR);
49                 }
50         elsif (/^\s*(\S+)\s*(.*)/) {
51                 # a directive or start of a section
52                 local $dir = { 'name' => $1, 'file' => $_[0],
53                                'index' => scalar(@rv) + $_[1],
54                                'line' => $lnum, 'eline' => $lnum };
55                 local $v = $2;
56                 if ($v =~ /^(=|\+=|-=)\s+(.*)/) {
57                         $dir->{'op'} = $1;
58                         $dir->{'value'} = $2;
59                         }
60                 else {
61                         $dir->{'op'} = '=' if ($service);
62                         $dir->{'value'} = $v;
63                         }
64                 local @v = split(/\s+/, $dir->{'value'});
65                 $dir->{'values'} = \@v;
66                 if ($section) {
67                         push(@{$section->{'members'}}, $dir);
68                         local @q = @{$section->{'quick'}->{$dir->{'name'}}};
69                         if ($dir->{'op'} eq '=') {
70                                 @q = @v;
71                                 }
72                         elsif ($dir->{'op'} eq '+=') {
73                                 @q = ( @q, @v );
74                                 }
75                         elsif ($dir->{'op'} eq '-=') {
76                                 @q = grep { &indexof($_, @v) < 0 } @q;
77                                 }
78                         $section->{'quick'}->{$dir->{'name'}} = \@q;
79                         }
80                 else { push(@rv, $dir); }
81                 }
82         $lnum++;
83         }
84 return @rv;
85 }
86
87 # set_member_value(&xinet, name, [value]*)
88 # Removes all members with the given name and replaces them with one
89 # like  name = value
90 sub set_member_value
91 {
92 local @m = @{$_[0]->{'members'}};
93 @m = grep { $_->{'name'} ne $_[1] } @m;
94 if (defined($_[2])) {
95         push(@m, { 'name' => $_[1],
96                    'op' => '=',
97                    'values' => [ @_[2..@_-1] ] } );
98         $_[0]->{'quick'}->{$_[1]} = [ @_[2..@_-1] ];
99         }
100 else {
101         delete($_[0]->{'quick'}->{$_[1]});
102         }
103 $_[0]->{'members'} = \@m;
104 }
105
106 # create_xinet(&xinet, [file])
107 # Add a new xinet record to the end of the config file
108 sub create_xinet
109 {
110 local $lref = &read_file_lines($_[1] || $config{'xinetd_conf'});
111 push(@$lref, &xinet_lines($_[0]));
112 &flush_file_lines();
113 }
114
115 # modify_xinet(&xinet)
116 # Update an existing xinet record
117 sub modify_xinet
118 {
119 local $lref = &read_file_lines($_[0]->{'file'});
120 splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1,
121        &xinet_lines($_[0]));
122 &flush_file_lines();
123 }
124
125 # delete_xinet(&xinet)
126 # Delete an existing xinet record
127 sub delete_xinet
128 {
129 local $lref = &read_file_lines($_[0]->{'file'});
130 splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1);
131 &flush_file_lines();
132 }
133
134 # xinet_lines(&xinet, tabs)
135 sub xinet_lines
136 {
137 local @rv;
138 $rv[0] = "$_[1]$_[0]->{'name'}";
139 $rv[0] .= " $_[0]->{'op'}" if ($_[0]->{'op'});
140 foreach $v (@{$_[0]->{'values'}}) {
141         $rv[0] .= " $v";
142         }
143 if ($_[0]->{'members'}) {
144         push(@rv, $_[1].'{');
145         foreach $m (@{$_[0]->{'members'}}) {
146                 push(@rv, &xinet_lines($m, "$_[1]\t"));
147                 }
148         push(@rv, $_[1].'}');
149         }
150 return @rv;
151 }
152
153 # list_protocols()
154 # Returns a list of supported protocols on this system
155 sub list_protocols
156 {
157 local(@rv);
158 open(PROT, $config{'protocols_file'});
159 while(<PROT>) {
160         chop; s/#.*$//g;
161         if (!/\S/) { next; }
162         /^(\S+)\s+/;
163         push(@rv, $1);
164         }
165 close(PROT);
166 return &unique(@rv);
167 }
168
169 sub is_xinetd_running
170 {
171 if ($config{'pid_file'}) {
172         return &check_pid_file($config{'pid_file'});
173         }
174 else {
175         local ($pid) = &find_byname("xinetd");
176         return $pid;
177         }
178 }
179
180 1;
181