blob: 05ca191c10f094236d25f3ee80e35e5dbc235660 [file] [log] [blame]
Hariharasubramanian R0ae14c72016-04-01 07:29:39 -05001#!/usr/bin/env python
2
3from subprocess import call
4import sys
5import subprocess
6import dbus
7import string
8import socket
9import os
10import fcntl
11import time
12import glib
13import gobject
14import dbus.service
15import dbus.mainloop.glib
16
17DBUS_NAME = 'org.openbmc.LogManager'
18ERRL_INTF_NAME = 'org.openbmc.Errl'
19SRVC_INTF_NAME = 'org.openbmc.Service'
20OBJ_NAME_RSYSLOG = '/org/openbmc/LogManager/rsyslog'
21
22'''
23 Object Path > /org/openbmc/LogManager/rsyslog
24 Interface:Method > org.openbmc.Service.Enable dict:string:string
25 Interface:Method > org.openbmc.Service.Disable
26'''
27
28class JournalUtils ():
29 def _isvalidip(self, family, ipaddr):
30 if family == socket.AF_INET:
31 try:
32 socket.inet_pton(socket.AF_INET, ipaddr)
33 except AttributeError: # no inet_pton here, sorry
34 try:
35 socket.inet_aton(ipaddr)
36 except socket.error:
37 return False
38 return ipaddr.count('.') == 3
39 except socket.error: # not a valid address
40 return False
41
42 return True
43
44 elif family == socket.AF_INET6:
45 try:
46 socket.inet_pton(socket.AF_INET6, ipaddr)
47 except socket.error: # not a valid address
48 return False
49 return True
50
51 else: return False
52
53class Rsyslog (dbus.service.Object):
54 def __init__(self, bus, name):
55 self.bus = bus
56 self.name = name
57 dbus.service.Object.__init__(self,bus,name)
58
59 @dbus.service.method(dbus.PROPERTIES_IFACE, "ss", "v")
60 def Get(self, iface, ppty):
61 return self.GetAll(iface)[ppty]
62
63 @dbus.service.method(dbus.PROPERTIES_IFACE, 's', 'a{sv}')
64 def GetAll(self, iface):
65 if iface == ERRL_INTF_NAME:
66 status, remote_ip, remote_port = self.Status()
67 return {'status': status, 'ipaddr': remote_ip, 'port': remote_port }
68 else:
69 raise dbus.exceptions.DBusException('org.openbmc.UnknownInterface',
70 'This object does not implement the %s interface' % iface)
71
72 @dbus.service.method(SRVC_INTF_NAME, "a{sv}", "x")
73 def Enable (self, argv_dict):
74 remote_ip = ""
75 remote_port = 0
76
77 params = len (argv_dict)
78 if params > 2 : ValueError("Invalid Parameters")
79
80 for property_name in argv_dict:
81 if property_name == "ipaddr":
82 remote_ip = argv_dict [property_name]
83 elif property_name == "port":
84 remote_port = argv_dict [property_name]
85 else:
86 raise ValueError("Invalid Argument: IP Address/Port expected.")
87
88 if not remote_ip:
89 cur_remote = self._GetConfig ('Remote')
90 if not cur_remote:
91 raise ValueError("Invalid Remote Syslog IP Address")
92 else:
93 cur_remote = cur_remote[3:]
94 remote_ip, port_str = cur_remote.split (":")
95 remote_port = int(port_str)
96 if not util._isvalidip (socket.AF_INET, remote_ip): raise ValueError, "Malformed IP Address"
97 if not remote_port : remote_port = 514
98 if remote_port > 65535 : raise ValueError("Invalid Remote Syslog Port")
99
100 remote_addr = remote_ip + ":" + str(remote_port)
101 r = self._ModifyService('Remote', remote_addr)
102
103 cur_options = self._GetConfig ('Options')
104 new_options = self._GetOptions()
105
106 if cur_options != new_options:
107 r = self._ModifyService('Options', new_options)
108 r = self._RestartService ()
109
110 return r
111
112 @dbus.service.method(SRVC_INTF_NAME, "as", "x")
113 def Disable (self, argv_list):
114 params = len (argv_list)
115 if params : ValueError("Invalid Parameters")
116
117 remote = self._GetConfig ('Remote')
118 if not remote : return 0
119
120 r = self._ModifyService('Options', '-C') # FIXME: Restore current options minus the remote.
121 r = self._RestartService ()
122 return r
123
124 def Status (self):
125 remote = self._GetConfig ('Remote')
126 if not remote : return ("Disabled", "0.0.0.0", 0)
127
128 cur_remote = remote[3:]
129 remote_ip, remote_port = cur_remote.split (":")
130
131 options = self._GetConfig ('Options')
132 if not options : return ("Disabled", remote_ip, remote_port)
133
134 if remote in options : return ("Enabled", remote_ip, remote_port)
135
136 return ("Disabled", remote_ip, remote_port)
137
138 def _ModifyService (self, opt, val):
139 if not os.path.isfile(syslog_service_bbx_file):
140 r = call (["cp", syslog_service_lib_file, syslog_service_bbx_file])
141 r = call (["ln", "-s", syslog_service_bbx_file, syslog_service_cfg_file])
142
143 if not os.path.isfile(syslog_service_env_file):
144 env_file = open(syslog_service_env_file, 'w')
145 env_file.write ("OPTIONS=\"-C\"")
146 env_file.close()
147
148 if opt not in OptionKeys: raise ValueError("Invalid Option")
149
150 self._ModifyParam (opt, val)
151
152 return 0
153
154 def _StopService (self):
155 r = call (["systemctl", "stop", "syslog"])
156 r = call (["systemctl", "--no-reload", "kill", "syslog"])
157 return r
158
159 def _StartService (self):
160 r = call (["systemctl", "daemon-reload"])
161 r = call (["systemctl", "start", "syslog"])
162 return r
163
164 def _RestartService (self):
165 r = self._StopService()
166 r = self._StartService()
167 return r
168
169 def _ModifyParam (self, opt, val):
170 env_file = open(syslog_service_env_file, 'r')
171 tmp_file = open(syslog_service_tmp_file, 'w')
172
173 optkey = OptionKeySwitchMap [opt]['key']
174 for line in env_file:
175 if line[0] == '#':
176 tmp_file.write(line)
177 continue
178 curkey = line.strip().split ("=")[0]
179 if curkey != optkey :
180 tmp_file.write(line)
181
182 tmp_file.write(optkey + "=\"" + OptionKeySwitchMap[opt]['switch'] + val + "\"" + "\n")
183
184 env_file.close ()
185 tmp_file.close ()
186
187 r = call (["cp", syslog_service_tmp_file, syslog_service_env_file])
188 return r
189
190 def _GetConfig (self, opt):
191 with open(syslog_service_env_file, "r") as f:
192 for line in f:
193 if line[0] == '#': continue
194 config = line.split ("=")
195 var = config [0]
196 if var == OptionKeySwitchMap[opt]['key']:
197 val = config [1]
198 val = val[1:-2] # FIXME: Why is there a trailing space ???
199 return val
200 return ""
201
202 def _GetOptions(self):
203 cfg = {}
204 i = 0
205
206 for opt in OptionKeys:
207 if opt == 'Options' : continue
208 cfg [i] = self._GetConfig(opt)
209 i+=1
210
211 options = ''
212 j = 0
213 while j<i-1:
214 if cfg[j] : options += cfg [j]
215 j+=1
216
217 return options
218
219def main():
220 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
221 bus = dbus.SystemBus()
222 name = dbus.service.BusName(DBUS_NAME, bus)
223
224 global util
225 global rsys
226 global syslog_service_lib_file
227 global syslog_service_bbx_file
228 global syslog_service_cfg_file
229 global syslog_service_env_file
230 global syslog_service_tmp_file
231 global OptionKeys
232 global OptionKeySwitchMap
233
234 OptionKeys = ['Options', 'Outfile', 'Priority', 'Smaller', 'RotateSize', 'RotateNum', 'Remote', 'LocalAndNet', 'DropDup', 'SharedMem', 'ConfFile', 'MarkTime', 'Printk']
235 OptionKeySwitchMap = {
236 'Options' : { 'switch' : "", 'key' : "OPTIONS" },
237 'Outfile' : { 'switch' : "-O ", 'key' : "OBMC_SYSLOG_OUTFILE" },
238 'Priority' : { 'switch' : "-O ", 'key' : "OBMC_SYSLOG_PRIORITY" },
239 'Smaller' : { 'switch' : "-S ", 'key' : "OBMC_SYSLOG_SMALLER" },
240 'RotateSize' : { 'switch' : "-s ", 'key' : "OBMC_SYSLOG_ROTATESIZE" },
241 'RotateNum' : { 'switch' : "-b ", 'key' : "OBMC_SYSLOG_ROTATENUM" },
242 'Remote' : { 'switch' : "-R ", 'key' : "OBMC_SYSLOG_REMOTE" },
243 'LocalAndNet' : { 'switch' : "-L ", 'key' : "OBMC_SYSLOG_LOCALNET" },
244 'DropDup' : { 'switch' : "-D ", 'key' : "OBMC_SYSLOG_DROPDUP" },
245 'SharedMem' : { 'switch' : "-C ", 'key' : "OBMC_SYSLOG_SHAREDMEM" },
246 'ConfFile' : { 'switch' : "-f ", 'key' : "OBMC_SYSLOG_CONFFILE" },
247 'MarkTime' : { 'switch' : "-m ", 'key' : "OBMC_SYSLOG_MARKTIME" },
248 'Printk' : { 'switch' : "-K ", 'key' : "OBMC_SYSLOG_PRINTK" }
249 }
250
251 syslog_service_lib_file = '/lib/systemd/system/busybox-syslog.service'
252 syslog_service_bbx_file = '/etc/systemd/system/busybox-syslog.service'
253 syslog_service_cfg_file = '/etc/systemd/system/syslog.service'
254 syslog_service_env_file = '/etc/default/busybox-syslog'
255 syslog_service_tmp_file = '/tmp/busybox-syslog.tmp'
256
257 util = JournalUtils ()
258 rsys = Rsyslog (bus, OBJ_NAME_RSYSLOG)
259
260 mainloop = gobject.MainLoop()
261 print("Started")
262 mainloop.run()
263
264if __name__ == '__main__':
265 sys.exit(main())
266