00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <config.h>
00035
00036 #include <stdlib.h>
00037 #include <errno.h>
00038 #include <stdio.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <fcntl.h>
00042 #include <unistd.h>
00043 #include <string.h>
00044
00045 #include <OpenIPMI/os_handler.h>
00046 #include <OpenIPMI/selector.h>
00047 #include <OpenIPMI/ipmi_debug.h>
00048
00049
00050 #include <OpenIPMI/internal/ipmi_malloc.h>
00051
00052 static os_vlog_t log_handler;
00053
00054 #ifdef HAVE_GDBM
00055 #include <gdbm.h>
00056
00057 static char *gdbm_filename;
00058 static GDBM_FILE gdbmf;
00059 #endif
00060
00061
00062 extern selector_t *debug_sel;
00063
00064 #ifdef IPMI_CHECK_LOCKS
00065 static void check_no_locks(os_handler_t *handler);
00066 #define CHECK_NO_LOCKS(handler) check_no_locks(handler)
00067 #else
00068 #define CHECK_NO_LOCKS(handler) do {} while(0)
00069 #endif
00070
00071 struct os_hnd_fd_id_s
00072 {
00073 int fd;
00074 void *cb_data;
00075 os_data_ready_t data_ready;
00076 os_handler_t *handler;
00077 os_fd_data_freed_t freed;
00078 };
00079
00080 static void
00081 fd_handler(int fd, void *data)
00082 {
00083 os_hnd_fd_id_t *fd_data = (os_hnd_fd_id_t *) data;
00084
00085 CHECK_NO_LOCKS(fd_data->handler);
00086 fd_data->data_ready(fd, fd_data->cb_data, fd_data);
00087 CHECK_NO_LOCKS(fd_data->handler);
00088 }
00089
00090 static void
00091 free_fd_data(int fd, void *data)
00092 {
00093 os_hnd_fd_id_t *fd_data = data;
00094
00095 if (fd_data->freed)
00096 fd_data->freed(fd, fd_data->cb_data);
00097 ipmi_mem_free(data);
00098 }
00099
00100 static int
00101 add_fd(os_handler_t *handler,
00102 int fd,
00103 os_data_ready_t data_ready,
00104 void *cb_data,
00105 os_fd_data_freed_t freed,
00106 os_hnd_fd_id_t **id)
00107 {
00108 os_hnd_fd_id_t *fd_data;
00109 int rv;
00110
00111 fd_data = ipmi_mem_alloc(sizeof(*fd_data));
00112 if (!fd_data)
00113 return ENOMEM;
00114
00115 fd_data->fd = fd;
00116 fd_data->cb_data = cb_data;
00117 fd_data->data_ready = data_ready;
00118 fd_data->handler = handler;
00119 fd_data->freed = freed;
00120 rv = sel_set_fd_handlers(debug_sel, fd, fd_data, fd_handler, NULL, NULL,
00121 free_fd_data);
00122 if (rv) {
00123 ipmi_mem_free(fd_data);
00124 return rv;
00125 }
00126 sel_set_fd_read_handler(debug_sel, fd, SEL_FD_HANDLER_ENABLED);
00127 sel_set_fd_write_handler(debug_sel, fd, SEL_FD_HANDLER_DISABLED);
00128 sel_set_fd_except_handler(debug_sel, fd, SEL_FD_HANDLER_DISABLED);
00129
00130 *id = fd_data;
00131 return 0;
00132 }
00133
00134 static int
00135 remove_fd(os_handler_t *handler, os_hnd_fd_id_t *fd_data)
00136 {
00137 sel_set_fd_read_handler(debug_sel, fd_data->fd, SEL_FD_HANDLER_DISABLED);
00138 sel_clear_fd_handlers(debug_sel, fd_data->fd);
00139
00140
00141 return 0;
00142 }
00143
00144 struct os_hnd_timer_id_s
00145 {
00146 void *cb_data;
00147 os_timed_out_t timed_out;
00148 sel_timer_t *timer;
00149 int running;
00150 os_handler_t *handler;
00151 };
00152
00153 static void
00154 timer_handler(selector_t *sel,
00155 sel_timer_t *timer,
00156 void *data)
00157 {
00158 os_hnd_timer_id_t *timer_data = (os_hnd_timer_id_t *) data;
00159
00160
00161 os_handler_t *os_handler = timer_data->handler;
00162 void *cb_data;
00163 os_timed_out_t timed_out;
00164
00165 CHECK_NO_LOCKS(os_handler);
00166 timed_out = timer_data->timed_out;
00167 cb_data = timer_data->cb_data;
00168 timer_data->running = 0;
00169 timed_out(cb_data, timer_data);
00170 CHECK_NO_LOCKS(os_handler);
00171 }
00172
00173 static int
00174 start_timer(os_handler_t *handler,
00175 os_hnd_timer_id_t *id,
00176 struct timeval *timeout,
00177 os_timed_out_t timed_out,
00178 void *cb_data)
00179 {
00180 struct timeval now;
00181
00182 if (id->running)
00183 return EBUSY;
00184
00185 id->running = 1;
00186 id->cb_data = cb_data;
00187 id->timed_out = timed_out;
00188
00189 gettimeofday(&now, NULL);
00190 now.tv_sec += timeout->tv_sec;
00191 now.tv_usec += timeout->tv_usec;
00192 while (now.tv_usec >= 1000000) {
00193 now.tv_usec -= 1000000;
00194 now.tv_sec += 1;
00195 }
00196
00197 return sel_start_timer(id->timer, &now);
00198 }
00199
00200 static int
00201 stop_timer(os_handler_t *handler, os_hnd_timer_id_t *timer_data)
00202 {
00203 return sel_stop_timer(timer_data->timer);
00204 }
00205
00206 static int
00207 alloc_timer(os_handler_t *handler,
00208 os_hnd_timer_id_t **id)
00209 {
00210 os_hnd_timer_id_t *timer_data;
00211 int rv;
00212
00213 timer_data = ipmi_mem_alloc(sizeof(*timer_data));
00214 if (!timer_data)
00215 return ENOMEM;
00216
00217 timer_data->running = 0;
00218 timer_data->timed_out = NULL;
00219 timer_data->handler = handler;
00220
00221 rv = sel_alloc_timer(debug_sel, timer_handler, timer_data,
00222 &(timer_data->timer));
00223 if (rv) {
00224 ipmi_mem_free(timer_data);
00225 return rv;
00226 }
00227
00228 *id = timer_data;
00229 return 0;
00230 }
00231
00232 static int
00233 free_timer(os_handler_t *handler, os_hnd_timer_id_t *timer_data)
00234 {
00235 sel_free_timer(timer_data->timer);
00236 ipmi_mem_free(timer_data);
00237 return 0;
00238 }
00239
00240 static int
00241 get_random(os_handler_t *handler, void *data, unsigned int len)
00242 {
00243 int fd = open("/dev/urandom", O_RDONLY);
00244 int rv;
00245
00246 if (fd == -1)
00247 return errno;
00248
00249 while (len > 0) {
00250 rv = read(fd, data, len);
00251 if (rv < 0) {
00252 rv = errno;
00253 goto out;
00254 }
00255 len -= rv;
00256 }
00257
00258 rv = 0;
00259
00260 out:
00261 close(fd);
00262 return rv;
00263 }
00264
00265 extern void debug_vlog(const char *format, enum ipmi_log_type_e log_type,
00266 va_list ap);
00267
00268 static void
00269 sdebug_vlog(os_handler_t *handler,
00270 enum ipmi_log_type_e log_type,
00271 const char *format,
00272 va_list ap)
00273 {
00274 if (log_handler)
00275 log_handler(handler, format, log_type, ap);
00276 }
00277
00278 static void
00279 sdebug_log(os_handler_t *handler,
00280 enum ipmi_log_type_e log_type,
00281 const char *format,
00282 ...)
00283 {
00284 va_list ap;
00285
00286 va_start(ap, format);
00287 sdebug_vlog(handler, log_type, format, ap);
00288 va_end(ap);
00289 }
00290
00291 #ifdef IPMI_CHECK_LOCKS
00292 struct os_hnd_lock_s
00293 {
00294 os_hnd_lock_t *next, *prev;
00295 int lock_count;
00296 };
00297
00298 static os_hnd_lock_t locks = { &locks, &locks, 0 };
00299
00300 static int
00301 create_lock(os_handler_t *handler,
00302 os_hnd_lock_t **id)
00303 {
00304 os_hnd_lock_t *lock;
00305
00306 lock = ipmi_mem_alloc(sizeof(*lock));
00307 if (!lock)
00308 return ENOMEM;
00309 lock->lock_count = 0;
00310 lock->next = NULL;
00311 lock->prev = NULL;
00312 *id = lock;
00313 return 0;
00314 }
00315
00316 static int
00317 destroy_lock(os_handler_t *handler,
00318 os_hnd_lock_t *id)
00319 {
00320 if (id->lock_count != 0) {
00321 IPMI_REPORT_LOCK_ERROR(handler,
00322 "Release of lock when count is not zero\n");
00323 id->next->prev = id->prev;
00324 id->prev->next = id->next;
00325 }
00326 ipmi_mem_free(id);
00327 return 0;
00328 }
00329
00330 static int
00331 lock(os_handler_t *handler,
00332 os_hnd_lock_t *id)
00333 {
00334 if (id->lock_count == 0) {
00335 id->next = locks.next;
00336 id->prev = &locks;
00337 id->next->prev = id;
00338 locks.next = id;
00339 } else
00340 IPMI_REPORT_LOCK_ERROR(handler,
00341 "lock called recursively\n");
00342
00343 id->lock_count++;
00344 return 0;
00345 }
00346
00347 static int
00348 unlock(os_handler_t *handler,
00349 os_hnd_lock_t *id)
00350 {
00351 if (id->lock_count <= 0)
00352 IPMI_REPORT_LOCK_ERROR(handler,
00353 "lock count went negative\n");
00354 id->lock_count--;
00355 if (id->lock_count == 0) {
00356 id->next->prev = id->prev;
00357 id->prev->next = id->next;
00358 id->next = NULL;
00359 id->prev = NULL;
00360 }
00361 return 0;
00362 }
00363
00364 static void
00365 check_no_locks(os_handler_t *handler)
00366 {
00367 if (locks.next != &locks)
00368 IPMI_REPORT_LOCK_ERROR(handler,
00369 "Locks held when all should be free\n");
00370 }
00371 #endif
00372
00373 static int
00374 perform_one_op(os_handler_t *os_hnd,
00375 struct timeval *timeout)
00376 {
00377 return sel_select(debug_sel, NULL, 0, NULL, timeout);
00378 }
00379
00380 static void
00381 operation_loop(os_handler_t *os_hnd)
00382 {
00383 sel_select_loop(debug_sel, NULL, 0, NULL);
00384 }
00385
00386 static void
00387 free_os_handler(os_handler_t *os_hnd)
00388 {
00389 }
00390
00391 static void *
00392 debug_malloc(int size)
00393 {
00394 return malloc(size);
00395 }
00396
00397 static void
00398 debug_free(void *data)
00399 {
00400 free(data);
00401 }
00402
00403 #ifdef HAVE_GDBM
00404 #define GDBM_FILE ".OpenIPMI_db"
00405
00406 static void
00407 init_gdbm(void)
00408 {
00409 if (!gdbm_filename) {
00410 char *home = getenv("HOME");
00411 if (!home)
00412 return;
00413 gdbm_filename = malloc(strlen(home)+strlen(GDBM_FILE)+2);
00414 if (!gdbm_filename)
00415 return;
00416 strcpy(gdbm_filename, home);
00417 strcat(gdbm_filename, "/");
00418 strcat(gdbm_filename, GDBM_FILE);
00419 }
00420
00421 gdbmf = gdbm_open(gdbm_filename, 512, GDBM_WRCREAT, 0600, NULL);
00422
00423 }
00424
00425 static int
00426 database_store(os_handler_t *handler,
00427 char *key,
00428 unsigned char *data,
00429 unsigned int data_len)
00430 {
00431 datum gkey, gdata;
00432 int rv;
00433
00434 if (!gdbmf) {
00435 init_gdbm();
00436 if (!gdbmf)
00437 return EINVAL;
00438 }
00439
00440 gkey.dptr = key;
00441 gkey.dsize = strlen(key);
00442 gdata.dptr = (char *) data;
00443 gdata.dsize = data_len;
00444
00445 rv = gdbm_store(gdbmf, gkey, gdata, GDBM_REPLACE);
00446 if (rv)
00447 return EINVAL;
00448 return 0;
00449 }
00450
00451 static int
00452 database_find(os_handler_t *handler,
00453 char *key,
00454 unsigned int *fetch_completed,
00455 unsigned char **data,
00456 unsigned int *data_len,
00457 void (*got_data)(void *cb_data,
00458 int err,
00459 unsigned char *data,
00460 unsigned int data_len),
00461 void *cb_data)
00462 {
00463 datum gkey, gdata;
00464
00465 if (!gdbmf) {
00466 init_gdbm();
00467 if (!gdbmf)
00468 return EINVAL;
00469 }
00470
00471 gkey.dptr = key;
00472 gkey.dsize = strlen(key);
00473 gdata = gdbm_fetch(gdbmf, gkey);
00474 if (!gdata.dptr)
00475 return EINVAL;
00476 *data = (unsigned char *) gdata.dptr;
00477 *data_len = gdata.dsize;
00478 *fetch_completed = 1;
00479 return 0;
00480 }
00481
00482 static void
00483 database_free(os_handler_t *handler,
00484 unsigned char *data)
00485 {
00486 free(data);
00487 }
00488
00489 static int
00490 set_gdbm_filename(os_handler_t *os_hnd, char *name)
00491 {
00492 char *nname;
00493
00494 nname = strdup(name);
00495 if (!nname)
00496 return ENOMEM;
00497 if (gdbm_filename)
00498 free(gdbm_filename);
00499 gdbm_filename = name;
00500 return 0;
00501 }
00502 #endif
00503
00504 void sset_log_handler(os_handler_t *handler,
00505 os_vlog_t rlog_handler)
00506 {
00507 log_handler = rlog_handler;
00508 }
00509
00510 os_handler_t ipmi_debug_os_handlers =
00511 {
00512 .mem_alloc = debug_malloc,
00513 .mem_free = debug_free,
00514 .add_fd_to_wait_for = add_fd,
00515 .remove_fd_to_wait_for = remove_fd,
00516 .start_timer = start_timer,
00517 .stop_timer = stop_timer,
00518 .alloc_timer = alloc_timer,
00519 .free_timer = free_timer,
00520 #ifdef IPMI_CHECK_LOCKS
00521 .create_lock = create_lock,
00522 .destroy_lock = destroy_lock,
00523 .lock = lock,
00524 .unlock = unlock,
00525 #else
00526 .create_lock = NULL,
00527 .destroy_lock = NULL,
00528 .lock = NULL,
00529 .unlock = NULL,
00530 #endif
00531 .get_random = get_random,
00532 .perform_one_op = perform_one_op,
00533 .operation_loop = operation_loop,
00534 .free_os_handler = free_os_handler,
00535 .log = sdebug_log,
00536 .vlog = sdebug_vlog,
00537 #ifdef HAVE_GDBM
00538 .database_store = database_store,
00539 .database_find = database_find,
00540 .database_free = database_free,
00541 .database_set_filename = set_gdbm_filename,
00542 #endif
00543 .set_log_handler = sset_log_handler,
00544 };