Main Page | Class List | Directories | File List | Class Members | File Members

os_debug.c

Go to the documentation of this file.
00001 /*
00002  * os_debug.c
00003  *
00004  * Debugging OS handler.
00005  *
00006  * Author: MontaVista Software, Inc.
00007  *         Corey Minyard <minyard@mvista.com>
00008  *         source@mvista.com
00009  *
00010  * Copyright 2002,2003 MontaVista Software Inc.
00011  *
00012  *  This program is free software; you can redistribute it and/or
00013  *  modify it under the terms of the GNU Lesser General Public License
00014  *  as published by the Free Software Foundation; either version 2 of
00015  *  the License, or (at your option) any later version.
00016  *
00017  *
00018  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00019  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00025  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00026  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00027  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  *  You should have received a copy of the GNU Lesser General Public
00030  *  License along with this program; if not, write to the Free
00031  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 /* Internal includes, do not use in your programs */
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     /* fd_data gets freed in the free_fd_data callback registered at
00140        set time. */
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     /* Make a copy of this, because the handler may delete the timer
00160        data. */
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     /* gdbmf will be NULL on error, which is what reports an error. */
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 };

© sourcejam.com 2005-2008