1/*
2 KSysGuard, the KDE System Guard
3
4 Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20*/
21
22#include <signal.h>
23#include <stdarg.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <syslog.h>
28#include <sys/time.h>
29
30#include "ccont.h"
31#include "ksysguardd.h"
32
33#include "Command.h"
34
35typedef struct {
36 char* command;
37 cmdExecutor ex;
38 char* type;
39 int isMonitor;
40 int isLegacy;
41 struct SensorModul* sm;
42} Command;
43
44static CONTAINER CommandList;
45static sigset_t SignalSet;
46
47void command_cleanup( void* v );
48
49void command_cleanup( void* v )
50{
51 if ( v ) {
52 Command* c = v;
53 if ( c->command )
54 free ( c->command );
55 if ( c->type )
56 free ( c->type );
57 free ( v );
58 }
59}
60
61/*
62================================ public part =================================
63*/
64
65int ReconfigureFlag = 0;
66int CheckSetupFlag = 0;
67void output( const char *fmt, ...)
68{
69 if( !CurrentClient )
70 return;
71 va_list az;
72 va_start( az, fmt );
73 if(vfprintf(CurrentClient, fmt, az) < 0) {
74 fprintf(stderr, "Error talking to client. Exiting\n.");
75 exit(EXIT_FAILURE);
76 }
77 va_end( az );
78}
79void print_error( const char *fmt, ... )
80{
81 char errmsg[ 1024 ];
82 va_list az;
83
84 va_start( az, fmt );
85 vsnprintf( errmsg, sizeof( errmsg ) - 1, fmt, az );
86 errmsg[ sizeof( errmsg ) - 1 ] = '\0';
87 va_end( az );
88
89 if ( CurrentClient )
90 output( "\033%s\033", errmsg );
91}
92
93void log_error( const char *fmt, ... )
94{
95 static int maxLogs = 0;
96 if(maxLogs++ > 10)
97 return;
98
99 char errmsg[ 1024 ];
100 va_list az;
101
102 va_start( az, fmt );
103 vsnprintf( errmsg, sizeof( errmsg ) - 1, fmt, az );
104 errmsg[ sizeof( errmsg ) - 1 ] = '\0';
105 va_end( az );
106
107 openlog( "ksysguardd", LOG_PID, LOG_DAEMON );
108 syslog( LOG_ERR, "%s", errmsg );
109 closelog();
110}
111
112void initCommand( void )
113{
114 CommandList = new_ctnr();
115 sigemptyset( &SignalSet );
116 sigaddset( &SignalSet, SIGALRM );
117
118 registerCommand( "monitors", printMonitors );
119 /* registerCommand( "test", printTest ); */
120
121 if ( RunAsDaemon == 0 )
122 registerCommand( "quit", exQuit );
123}
124
125void exitCommand( void )
126{
127 destr_ctnr( CommandList, command_cleanup );
128}
129
130void registerCommand( const char* command, cmdExecutor ex )
131{
132 Command* cmd = (Command*)malloc( sizeof( Command ) );
133 if(!cmd || !(cmd->command = (char*)malloc( strlen( command ) + 1 ))) {
134 print_error("Out of memory");
135 free(cmd);
136 return;
137 }
138 strcpy( cmd->command, command );
139 cmd->type = 0;
140 cmd->ex = ex;
141 cmd->isMonitor = 0;
142 push_ctnr( CommandList, cmd );
143 ReconfigureFlag = 1;
144}
145
146void removeCommand( const char* command )
147{
148 Command* cmd;
149
150 for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) {
151 if ( cmd->command && strcmp( cmd->command, command ) == 0 ) {
152 remove_ctnr( CommandList );
153 free( cmd->command );
154 if ( cmd->type )
155 free( cmd->type );
156 free( cmd );
157 }
158 }
159
160 ReconfigureFlag = 1;
161}
162
163void registerAnyMonitor( const char* command, const char* type, cmdExecutor ex,
164 cmdExecutor iq, struct SensorModul* sm, int isLegacy )
165{
166 /* Monitors are similar to regular commands except that every monitor
167 * registers two commands. The first is the value request command and
168 * the second is the info request command. The info request command is
169 * identical to the value request but with an '?' appended. The value
170 * command prints a single value. The info request command prints
171 * a description of the monitor, the mininum value, the maximum value
172 * and the unit. */
173 Command* cmd = (Command*)malloc( sizeof( Command ) );
174 if(!cmd || !(cmd->command = (char*)malloc( strlen( command ) + 1 ))) {
175 print_error("Out of memory");
176 free(cmd);
177 return;
178 }
179
180 strcpy( cmd->command, command );
181 cmd->ex = ex;
182 cmd->type = (char*)malloc( strlen( type ) + 1 );
183 if(!cmd->type ) {
184 print_error("Out of memory");
185 free(cmd);
186 return;
187 }
188
189 strcpy( cmd->type, type );
190 cmd->isMonitor = 1;
191 cmd->isLegacy = isLegacy;
192 cmd->sm = sm;
193 push_ctnr( CommandList, cmd );
194
195 cmd = (Command*)malloc( sizeof( Command ) );
196 if(!cmd ) {
197 print_error("Out of memory");
198 return;
199 }
200
201 cmd->command = (char*)malloc( strlen( command ) + 2 );
202 if(!cmd->command ) {
203 print_error("Out of memory");
204 free(cmd);
205 return;
206 }
207
208 strcpy( cmd->command, command );
209 cmd->command[ strlen( command ) ] = '?';
210 cmd->command[ strlen( command ) + 1 ] = '\0';
211 cmd->ex = iq;
212 cmd->isMonitor = 0;
213 cmd->sm = sm;
214 cmd->type = 0;
215 push_ctnr( CommandList, cmd );
216}
217
218void registerMonitor( const char* command, const char* type, cmdExecutor ex,
219 cmdExecutor iq, struct SensorModul* sm )
220{
221 int legacyFlag = 0;
222
223 registerAnyMonitor( command, type, ex, iq, sm, legacyFlag );
224}
225
226void registerLegacyMonitor( const char* command, const char* type, cmdExecutor ex,
227 cmdExecutor iq, struct SensorModul* sm )
228{
229 int legacyFlag = 1;
230
231 registerAnyMonitor( command, type, ex, iq, sm, legacyFlag );
232}
233
234void removeMonitor( const char* command )
235{
236 char* buf;
237
238 removeCommand( command );
239 buf = (char*)malloc( strlen( command ) + 2 );
240 if(!buf ) {
241 print_error("Out of memory");
242 return;
243 }
244
245 strcpy( buf, command );
246 strcat( buf, "?" );
247 removeCommand( buf );
248 free( buf );
249}
250
251void executeCommand( const char* command )
252{
253 Command* cmd;
254 int i = 0;
255 while(command[i] != 0 && command[i] != ' ' && command[i] != '\t' )
256 i++;
257 if( i <= 0 )
258 return; /* No command give at all */
259 int lengthOfCommand = i;
260
261 for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) {
262 if ( strncmp( cmd->command, command, lengthOfCommand ) == 0 && cmd->command[lengthOfCommand] == 0) {
263 if ( cmd->isMonitor && cmd->sm->updateCommand != NULL) {
264 struct timeval currentTime;
265 gettimeofday(&currentTime,NULL);
266 unsigned long long timeCentiSeconds = (unsigned long long)currentTime.tv_sec * 10 + currentTime.tv_usec / 100000;
267 if ( timeCentiSeconds - cmd->sm->timeCentiSeconds >= UPDATEINTERVAL ) {
268 cmd->sm->timeCentiSeconds = timeCentiSeconds;
269 cmd->sm->updateCommand();
270 }
271 }
272
273 (*(cmd->ex))( command );
274
275 if ( ReconfigureFlag ) {
276 ReconfigureFlag = 0;
277 print_error( "RECONFIGURE" );
278 }
279
280 fflush( CurrentClient );
281 return;
282 }
283 }
284
285 if ( CurrentClient ) {
286 output( "UNKNOWN COMMAND\n" );
287 fflush( CurrentClient );
288 }
289}
290
291void printMonitors( const char *c )
292{
293 Command* cmd;
294 ReconfigureFlag = 0;
295
296 (void)c;
297
298 for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) {
299 if ( cmd->isMonitor && !cmd->isLegacy )
300 output( "%s\t%s\n", cmd->command, cmd->type);
301 }
302
303 fflush( CurrentClient );
304}
305
306void printTest( const char* c )
307{
308 Command* cmd;
309
310 for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) {
311 if ( strcmp( cmd->command, c + strlen( "test " ) ) == 0 ) {
312 output( "1\n" );
313 fflush( CurrentClient );
314 return;
315 }
316 }
317
318 output( "0\n" );
319 fflush( CurrentClient );
320}
321
322void exQuit( const char* cmd )
323{
324 (void)cmd;
325
326 QuitApp = 1;
327}
328