/usr/share/perl5/MetaInit/Parse.pm is in metainit 0.0.5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | package MetaInit::Parse;
use v5.008;
use strict;
use warnings;
use Carp qw/croak/;
use File::Basename;
use Scalar::Util qw/openhandle/;
=head1 NAME
MetaInit::Parse - Parses a MetaInit definition fild
=head1 SYNOPSIS
$data = MetaInit::Parse::parse($filename)
Opens and parses the specified file. The parsed data is handed back as a
hashref, containing an entry for each definition.
=head2 FILE FORMAT
The file to be parsed should be in a RFC822-like format (field names and values
are separated by a colon (C<:>). Lines starting with a blank are just appended
to their previous line's value. Lines that contain only a period (C<.>) in them
will become an empty line in the output.
Empty lines are ignored.
Comments are allowed - All characters after a # sign until the end of the
line are ignored. If you need to include the # sign, prepend it with a
backslash (\#).
=head2 FIELDS
A MetaInit file has several defined fields, out of which only C<Exec> is mandatory:
=over 4
=item Short-Description
A short (~60 character) description of the daemon. Merely informative.
=item Description
A longer description of the daemon, usually a couple of lines long. Merely
informative.
=item Exec
The command to execute to get the daemon to room. Please keep in mind this
should start the daemon in the I<foreground>, not send it to the background.
=item Required-Start
The facilities that should be started before this one. This can include the
LSB facility names. It defaults to "B<$local_fs $network $remote_fs>.
=item Required-Stop
B<CURRENTLY IGNORED - SHOULD CHECK LATER>
=item Should-Start
B<CURRENTLY IGNORED - SHOULD CHECK LATER>
=item Should-Stop
B<CURRENTLY IGNORED - SHOULD CHECK LATER>
=item Prestart-Hook
A shell snippet that should be included in the generated init script I<before>
the daemon is run
=item Poststop-hook
A shell snippet that should be included in the generated init script I<after>
the daemon finishes running
=item No-Auto
If this is set to anything, the generated init scripts will be installed in a
way that the deamon is not started by default on system start up. It can still
be started manually (e.g. using /etc/init.d/<name> start) and be configured to
start automatically (e.g. by adjusting the symlinks).
=back
Some fields (Required-Start, Should-Start, Required-Stop and Should-Stop) will
not return strings but arrayrefs - Elements will be separated by whitespace.
=head1 NOTES
Note that this module is written specifically for MetaInit, it will quite
probably not be useful outside it.
=head1 SEE ALSO
The (as for now inexistent ;-) ) MetaInit documentation
LSB facility names,
http://refspecs.freestandards.org/LSB_2.1.0/LSB-generic/LSB-generic/facilname.html
=head1 AUTHOR
=cut
my @splits = qw(Required-Start Should-Start Required-Stop Should-Stop);
my @mandatory = qw(Exec);
sub slurp_from_fh {
my ($fh) = @_;
return do { local $/; <$fh> };
}
sub process_data {
my ($data, $parsed) = @_;
my $lastkey;
for (split /\n/, $data) {
chomp;
# Ignore comments; unescape escaped #s
s/[^\\]\#.*//;
s/\\\#/\#/g;
# Ignore empty lines; convert single dots in a line into empty lines
next if /^\s*$/;
s/^\s*\.\s*$//;
if (my ($key, $value) = m/^(\S.*)\s*:\s*(.*)/) {
$parsed->{$key} = $value;
$lastkey = $key;
}
elsif ($lastkey) {
s/^\s+//;
s/^\.$//;
$parsed->{$lastkey} .= "\n$_";
} else {
die "Cannot parse line: ``$_''";
}
}
}
sub fixup_results {
my (%parsed) = @_;
my $error_msg = "";
for my $field (@mandatory) {
$error_msg .= "Mandatory field `$field' not provided\n" unless exists $parsed{$field};
}
croak($error_msg) if $error_msg;
if (not exists $parsed{Description}) {
$parsed{Description} = $parsed{"Short-Description"}
}
($parsed{Path}, $parsed{Args}) = split(/\s+/,$parsed{Exec},2);
$parsed{Basename} = basename $parsed{Path};
for (@splits){
$parsed{$_} = [ split m/\s+/, $parsed{$_}||'' ];
}
if ($parsed{"No-Auto"}) {
$parsed{"Start-Levels"} = [];
$parsed{"Stop-Levels"} = [1,2,3,4,5];
} else {
$parsed{"Start-Levels"} = [2,3,4,5];
$parsed{"Stop-Levels"} = [1];
}
if ($parsed{"Post-Stop"}) {
push @{$parsed{"Stop-Levels"}}, 0, 6;
}
for (qw/Start-Levels Stop-Levels/) {
@{$parsed{$_}} = sort @{$parsed{$_}};
}
return %parsed;
}
sub parse {
my ($args) = @_;
if (ref $args ne 'HASH') {
croak('hash reference expected');
}
my $data;
my %parsed;
if (defined $args->{input}) {
$data = $args->{input};
}
elsif (my $fh = openhandle($args->{handle})) {
$data = slurp_from_fh($fh);
}
elsif (defined (my $file = $args->{filename})) {
open(my $handle, '<', $file)
or die "Failed to open input file `$file': $!";
$data = slurp_from_fh($handle);
$parsed{File} = $file;
$parsed{Name} = basename($file,'.metainit');
}
else {
croak("no input given; you need to pass a `filename', "
. "an opened `handle' or an `input' string");
}
if (!defined $parsed{File}) {
if (ref $args->{fields} ne 'HASH'
|| !exists $args->{fields}->{File}
|| !exists $args->{fields}->{Name}) {
croak("parsing from handles or strings requires the `fields' option to "
. "be set to a hash reference that defines both the `Name' and the "
. "`File' field.");
}
}
@parsed{keys %{ $args->{fields} }} = values %{ $args->{fields} };
# Defaults:
$parsed{"Short-Description"} = $parsed{Name};
$parsed{"No-Auto"} = 0;
$parsed{"Required-Start"} = '$local_fs $network $remote_fs';
$parsed{"Required-Stop"} = '$local_fs $network $remote_fs';
process_data($data, \%parsed);
%parsed = fixup_results(%parsed);
return \%parsed;
}
# Return a true value
1;
# vim:sw=4:ts=4:expandtab
|