1 /*
2  * test1.c
3  *
4  * OpenIPMI test code showing event setup
5  *
6  * Author: Corey Minyard <minyard@acm.org>
7  *
8  *  This program is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public License
10  *  as published by the Free Software Foundation; either version 2 of
11  *  the License, or (at your option) any later version.
12  *
13  *
14  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
20  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *  You should have received a copy of the GNU Lesser General Public
26  *  License along with this program; if not, write to the Free
27  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <ctype.h>
39 #include <time.h>
40 
41 #include <OpenIPMI/ipmiif.h>
42 #include <OpenIPMI/ipmi_smi.h>
43 #include <OpenIPMI/ipmi_err.h>
44 #include <OpenIPMI/ipmi_auth.h>
45 #include <OpenIPMI/ipmi_lan.h>
46 #include <OpenIPMI/ipmi_posix.h>
47 
48 /* This sample application demostrates some general handling of sensors,
49    like reading values, setting up events, and things of that nature.
50    It also demonstrates some good coding practices like refcounting
51    structures. */
52 
53 static const char *progname;
54 
55 #define MAX_SENSOR_NAME_SIZE 128
56 
57 typedef struct sdata_s
58 {
59     unsigned int       refcount;
60     ipmi_sensor_id_t   sensor_id;
61     char               name[MAX_SENSOR_NAME_SIZE];
62     ipmi_event_state_t *es;
63     ipmi_thresholds_t  *th;
64     int                state_sup;
65     int                thresh_sup;
66 
67     struct sdata_s     *next, *prev;
68 } sdata_t;
69 
70 static sdata_t *sdata_list = NULL;
71 
72 static sdata_t *
alloc_sdata(ipmi_sensor_t * sensor)73 alloc_sdata(ipmi_sensor_t *sensor)
74 {
75     sdata_t *sdata;
76 
77     sdata = malloc(sizeof(*sdata));
78     if (!sdata)
79 	return NULL;
80 
81     sdata->es = malloc(ipmi_event_state_size());
82     if (!sdata->es) {
83 	free(sdata);
84 	return NULL;
85     }
86     ipmi_event_state_init(sdata->es);
87 
88     sdata->th = malloc(ipmi_thresholds_size());
89     if (!sdata->th) {
90 	free(sdata->es);
91 	free(sdata);
92 	return NULL;
93     }
94     ipmi_thresholds_init(sdata->th);
95 
96     sdata->refcount = 1;
97 
98     sdata->sensor_id = ipmi_sensor_convert_to_id(sensor);
99     ipmi_sensor_get_name(sensor, sdata->name, sizeof(sdata->name));
100 
101     sdata->next = sdata_list;
102     sdata->prev = NULL;
103     sdata_list = sdata;
104 
105     return sdata;
106 }
107 
108 static sdata_t *
find_sdata(ipmi_sensor_t * sensor)109 find_sdata(ipmi_sensor_t *sensor)
110 {
111     ipmi_sensor_id_t id = ipmi_sensor_convert_to_id(sensor);
112     sdata_t          *link;
113 
114     link = sdata_list;
115     while (link) {
116 	if (ipmi_cmp_sensor_id(id, link->sensor_id) == 0)
117 	    return link;
118 	link = link->next;
119     }
120     return NULL;
121 }
122 
123 static void
use_sdata(sdata_t * sdata)124 use_sdata(sdata_t *sdata)
125 {
126     sdata->refcount++;
127 }
128 
129 static void
release_sdata(sdata_t * sdata)130 release_sdata(sdata_t *sdata)
131 {
132     sdata->refcount--;
133     if (sdata->refcount == 0) {
134 	/* Remove it from the list. */
135 	if (sdata->next)
136 	    sdata->next->prev = sdata->prev;
137 
138 	if (sdata->prev)
139 	    sdata->prev->next = sdata->next;
140 	else
141 	    sdata_list = sdata->next;
142 
143 	free(sdata->es);
144 	free(sdata->th);
145 	free(sdata);
146     }
147 }
148 
con_usage(const char * name,const char * help,void * cb_data)149 static void con_usage(const char *name, const char *help, void *cb_data)
150 {
151     printf("\n%s%s", name, help);
152 }
153 
154 static void
usage(void)155 usage(void)
156 {
157     printf("Usage:\n");
158     printf(" %s <con_parms>\n", progname);
159     printf(" Where <con_parms> is one of:");
160     ipmi_parse_args_iter_help(con_usage, NULL);
161 }
162 
163 static void
got_thresh_reading(ipmi_sensor_t * sensor,int err,enum ipmi_value_present_e value_present,unsigned int raw_value,double val,ipmi_states_t * states,void * cb_data)164 got_thresh_reading(ipmi_sensor_t             *sensor,
165 		   int                       err,
166 		   enum ipmi_value_present_e value_present,
167 		   unsigned int              raw_value,
168 		   double                    val,
169 		   ipmi_states_t             *states,
170 		   void                      *cb_data)
171 {
172     sdata_t            *sdata = cb_data;
173     enum ipmi_thresh_e thresh;
174 
175     if (err) {
176 	printf("Error 0x%x getting discrete states for sensor %s\n",
177 	       err, sdata->name);
178 	goto out;
179     }
180 
181     printf("Got threshold reading for sensor %s\n", sdata->name);
182     if (ipmi_is_event_messages_enabled(states))
183 	printf("  event messages enabled\n");
184     if (ipmi_is_sensor_scanning_enabled(states))
185 	printf("  sensor scanning enabled\n");
186     if (ipmi_is_initial_update_in_progress(states))
187 	printf("  initial update in progress\n");
188 
189     switch (value_present)
190     {
191     case IPMI_NO_VALUES_PRESENT:
192 	printf("  no value present\n");
193 	break;
194     case IPMI_BOTH_VALUES_PRESENT:
195 	{
196 	    const char *percent = "";
197 	    const char *base;
198 	    const char *mod_use = "";
199 	    const char *modifier = "";
200 	    const char *rate;
201 
202 	    base = ipmi_sensor_get_base_unit_string(sensor);
203 	    if (ipmi_sensor_get_percentage(sensor))
204 		percent = "%";
205 	    switch (ipmi_sensor_get_modifier_unit_use(sensor)) {
206 	    case IPMI_MODIFIER_UNIT_NONE:
207 		break;
208 	    case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
209 		mod_use = "/";
210 		modifier = ipmi_sensor_get_modifier_unit_string(sensor);
211 		break;
212 	    case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
213 		mod_use = "*";
214 		modifier = ipmi_sensor_get_modifier_unit_string(sensor);
215 		break;
216 	    }
217 	    rate = ipmi_sensor_get_rate_unit_string(sensor);
218 
219 	    printf("  value: %lf%s %s%s%s%s\n", val, percent,
220 		   base, mod_use, modifier, rate);
221 	}
222 	/* FALLTHROUGH */
223     case IPMI_RAW_VALUE_PRESENT:
224 	printf("  raw value: 0x%2.2x\n", raw_value);
225     }
226 
227     if (sdata->thresh_sup == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE)
228 	goto out;
229 
230     for (thresh=IPMI_LOWER_NON_CRITICAL;
231 	 thresh<=IPMI_UPPER_NON_RECOVERABLE;
232 	 thresh++)
233     {
234 	int val, rv;
235 
236 	rv = ipmi_sensor_threshold_reading_supported(sensor, thresh, &val);
237 	if (rv || !val)
238 	    continue;
239 
240 	if (ipmi_is_threshold_out_of_range(states, thresh))
241 	    printf("  Threshold %s is out of range\n",
242 		   ipmi_get_threshold_string(thresh));
243 	else
244 	    printf("  Threshold %s is in range\n",
245 		   ipmi_get_threshold_string(thresh));
246     }
247 
248  out:
249     release_sdata(sdata);
250 }
251 
252 static void
got_discrete_states(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)253 got_discrete_states(ipmi_sensor_t *sensor,
254 		    int           err,
255 		    ipmi_states_t *states,
256 		    void          *cb_data)
257 {
258     sdata_t *sdata = cb_data;
259     int     i;
260 
261     if (err) {
262 	printf("Error 0x%x getting discrete states for sensor %s\n",
263 	       err, sdata->name);
264 	goto out;
265     }
266 
267     if (err) {
268 	printf("Error 0x%x getting discrete states for sensor %s\n",
269 	       err, sdata->name);
270 	goto out;
271     }
272 
273     printf("Got state reading for sensor %s\n", sdata->name);
274     if (ipmi_is_event_messages_enabled(states))
275 	printf("  event messages enabled\n");
276     if (ipmi_is_sensor_scanning_enabled(states))
277 	printf("  sensor scanning enabled\n");
278     if (ipmi_is_initial_update_in_progress(states))
279 	printf("  initial update in progress\n");
280 
281     for (i=0; i<15; i++) {
282 	int val, rv;
283 
284 	rv = ipmi_sensor_discrete_event_readable(sensor, i, &val);
285 	if (rv || !val)
286 	    continue;
287 
288 	printf("  state %d value is %d\n", i, ipmi_is_state_set(states, i));
289     }
290 
291  out:
292     release_sdata(sdata);
293 }
294 
295 static void
event_set_done(ipmi_sensor_t * sensor,int err,void * cb_data)296 event_set_done(ipmi_sensor_t *sensor,
297 	       int           err,
298 	       void          *cb_data)
299 {
300     sdata_t *sdata = cb_data;
301 
302     if (err) {
303 	printf("Error 0x%x setting events for sensor %s\n", err, sdata->name);
304 	goto out;
305     }
306 
307     printf("Events set for sensor %s\n", sdata->name);
308 
309  out:
310     release_sdata(sdata);
311 }
312 
313 static void
got_events(ipmi_sensor_t * sensor,int err,ipmi_event_state_t * states,void * cb_data)314 got_events(ipmi_sensor_t      *sensor,
315 	   int                err,
316 	   ipmi_event_state_t *states,
317 	   void               *cb_data)
318 {
319     sdata_t *sdata = cb_data;
320     int     rv;
321 
322     if (err) {
323 	printf("Error 0x%x getting events for sensor %s\n", err, sdata->name);
324 	goto out_err;
325     }
326 
327     /* Turn on the general events for a sensor, since this at
328        least supports per-sensor enables. */
329     ipmi_event_state_set_events_enabled(sdata->es, 1);
330     ipmi_event_state_set_scanning_enabled(sdata->es, 1);
331 
332     printf("Sensor %s event settings:\n", sdata->name);
333     if (sdata->state_sup != IPMI_EVENT_SUPPORT_PER_STATE) {
334 	/* No per-state sensors, just do the global enable. */
335     } else if (ipmi_sensor_get_event_reading_type(sensor)
336 	       == IPMI_EVENT_READING_TYPE_THRESHOLD)
337     {
338 	/* Check each event, print out the current state, and turn it
339 	   on in the events to set if it is available. */
340 	enum ipmi_event_value_dir_e value_dir;
341 	enum ipmi_event_dir_e       dir;
342 	enum ipmi_thresh_e          thresh;
343 	int                         val;
344 	for (value_dir=IPMI_GOING_LOW; value_dir<=IPMI_GOING_HIGH; value_dir++)
345 	{
346 	    for (dir=IPMI_ASSERTION; dir<=IPMI_DEASSERTION; dir++) {
347 		for (thresh=IPMI_LOWER_NON_CRITICAL;
348 		     thresh<=IPMI_UPPER_NON_RECOVERABLE;
349 		     thresh++)
350 		{
351 		    char *v;
352 
353 		    rv = ipmi_sensor_threshold_event_supported
354 			(sensor, thresh, value_dir, dir, &val);
355 		    if (rv || !val)
356 			continue;
357 
358 		    if (ipmi_is_threshold_event_set(states, thresh,
359 						    value_dir, dir))
360 			v = "";
361 		    else
362 			v = " not";
363 
364 		    printf("  %s %s %s was%s enabled\n",
365 			   ipmi_get_threshold_string(thresh),
366 			   ipmi_get_value_dir_string(value_dir),
367 			   ipmi_get_event_dir_string(dir),
368 			   v);
369 
370 		    ipmi_threshold_event_set(sdata->es, thresh,
371 					     value_dir, dir);
372 		}
373 	    }
374 	}
375     } else {
376 	/* Check each event, print out the current state, and turn it
377 	   on in the events to set if it is available. */
378 	enum ipmi_event_dir_e dir;
379 	int                   i;
380 
381 	for (dir=IPMI_ASSERTION; dir<=IPMI_DEASSERTION; dir++) {
382 	    for (i=0; i<15; i++) {
383 		char *v;
384 		int  val;
385 
386 		rv = ipmi_sensor_discrete_event_supported
387 		    (sensor, i, dir, &val);
388 		if (rv || !val)
389 		    continue;
390 
391 		if (ipmi_is_discrete_event_set(states, i, dir))
392 		    v = "";
393 		else
394 		    v = " not";
395 
396 		printf("  bit %d %s was%s enabled\n",
397 		       i,
398 		       ipmi_get_event_dir_string(dir),
399 		       v);
400 
401 		ipmi_discrete_event_set(sdata->es, i, dir);
402 	    }
403 	}
404     }
405 
406     rv = ipmi_sensor_set_event_enables(sensor, sdata->es,
407 				       event_set_done, sdata);
408     if (rv) {
409 	printf("Error 0x%x enabling events for sensor %s\n", err, sdata->name);
410 	goto out_err;
411     }
412 
413     return;
414 
415  out_err:
416     release_sdata(sdata);
417 }
418 
419 static void
thresholds_set(ipmi_sensor_t * sensor,int err,void * cb_data)420 thresholds_set(ipmi_sensor_t *sensor, int err, void *cb_data)
421 {
422     sdata_t *sdata = cb_data;
423 
424     if (err) {
425 	printf("Error 0x%x setting thresholds for sensor %s\n",
426 	       err, sdata->name);
427 	goto out;
428     }
429 
430     printf("Thresholds set for sensor %s\n", sdata->name);
431 
432  out:
433     release_sdata(sdata);
434 }
435 
436 static void
got_thresholds(ipmi_sensor_t * sensor,int err,ipmi_thresholds_t * th,void * cb_data)437 got_thresholds(ipmi_sensor_t     *sensor,
438 	       int               err,
439 	       ipmi_thresholds_t *th,
440 	       void              *cb_data)
441 {
442     sdata_t            *sdata = cb_data;
443     enum ipmi_thresh_e thresh;
444     int                rv;
445 
446     if (err) {
447 	printf("Error 0x%x getting events for sensor %s\n", err, sdata->name);
448 	goto out_err;
449     }
450 
451     printf("Sensor %s threshold settings:\n", sdata->name);
452     for (thresh=IPMI_LOWER_NON_CRITICAL;
453 	 thresh<=IPMI_UPPER_NON_RECOVERABLE;
454 	 thresh++)
455     {
456 	int    val;
457 	double dval;
458 
459 	rv = ipmi_sensor_threshold_readable(sensor, thresh, &val);
460 	if (rv || !val)
461 	    /* Threshold not available. */
462 	    continue;
463 
464 	rv = ipmi_threshold_get(th, thresh, &dval);
465 	if (rv) {
466 	    printf("  threshold %s could not be fetched due to error 0x%x\n",
467 		   ipmi_get_threshold_string(thresh), rv);
468 	} else {
469 	    printf("  threshold %s is %lf\n",
470 		   ipmi_get_threshold_string(thresh), dval);
471 	}
472     }
473 
474     rv = ipmi_get_default_sensor_thresholds(sensor, sdata->th);
475     if (rv) {
476 	printf("Error 0x%x getting def thresholds for sensor %s\n",
477 	       rv, sdata->name);
478 	goto out_err;
479     }
480 
481     rv = ipmi_sensor_set_thresholds(sensor, sdata->th, thresholds_set, sdata);
482     if (rv) {
483 	printf("Error 0x%x setting thresholds for sensor %s\n",
484 	       rv, sdata->name);
485 	goto out_err;
486     }
487     return;
488 
489  out_err:
490     release_sdata(sdata);
491 }
492 
493 
494 /* Whenever the status of a sensor changes, the function is called
495    We display the information of the sensor if we find a new sensor */
496 static void
sensor_change(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)497 sensor_change(enum ipmi_update_e op,
498 	      ipmi_entity_t      *ent,
499 	      ipmi_sensor_t      *sensor,
500 	      void               *cb_data)
501 {
502     sdata_t *sdata;
503     int     rv;
504 
505     if (op == IPMI_ADDED) {
506 	sdata = alloc_sdata(sensor);
507 	if (!sdata) {
508 	    printf("Unable to allocate sensor name memory\n");
509 	    return;
510 	}
511 
512 	printf("Sensor added: %s\n", sdata->name);
513 
514 	/* Get the current reading. */
515 	if (ipmi_sensor_get_event_reading_type(sensor)
516 	    == IPMI_EVENT_READING_TYPE_THRESHOLD)
517 	{
518 	    use_sdata(sdata);
519 	    rv = ipmi_sensor_get_reading(sensor, got_thresh_reading, sdata);
520 	    if (rv) {
521 		printf("ipmi_reading_get returned error 0x%x for sensor %s\n",
522 		       rv, sdata->name);
523 		release_sdata(sdata);
524 	    }
525 	} else {
526 	    use_sdata(sdata);
527 	    rv = ipmi_sensor_get_states(sensor, got_discrete_states, sdata);
528 	    if (rv) {
529 		printf("ipmi_states_get returned error 0x%x for sensor %s\n",
530 		       rv, sdata->name);
531 		release_sdata(sdata);
532 	    }
533 	}
534 
535 	/* Set up events. */
536 	sdata->state_sup = ipmi_sensor_get_event_support(sensor);
537 	switch (sdata->state_sup)
538 	{
539 	    case IPMI_EVENT_SUPPORT_NONE:
540 	    case IPMI_EVENT_SUPPORT_GLOBAL_ENABLE:
541 		/* No events to set up. */
542 		printf("Sensor %s has no event support\n", sdata->name);
543 		goto get_thresh;
544 	}
545 
546 	use_sdata(sdata);
547 	rv = ipmi_sensor_get_event_enables(sensor, got_events, sdata);
548 	if (rv) {
549 	    printf("ipmi_sensor_events_enable_get returned error 0x%x"
550 		   " for sensor %s\n",
551 		   rv, sdata->name);
552 	    release_sdata(sdata);
553 	}
554 
555     get_thresh:
556 	/* Handle the threshold settings. */
557 
558 	if (ipmi_sensor_get_event_reading_type(sensor)
559 	    != IPMI_EVENT_READING_TYPE_THRESHOLD)
560 	    /* Thresholds only for threshold sensors (duh) */
561 	    goto out;
562 
563 	sdata->thresh_sup = ipmi_sensor_get_threshold_access(sensor);
564 
565 	switch (sdata->thresh_sup)
566 	{
567 	case IPMI_THRESHOLD_ACCESS_SUPPORT_NONE:
568 	    printf("Sensor %s has no threshold support\n", sdata->name);
569 	    goto out;
570 
571 	case IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED:
572 	    printf("Sensor %s has fixed threshold support\n", sdata->name);
573 	    goto out;
574 	}
575 
576 	use_sdata(sdata);
577 	rv = ipmi_sensor_get_thresholds(sensor, got_thresholds, sdata);
578 	if (rv) {
579 	    printf("ipmi_thresholds_get returned error 0x%x"
580 		   " for sensor %s\n",
581 		   rv, sdata->name);
582 	    release_sdata(sdata);
583 	}
584     } else if (op == IPMI_DELETED) {
585 	sdata = find_sdata(sensor);
586 	if (!sdata) {
587 	    char name[120];
588 	    ipmi_sensor_get_name(sensor, name, sizeof(name));
589 
590 	    printf("sensor %s was deleted but not found in the sensor db\n",
591 		   name);
592 	    goto out;
593 	}
594 
595 	printf("sensor %s was deleted\n", sdata->name);
596 	release_sdata(sdata);
597     }
598 
599  out:
600     return;
601 }
602 
603 /* Whenever the status of an entity changes, the function is called
604    When a new entity is created, we search all sensors that belong
605    to the entity */
606 static void
entity_change(enum ipmi_update_e op,ipmi_domain_t * domain,ipmi_entity_t * entity,void * cb_data)607 entity_change(enum ipmi_update_e op,
608 	      ipmi_domain_t      *domain,
609 	      ipmi_entity_t      *entity,
610 	      void               *cb_data)
611 {
612     int  rv;
613     char name[50];
614 
615     ipmi_entity_get_name(entity, name, sizeof(name));
616     if (op == IPMI_ADDED) {
617 	    printf("Entity added: %s\n", name);
618 	    /* Register callback so that when the status of a
619 	       sensor changes, sensor_change is called */
620 	    rv = ipmi_entity_add_sensor_update_handler(entity,
621 						       sensor_change,
622 						       NULL);
623 	    if (rv) {
624 		printf("ipmi_entity_set_sensor_update_handler: 0x%x", rv);
625 		exit(1);
626 	    }
627     }
628 }
629 
630 /* After we have established connection to domain, this function get called
631    At this time, we can do whatever things we want to do. Herr we want to
632    search all entities in the system */
633 void
setup_done(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected,void * user_data)634 setup_done(ipmi_domain_t *domain,
635 	   int           err,
636 	   unsigned int  conn_num,
637 	   unsigned int  port_num,
638 	   int           still_connected,
639 	   void          *user_data)
640 {
641     int rv;
642 
643     /* Register a callback functin entity_change. When a new entities
644        is created, entity_change is called */
645     rv = ipmi_domain_add_entity_update_handler(domain, entity_change, domain);
646     if (rv) {
647 	printf("ipmi_domain_add_entity_update_handler return error: %d\n", rv);
648 	return;
649     }
650 }
651 
652 static os_handler_t *os_hnd;
653 
654 int
main(int argc,char * argv[])655 main(int argc, char *argv[])
656 {
657     int         rv;
658     int         curr_arg = 1;
659     ipmi_args_t *args;
660     ipmi_con_t  *con;
661 
662     progname = argv[0];
663 
664     /* OS handler allocated first. */
665     os_hnd = ipmi_posix_setup_os_handler();
666     if (!os_hnd) {
667 	printf("ipmi_smi_setup_con: Unable to allocate os handler\n");
668 	exit(1);
669     }
670 
671     /* Use the default log handler. */
672 
673     /* Initialize the OpenIPMI library. */
674     ipmi_init(os_hnd);
675 
676     rv = ipmi_parse_args2(&curr_arg, argc, argv, &args);
677     if (rv) {
678 	fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
679 		curr_arg, strerror(rv));
680 	usage();
681 	exit(1);
682     }
683 
684     rv = ipmi_args_setup_con(args, os_hnd, NULL, &con);
685     if (rv) {
686         fprintf(stderr, "ipmi_ip_setup_con: %s", strerror(rv));
687 	exit(1);
688     }
689 
690     rv = ipmi_open_domain("", &con, 1, setup_done, NULL, NULL, NULL,
691 			  NULL, 0, NULL);
692     if (rv) {
693 	fprintf(stderr, "ipmi_init_domain: %s\n", strerror(rv));
694 	exit(1);
695     }
696 
697     /* This is the main loop of the event-driven program.
698        Try <CTRL-C> to exit the program */
699     /* Let the selector code run the select loop. */
700     os_hnd->operation_loop(os_hnd);
701 
702     /* Technically, we can't get here, but this is an example. */
703     os_hnd->free_os_handler(os_hnd);
704     return 0;
705 }
706