1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include <protocol/protocol.h>
26 #include <base/time.h>
27 #include <provmgr/provmgr.h>
28 #include <base/strings.h>
29 #include <base/args.h>
30 #include <base/log.h>
31 #include <base/env.h>
32 #include <base/paths.h>
33 #include <base/getopt.h>
34 #include <sys/types.h>
35 #include <pwd.h>
36 #include <grp.h>
37
38 #define T MI_T
39
40 typedef struct _AgentData AgentData;
41
42 struct _AgentData
43 mike 1.1 {
44 Protocol* protocol;
45 ProvMgr provmgr;
46 Selector selector;
47 } ;
48
49 typedef struct _Options
50 {
51 const char* provDir;
52 MI_Boolean help;
53 MI_Uint32 idletimeout;
54 }
55 Options;
56
57 static AgentData s_data;
58
59 static Options s_opts;
60 static const char* arg0 = 0;
61 static const char HELP[] = "\
62 Usage: %s [OPTIONS]\n\
63 \n\
64 mike 1.1 This program starts the OMI agent.\n\
65 \n\
66 OPTIONS:\n\
67 --version Print version information.\n\
68 --providerdir Find providers in this directory.\n\
69 --loglevel LEVEL Set the log level (0-4).\n\
70 \n";
71
72 PRINTF_FORMAT(1, 2)
73 void FUNCTION_NEVER_RETURNS err(const char* fmt, ...)
74 {
75 va_list ap;
76 memset(&ap, 0, sizeof(ap));
77
78 fprintf(stderr, "%s: ", arg0);
79
80 va_start(ap, fmt);
81 vfprintf(stderr, fmt, ap);
82 va_end(ap);
83
84 fputc('\n', stderr);
85 mike 1.1 exit(1);
86 }
87
88 static void _ProviderCallback(Message* msg, void* callbackData)
89 {
90
91 /* forward message to the other side */
92 /*if (msg->request)
93 msg->clientID = msg->request->clientID;*/
94
95 Protocol_Send(s_data.protocol, msg);
96 }
97
98 /* Called by protocol stack to dispatch an incoming request message */
99 static MI_Boolean _RequestCallback(
100 Protocol* protocol_,
101 Message* msg,
102 void* data)
103 {
104 //ServerCallbackData* self = (ServerCallbackData*)data;
105 MI_Result r;
106 mike 1.1
107 MI_UNUSED(protocol_);
108
109 msg->callback = _ProviderCallback;
110 //msg->callbackData = self;
111
112 r = ProvMgr_PostMessage(&s_data.provmgr, msg->libraryName, msg);
113
114 if (MI_RESULT_OK != r)
115 {
116 PostResultMsg* resp;
117
118 resp = PostResultMsg_New( msg->msgID );
119
120 if (!resp)
121 return MI_FALSE;
122
123 resp->result = r;
124 Message_SetRequest(&resp->base,msg);
125 (*msg->callback)(&resp->base, msg->callbackData);
126
127 mike 1.1 PostResultMsg_Release(resp);
128 }
129
130 return MI_TRUE;
131 }
132
133 static void GetCommandLineDestDirOption(
134 int* argc_,
135 const char* argv[])
136 {
137 int argc = *argc_;
138 int i;
139 const char* destdir = NULL;
140
141 for (i = 1; i < argc; )
142 {
143 if (strcmp(argv[i], "--destdir") == 0)
144 {
145 if (i + 1 == argc)
146 err("missing argument for --destdir option");
147
148 mike 1.1 destdir = argv[i+1];
149 memmove((char*)&argv[i], (char*)&argv[i+2],
150 sizeof(char*) * (argc-i-1));
151 argc -= 2;
152 }
153 else if (strncmp(argv[i], "--destdir=", 10) == 0)
154 {
155 destdir = argv[i] + 10;
156 memmove((char*)&argv[i], (char*)&argv[i+1],
157 sizeof(char*) * (argc-i));
158
159 argc -= 1;
160 }
161 else
162 i++;
163 }
164
165 if (destdir)
166 {
167 if (SetPath(ID_DESTDIR, destdir) != 0)
168 err("failed to set destdir");
169 mike 1.1 }
170
171 *argc_ = argc;
172 }
173
174 static void GetCommandLineOptions(int* argc, const char* argv[])
175 {
176 GetOptState state = GETOPTSTATE_INITIALIZER;
177 const char* opts[] =
178 {
179 "-h",
180 "--help",
181 "-v",
182 "--version",
183 "--providerdir:",
184 "--idletimeout:",
185 "--loglevel:",
186 NULL,
187 };
188
189 for (;;)
190 mike 1.1 {
191 int r = GetOpt(argc, argv, opts, &state);
192
193 if (r == 1)
194 break;
195
196 if (r == -1)
197 err("%s", state.err);
198
199 /* Check for -h option */
200 if (strcmp(state.opt, "-h") == 0 || strcmp(state.opt, "--help") == 0)
201 {
202 s_opts.help = MI_TRUE;
203 }
204 else if (strcmp(state.opt, "--version") == 0)
205 {
206 printf("%s: %s\n", arg0,
207 CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE);
208 exit(0);
209 }
210 else if (strcmp(state.opt, "--providerdir") == 0)
211 mike 1.1 {
212 s_opts.provDir = state.arg;
213 }
214 else if (strcmp(state.opt, "--idletimeout") == 0)
215 {
216 char* end;
217 MI_Uint64 x = Strtoull(state.arg, &end, 10);
218
219 if (*end != '\0')
220 err("bad option argument for --idletimeout: %s", state.arg);
221
222 s_opts.idletimeout = x;
223 }
224 else if (strcmp(state.opt, "--loglevel") == 0)
225 {
226 if (Log_SetLevelFromString(state.arg) != 0)
227 {
228 err("bad option argument for %s: %s", state.opt, state.arg);
229 }
230 }
231 }
232 mike 1.1 }
233
234 static void _EventCallback(
235 Protocol* protocol,
236 ProtocolEvent event,
237 void* data)
238 {
239 MI_UNUSED(protocol);
240 MI_UNUSED(event);
241 MI_UNUSED(data);
242
243 LOGI_CHAR(("disconnected form server; exiting"));
244 exit(0);
245 }
246
247 static void _ProvMgrCallbackOnIdle(
248 ProvMgr* mgr,
249 void* callbackData)
250 {
251 BinProtocolNotification* notification;
252
253 mike 1.1 MI_UNUSED(mgr);
254 MI_UNUSED(callbackData);
255
256 LOGI_CHAR(("sending 'agent-idle' notification to the server"));
257
258 notification = BinProtocolNotification_New( BinNotificationAgentIdle );
259
260 if (!notification)
261 return;
262
263 Protocol_Send(s_data.protocol, ¬ification->base);
264
265 BinProtocolNotification_Release(notification);
266 }
267
268 int agent_main(int argc, const char* argv[])
269 {
270 MI_Result r;
271 Sock fd;
272 int logfd;
273
274 mike 1.1 arg0 = argv[0];
275
276 memset(&s_data, 0, sizeof(s_data));
277
278 /* Get --destdir option first (other options may depend on it) */
279 GetCommandLineDestDirOption(&argc, argv);
280
281 /* Extract options */
282 GetCommandLineOptions(&argc, argv);
283
284 /* Print help */
285 if (s_opts.help)
286 {
287 fprintf(stderr, HELP, arg0);
288 exit(1);
289 }
290
291 /* extract socket number */
292 if (argc < 3)
293 {
294 LOGE_CHAR(("parameter is missing (fd)"));
295 mike 1.1 exit(1);
296 }
297
298 fd = Strtol(argv[1], 0, 10);
299 logfd = Strtol(argv[2], 0, 10);
300
301 /* Attach log file */
302 {
303 /* Open the log file */
304 if (Log_OpenFD(logfd) != MI_RESULT_OK)
305 {
306 err("failed to attach log file to fd: %d; errno %d", logfd,
307 (int)errno);
308 }
309 }
310
311 /* selector */
312 {
313 /* Initialize the network */
314 Sock_Start();
315
316 mike 1.1 if(Selector_Init(&s_data.selector) != MI_RESULT_OK)
317 err("Selector_Init() failed");
318 }
319
320 /* Create new protocol object */
321 {
322 r = Protocol_New_From_Socket(
323 &s_data.protocol,
324 &s_data.selector,
325 fd,
326 MI_FALSE,
327 _RequestCallback,
328 0,
329 _EventCallback,
330 0);
331
332 if (r != MI_RESULT_OK)
333 err("Protocol_New_Listener() failed");
334 }
335
336 /* Provider manager */
337 mike 1.1 {
338 r = ProvMgr_Init(&s_data.provmgr, &s_data.selector, _ProvMgrCallbackOnIdle, &s_data, s_opts.provDir);
339
340 if (r != MI_RESULT_OK)
341 err("ProvMgr_Init() failed");
342 }
343
344 /* idle timeout */
345 if (s_opts.idletimeout)
346 {
347 /* convert it to usec */
348 s_data.provmgr.idleTimeoutUsec = s_opts.idletimeout * 1000000;
349 LOGI((T("changing idle timeout to %d sec"), (int)s_opts.idletimeout));
350
351 }
352
353 /* Log start up message */
354 LOGI((T("agent started; fd %d"), (int)fd));
355
356 /* Run the protocol object (waiting for new messages) */
357 r = Protocol_Run(s_data.protocol, TIME_NEVER);
358 mike 1.1
359 if (r != MI_RESULT_OK)
360 err("Protocol_Run() failed (%d)", (int)r);
361
362 // Destroy all global objects
363 Selector_RemoveAllHandlers(&s_data.selector);
364 Protocol_Delete(s_data.protocol);
365 Selector_Destroy(&s_data.selector);
366
367 return 0;
368 }
|