Add ability to reload the ignore list.
[people/stevee/guardian.git] / modules / Socket.pm
1 package Guardian::Socket;
2 use strict;
3 use warnings;
4
5 use Exporter qw(import);
6
7 our @EXPORT_OK = qw(Server Client Message_Parser RemoveSocketFile);
8
9 use IO::Socket::UNIX qw( SOCK_STREAM SOMAXCONN );
10
11 # The path and filename to the UNIX socket.
12 my $socketpath = "/run/guardian";
13 my $socketfile = "/run/guardian/guardian.sock";
14
15 # Hash with all supported socket commands and events which should
16 # be returned by the parser.
17 my %supported_commands = (
18         'block' => 'block',
19         'unblock' => 'unblock',
20         'flush' => 'flush',
21         'reload' => 'reload',
22         'reload-ignore-list' => 'reload-ignore-list',
23         'logrotate' => 'logrotate',
24 );
25
26 #
27 ## Socket server function.
28 #
29 ## It is used to create the server component to provide an IPC
30 ## mechanism for guardian.  The server function creates an UNIX
31 ## socket.
32 #
33 sub Server ($) {
34         my $socket_owner = shift;
35
36         # If the path for the socketfile does not exist, try to
37         # create it.
38         unless (-d "$socketpath") {
39                 mkdir("$socketpath") or die "Could not create $socketpath: $!";
40         }
41
42         # Delete an existing socket file.
43         if (-e "$socketfile") {
44                 unlink $socketfile
45                 or die "Could not release existing socket file: $!";
46         }
47
48         # Create a new UNIX socket.
49         my $server = IO::Socket::UNIX->new(
50                 Local => $socketfile,
51                 Listen => SOMAXCONN,
52                 Type => SOCK_STREAM,
53         ) or die "Could not create socket: $!";
54
55         
56         # Translate the given user/group name into ID values.
57         if (defined ($socket_owner)) {
58                 # Splitt provided user/group into single arguments.
59                 my ($username, $groupname) = split(/:/, $socket_owner);
60
61                 # Get the ID for the given user name.
62                 my $uid = getpwnam($username) or die "Could not get an UID for $username: $!";
63
64                 # Get the ID for given group name.
65                 my $gid = getgrnam($groupname) or die "Could not get a GID for $groupname: $!";
66
67                 # Set new ownership for the socket file.
68                 chown($uid, $gid, "$socketfile") or die "Could not change ownership to ($uid:$gid) for $socketfile: $!";
69         }
70
71         # Return the server object.
72         return $server;
73 }
74
75 #
76 ## A client for the socket server.
77 #
78 ## This function provides a simple client to connect to the server socket
79 ## and send messages through it to a running guardian process.
80 #
81 sub Client($) {
82         my ($message) = @_;
83
84         # Create the client and connect to the server socket.
85         my $client = IO::Socket::UNIX->new(
86                 Type => SOCK_STREAM,
87                 Peer => $socketfile,
88         ) or die "Could not connect to socketfile: $!\n";
89
90         # Remove any newline.
91         chomp($message);
92
93         # Send the message through the socket.
94         print $client "$message\n";
95 }
96
97 #
98 ## The Socket message parser.
99 #
100 ## This subfunction is responsible for parsing any data or messages
101 ## which have been recieved through the server socket.
102 #
103 sub Message_Parser ($) {
104         # Splitt the message into single parts.
105         # The first part contains the command, the second
106         # one an optional argument.
107         my @message = split(/ /, $_[0]);
108         my ($command, $optarg, $unsupported) = @message;
109
110         # Currently only socket messages with two arguments (command and
111         # the additional argument which is required for some commands)
112         # are supported. If a third argument is passed, the message
113         # is invalid and the parser returns false.
114         if ($unsupported) {
115                 return undef;
116         }
117
118         # Check if we got a supported command.
119         if (exists $supported_commands{$command}) {
120                 # Check an optional argument has been given.
121                 if ($optarg) {
122                         # The message is valid, return the event and
123                         # the optional argument.
124                         return "$supported_commands{$command} $optarg Socket User-requested action.";
125                 } else {
126                         # Only return the event for the recieved command.
127                         return "$supported_commands{$command}";
128                 }
129         }
130
131         # If we got here, the command was not supported or something different
132         # went wrong. In such cases the function will return undef (False).
133         return undef;
134 }
135
136 #
137 ## RemoveSocketFile function.
138 #
139 ## A tiny function which just removes an existing Socket file.
140 #
141 sub RemoveSocketFile () {
142         # Check if a socketfile exists.
143         if (-e $socketfile) {
144                 # Delete the socket file.
145                 unlink($socketfile);
146         }
147 }
148
149 1;