1 /*
2 * waiter_sample.c
3 *
4 * OpenIPMI test code how to use OS handler waiters for blocking code.
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_SENSORS 128
56
57 struct waiter_data
58 {
59 os_handler_waiter_t *waiter;
60 int err;
61 ipmi_sensor_id_t sensors[MAX_SENSORS];
62 int sensors_type[MAX_SENSORS];
63 unsigned int num_sensors;
64 unsigned int curr;
65
66 /* values from a threshold sensor. */
67 enum ipmi_value_present_e value_present;
68 unsigned int raw_value;
69 double val;
70
71 /* values from a discrete and a threshold sensor */
72 ipmi_states_t *states;
73 };
74
75 void
setup_done(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected,void * cb_data)76 setup_done(ipmi_domain_t *domain,
77 int err,
78 unsigned int conn_num,
79 unsigned int port_num,
80 int still_connected,
81 void *cb_data)
82 {
83 struct waiter_data *wd = cb_data;
84
85 if (err) {
86 wd->err = err;
87 os_handler_waiter_release(wd->waiter);
88 }
89 }
90
91 void
fully_up(ipmi_domain_t * domain,void * cb_data)92 fully_up(ipmi_domain_t *domain, void *cb_data)
93 {
94 struct waiter_data *wd = cb_data;
95
96 wd->err = 0;
97 os_handler_waiter_release(wd->waiter);
98 }
99
100 void
sensor_handler(ipmi_entity_t * entity,ipmi_sensor_t * sensor,void * cb_data)101 sensor_handler(ipmi_entity_t *entity, ipmi_sensor_t *sensor, void *cb_data)
102 {
103 struct waiter_data *wd = cb_data;
104
105 if (wd->num_sensors >= MAX_SENSORS)
106 return;
107
108 wd->sensors[wd->num_sensors] = ipmi_sensor_convert_to_id(sensor);
109 wd->sensors_type[wd->num_sensors]
110 = ipmi_sensor_get_event_reading_type(sensor);
111
112 wd->num_sensors++;
113 }
114
115 void
entity_iterate_sensors(ipmi_entity_t * entity,void * cb_data)116 entity_iterate_sensors(ipmi_entity_t *entity, void *cb_data)
117 {
118 ipmi_entity_iterate_sensors(entity, sensor_handler, cb_data);
119 }
120
121 void
domain_iterate_entities(ipmi_domain_t * domain,void * cb_data)122 domain_iterate_entities(ipmi_domain_t *domain, void *cb_data)
123 {
124 ipmi_domain_iterate_entities(domain, entity_iterate_sensors, cb_data);
125 }
126
127 void
close_done(void * cb_data)128 close_done(void *cb_data)
129 {
130 struct waiter_data *wd = cb_data;
131
132 os_handler_waiter_release(wd->waiter);
133 }
134
135 void
domain_close(ipmi_domain_t * domain,void * cb_data)136 domain_close(ipmi_domain_t *domain, void *cb_data)
137 {
138 struct waiter_data *wd = cb_data;
139
140 wd->err = ipmi_domain_close(domain, close_done, cb_data);
141 if (wd->err)
142 os_handler_waiter_release(wd->waiter);
143 }
144
145 static void
handle_sensor_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)146 handle_sensor_reading(ipmi_sensor_t *sensor,
147 int err,
148 enum ipmi_value_present_e value_present,
149 unsigned int raw_value,
150 double val,
151 ipmi_states_t *states,
152 void *cb_data)
153 {
154 struct waiter_data *wd = cb_data;
155 enum ipmi_thresh_e thresh;
156 char name[IPMI_SENSOR_NAME_LEN];
157
158 ipmi_sensor_get_name(sensor, name, sizeof(name));
159 if (err) {
160 printf("Error 0x%x getting discrete states for sensor %s\n",
161 err, name);
162 goto out;
163 }
164
165 printf("Got threshold reading for sensor %s\n", name);
166 if (ipmi_is_event_messages_enabled(states))
167 printf(" event messages enabled\n");
168 if (ipmi_is_sensor_scanning_enabled(states))
169 printf(" sensor scanning enabled\n");
170 if (ipmi_is_initial_update_in_progress(states))
171 printf(" initial update in progress\n");
172
173 switch (value_present)
174 {
175 case IPMI_NO_VALUES_PRESENT:
176 printf(" no value present\n");
177 break;
178 case IPMI_BOTH_VALUES_PRESENT:
179 {
180 const char *percent = "";
181 const char *base;
182 const char *mod_use = "";
183 const char *modifier = "";
184 const char *rate;
185
186 base = ipmi_sensor_get_base_unit_string(sensor);
187 if (ipmi_sensor_get_percentage(sensor))
188 percent = "%";
189 switch (ipmi_sensor_get_modifier_unit_use(sensor)) {
190 case IPMI_MODIFIER_UNIT_NONE:
191 break;
192 case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
193 mod_use = "/";
194 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
195 break;
196 case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
197 mod_use = "*";
198 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
199 break;
200 }
201 rate = ipmi_sensor_get_rate_unit_string(sensor);
202
203 printf(" value: %lf%s %s%s%s%s\n", val, percent,
204 base, mod_use, modifier, rate);
205 }
206 /* FALLTHROUGH */
207 case IPMI_RAW_VALUE_PRESENT:
208 printf(" raw value: 0x%2.2x\n", raw_value);
209 }
210
211 if (ipmi_sensor_get_threshold_access(sensor)
212 == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE)
213 goto out;
214
215 for (thresh=IPMI_LOWER_NON_CRITICAL;
216 thresh<=IPMI_UPPER_NON_RECOVERABLE;
217 thresh++)
218 {
219 int val, rv;
220
221 rv = ipmi_sensor_threshold_reading_supported(sensor, thresh, &val);
222 if (rv || !val)
223 continue;
224
225 if (ipmi_is_threshold_out_of_range(states, thresh))
226 printf(" Threshold %s is out of range\n",
227 ipmi_get_threshold_string(thresh));
228 else
229 printf(" Threshold %s is in range\n",
230 ipmi_get_threshold_string(thresh));
231 }
232
233 out:
234 os_handler_waiter_release(wd->waiter);
235 }
236
237 static void
handle_sensor_states(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)238 handle_sensor_states(ipmi_sensor_t *sensor,
239 int err,
240 ipmi_states_t *states,
241 void *cb_data)
242 {
243 struct waiter_data *wd = cb_data;
244 int i;
245 char name[IPMI_SENSOR_NAME_LEN];
246
247 ipmi_sensor_get_name(sensor, name, sizeof(name));
248 if (err) {
249 printf("Error 0x%x getting discrete states for sensor %s\n",
250 err, name);
251 goto out;
252 }
253
254 printf("Got state reading for sensor %s\n", name);
255 if (ipmi_is_event_messages_enabled(states))
256 printf(" event messages enabled\n");
257 if (ipmi_is_sensor_scanning_enabled(states))
258 printf(" sensor scanning enabled\n");
259 if (ipmi_is_initial_update_in_progress(states))
260 printf(" initial update in progress\n");
261
262 for (i=0; i<15; i++) {
263 int val, rv;
264
265 rv = ipmi_sensor_discrete_event_readable(sensor, i, &val);
266 if (rv || !val)
267 continue;
268
269 printf(" state %d value is %d\n", i, ipmi_is_state_set(states, i));
270 }
271
272 out:
273 os_handler_waiter_release(wd->waiter);
274 }
275
276 int
main(int argc,char * argv[])277 main(int argc, char *argv[])
278 {
279 int rv;
280 int curr_arg = 1;
281 ipmi_args_t *args;
282 ipmi_con_t *con;
283 os_handler_waiter_factory_t *waiterf;
284 os_handler_t *os_hnd;
285 char ebuf[128];
286 ipmi_domain_id_t domain_id;
287
288
289 /*
290 * We can do this without dynamic allocation because this function will
291 * never be exited until the progran is done.
292 */
293 struct waiter_data waiter_space;
294 struct waiter_data *wd = &waiter_space;
295
296 progname = argv[0];
297
298 /* OS handler allocated first. */
299 os_hnd = ipmi_posix_setup_os_handler();
300 if (!os_hnd) {
301 printf("ipmi_smi_setup_con: Unable to allocate os handler\n");
302 exit(1);
303 }
304
305 /* Use the default log handler. */
306
307 /* Initialize the OpenIPMI library. */
308 ipmi_init(os_hnd);
309
310 rv = ipmi_parse_args2(&curr_arg, argc, argv, &args);
311 if (rv) {
312 fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
313 curr_arg, ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
314 exit(1);
315 }
316
317 rv = ipmi_args_setup_con(args, os_hnd, NULL, &con);
318 if (rv) {
319 fprintf(stderr, "ipmi_ip_setup_con: %s",
320 ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
321 exit(1);
322 }
323
324 rv = os_handler_alloc_waiter_factory(os_hnd, 0, 0, &waiterf);
325 if (rv) {
326 fprintf(stderr, "os_handler_alloc_waiter_factory: %s",
327 ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
328 exit(1);
329 }
330
331 wd->num_sensors = 0;
332 wd->waiter = os_handler_alloc_waiter(waiterf);
333 if (!wd->waiter) {
334 fprintf(stderr, "os_handler_alloc_waiter: Out of memory");
335 exit(1);
336 }
337
338 rv = ipmi_open_domain("", &con, 1, setup_done, wd, fully_up, wd,
339 NULL, 0, &domain_id);
340 if (rv) {
341 fprintf(stderr, "ipmi_init_domain: %s\n",
342 ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
343 exit(1);
344 }
345
346 os_handler_waiter_wait(wd->waiter, NULL);
347 if (wd->err) {
348 fprintf(stderr, "Error starting connection: %s\n",
349 ipmi_get_error_string(wd->err, ebuf, sizeof(ebuf)));
350 }
351
352 /*
353 * At this point the domain is fully up. We can iterate the
354 * sensors now. First get a list of all sensor ids.
355 */
356 ipmi_domain_pointer_cb(domain_id, domain_iterate_entities, wd);
357
358 /*
359 * Now scan the sensors
360 */
361 for (wd->curr = 0; wd->curr < wd->num_sensors; wd->curr++) {
362 os_handler_waiter_use(wd->waiter);
363 if (wd->sensors_type[wd->curr] == IPMI_EVENT_READING_TYPE_THRESHOLD)
364 rv = ipmi_sensor_id_get_reading(wd->sensors[wd->curr],
365 handle_sensor_reading, wd);
366 else
367 rv = ipmi_sensor_id_get_states(wd->sensors[wd->curr],
368 handle_sensor_states, wd);
369 if (rv) {
370 fprintf(stderr, "Error reading sensor: %s\n",
371 ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
372 continue;
373 }
374 os_handler_waiter_wait(wd->waiter, NULL);
375 }
376
377 wd->err = 0;
378 os_handler_waiter_use(wd->waiter);
379 rv = ipmi_domain_pointer_cb(domain_id, domain_close, wd);
380 if (rv) {
381 fprintf(stderr, "close ptr cb: %s\n",
382 ipmi_get_error_string(rv, ebuf, sizeof(ebuf)));
383 exit(1);
384 }
385 os_handler_waiter_wait(wd->waiter, NULL);
386 if (wd->err) {
387 fprintf(stderr, "ipmi_domain_close: %s\n",
388 ipmi_get_error_string(wd->err, ebuf, sizeof(ebuf)));
389 }
390
391 /* Technically, we can't get here, but this is an example. */
392 os_hnd->free_os_handler(os_hnd);
393 return 0;
394 }
395