1 /*
2  * Copyright (C) 2003-2015 FreeIPMI Core Team
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #include <stdarg.h>
28 #endif /* STDC_HEADERS */
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif /* HAVE_UNISTD_H */
32 #include <assert.h>
33 #include <errno.h>
34 
35 #include "freeipmi/debug/ipmi-debug.h"
36 #include "freeipmi/fiid/fiid.h"
37 #include "freeipmi/interface/ipmi-ipmb-interface.h"
38 
39 #include "ipmi-debug-common.h"
40 
41 #include "libcommon/ipmi-trace.h"
42 
43 #include "freeipmi-portability.h"
44 
45 #define IPMI_DEBUG_MAX_BUF_LEN        65536
46 #define IPMI_DEBUG_MAX_PKT_LEN        65536
47 #define IPMI_DEBUG_CHAR_PER_LINE          8
48 #define IPMI_DEBUG_DEFAULT_FD STDERR_FILENO
49 
50 static int
_write(int fd,const void * buf,size_t n)51 _write (int fd, const void *buf, size_t n)
52 {
53   /* chu: by Chris Dunlap <dunlap6 at llnl dot gov> */
54   size_t nleft;
55   ssize_t nwritten;
56   unsigned char *p;
57 
58   p = (unsigned char *)buf;
59   nleft = n;
60   while (nleft > 0)
61     {
62       if ((nwritten = write (fd, p, nleft)) < 0)
63         {
64           if (errno == EINTR)
65             continue;
66           else
67             return (-1);
68         }
69       nleft -= nwritten;
70       p += nwritten;
71     }
72   return (n);
73 }
74 
75 int
debug_dprintf(int fd,const char * fmt,...)76 debug_dprintf (int fd, const char *fmt, ...)
77 {
78   va_list ap;
79   int len, rv;
80   char buf[IPMI_DEBUG_MAX_BUF_LEN];
81 
82   va_start (ap, fmt);
83   len = vsnprintf (buf, IPMI_DEBUG_MAX_BUF_LEN, fmt, ap);
84   rv = _write (fd, buf, len);
85   va_end (ap);
86 
87   return (rv);
88 }
89 
90 int
debug_set_prefix(char * buf,unsigned int buflen,const char * prefix)91 debug_set_prefix (char *buf, unsigned int buflen, const char *prefix)
92 {
93   assert (buf && buflen > 3);
94 
95   /* clear buffer, empty prefix allowed */
96   memset (buf, '\0', buflen);
97   if (prefix)
98     {
99       strncpy (buf, prefix, buflen);
100       buf[buflen - 1] = '\0'; /* strncpy may not null terminate */
101       buf[buflen - 2] = '\0'; /* guaranteed space for ' ' */
102       buf[buflen - 3] = '\0'; /* guaranteed space for ':' */
103       strcat (buf, ": ");
104     }
105 
106   return (0);
107 }
108 
109 int
debug_output_str(int fd,const char * prefix,const char * str)110 debug_output_str (int fd, const char *prefix, const char *str)
111 {
112   /* achu: Yeah, I know this is slow.  Figure out something better
113    * later.
114    */
115   if (str)
116     {
117       char *ptr = (char *)str;
118 
119       if (prefix)
120         {
121           if (debug_dprintf (fd, "%s", prefix) < 0)
122             {
123               ERRNO_TRACE (errno);
124               return (-1);
125             }
126         }
127 
128       while (*ptr != '\0')
129         {
130           if (*ptr == '\n')
131             {
132               if (debug_dprintf (fd, "%c", *ptr++) < 0)
133                 {
134                   ERRNO_TRACE (errno);
135                   return (-1);
136                 }
137               if (prefix)
138                 {
139                   if (debug_dprintf (fd, "%s", prefix) < 0)
140                     {
141                       ERRNO_TRACE (errno);
142                       return (-1);
143                     }
144                 }
145             }
146           else
147             {
148               if (debug_dprintf (fd, "%c", *ptr++) < 0)
149                 {
150                   ERRNO_TRACE (errno);
151                   return (-1);
152                 }
153             }
154         }
155 
156       if (debug_dprintf (fd, "\n") < 0)
157         {
158           ERRNO_TRACE (errno);
159           return (-1);
160         }
161     }
162 
163   return (0);
164 }
165 
166 int
debug_output_byte_array(int fd,const char * prefix,const uint8_t * buf,unsigned int buf_len)167 debug_output_byte_array (int fd, const char *prefix, const uint8_t *buf, unsigned int buf_len)
168 {
169   unsigned int count = 0;
170 
171   assert (buf);
172 
173   while (count < buf_len)
174     {
175       int i = 0;
176       if (prefix)
177         {
178           if (debug_dprintf (fd, "%s", prefix) < 0)
179             {
180               ERRNO_TRACE (errno);
181               return (-1);
182             }
183         }
184 
185       if (debug_dprintf (fd, "[ ") < 0)
186         {
187           ERRNO_TRACE (errno);
188           return (-1);
189         }
190 
191       while (count < buf_len && i < IPMI_DEBUG_CHAR_PER_LINE)
192         {
193           if (debug_dprintf (fd, "%02Xh ", buf[count++]) < 0)
194             {
195               ERRNO_TRACE (errno);
196               return (-1);
197             }
198           i++;
199         }
200 
201       if (debug_dprintf (fd, "]\n") < 0)
202         {
203           ERRNO_TRACE (errno);
204           return (-1);
205         }
206     }
207 
208   return (0);
209 }
210 
211 int
debug_dump_ipmb(int fd,const char * prefix,const uint8_t * ipmb_buf,unsigned int ipmb_buf_len,fiid_template_t tmpl_ipmb_msg_hdr,fiid_template_t tmpl_ipmb_cmd)212 debug_dump_ipmb (int fd,
213                  const char *prefix,
214                  const uint8_t *ipmb_buf,
215                  unsigned int ipmb_buf_len,
216                  fiid_template_t tmpl_ipmb_msg_hdr,
217                  fiid_template_t tmpl_ipmb_cmd)
218 {
219   char *ipmb_msg_hdr =
220     "IPMB Message Header:\n"
221     "--------------------";
222   char *ipmb_cmd_hdr =
223     "IPMB Message Data:\n"
224     "------------------";
225   char *ipmb_msg_trlr_hdr =
226     "IPMB Message Trailer:\n"
227     "---------------------";
228   char *ipmb_unexpected_hdr =
229     "IPMB Unexpected Data:\n"
230     "---------------------";
231   fiid_obj_t obj_ipmb_msg_hdr = NULL;
232   fiid_obj_t obj_ipmb_cmd = NULL;
233   fiid_obj_t obj_ipmb_msg_trlr = NULL;
234   fiid_obj_t obj_ipmb_unexpected_data = NULL;
235   int obj_ipmb_msg_trlr_len = 0;
236   unsigned int obj_ipmb_cmd_len = 0;
237   int ipmb_hdr_len = 0;
238   int ipmb_cmd_len = 0;
239   int ipmb_trlr_len = 0;
240   int len;
241   unsigned int ipmb_indx = 0;
242   int rv = -1;
243 
244   assert (ipmb_buf);
245   assert (ipmb_buf_len);
246   assert (tmpl_ipmb_msg_hdr);
247   assert (tmpl_ipmb_cmd);
248 
249   if (!(obj_ipmb_msg_hdr = fiid_obj_create (tmpl_ipmb_msg_hdr)))
250     {
251       ERRNO_TRACE (errno);
252       goto cleanup;
253     }
254   if (!(obj_ipmb_cmd = fiid_obj_create (tmpl_ipmb_cmd)))
255     {
256       ERRNO_TRACE (errno);
257       goto cleanup;
258     }
259   if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr)))
260     {
261       ERRNO_TRACE (errno);
262       goto cleanup;
263     }
264 
265   if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0)
266     {
267       ERRNO_TRACE (errno);
268       goto cleanup;
269     }
270 
271   if ((ipmb_hdr_len = fiid_obj_set_all (obj_ipmb_msg_hdr,
272                                         ipmb_buf,
273                                         ipmb_buf_len)) < 0)
274     {
275       FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
276       goto cleanup;
277     }
278   ipmb_indx += ipmb_hdr_len;
279 
280   if (ipmi_obj_dump (fd,
281                      prefix,
282                      ipmb_msg_hdr,
283                      NULL,
284                      obj_ipmb_msg_hdr) < 0)
285     {
286       ERRNO_TRACE (errno);
287       goto cleanup;
288     }
289 
290   if (ipmb_buf_len <= ipmb_indx)
291     {
292       rv = 0;
293       goto cleanup;
294     }
295 
296   if ((ipmb_buf_len - ipmb_hdr_len) <= obj_ipmb_msg_trlr_len)
297     goto dump_ipmb_extra;
298 
299   obj_ipmb_cmd_len = (ipmb_buf_len - ipmb_hdr_len) - obj_ipmb_msg_trlr_len;
300 
301   if ((ipmb_cmd_len = fiid_obj_set_all (obj_ipmb_cmd,
302                                         ipmb_buf + ipmb_hdr_len,
303                                         obj_ipmb_cmd_len)) < 0)
304     {
305       FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_cmd);
306       goto cleanup;
307     }
308   ipmb_indx += ipmb_cmd_len;
309 
310   if (ipmi_obj_dump (fd,
311                      prefix,
312                      ipmb_cmd_hdr,
313                      NULL,
314                      obj_ipmb_cmd) < 0)
315     {
316       ERRNO_TRACE (errno);
317       goto cleanup;
318     }
319 
320   if (ipmb_buf_len <= ipmb_indx)
321     {
322       rv = 0;
323       goto cleanup;
324     }
325 
326   if ((ipmb_trlr_len = fiid_obj_set_all (obj_ipmb_msg_trlr,
327                                          ipmb_buf + ipmb_hdr_len + ipmb_cmd_len,
328                                          (ipmb_buf_len - ipmb_hdr_len - ipmb_cmd_len))) < 0)
329     {
330       FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr);
331       goto cleanup;
332     }
333   ipmb_indx += ipmb_trlr_len;
334 
335   if (ipmi_obj_dump (fd,
336                      prefix,
337                      ipmb_msg_trlr_hdr,
338                      NULL,
339                      obj_ipmb_msg_trlr) < 0)
340     {
341       ERRNO_TRACE (errno);
342       goto cleanup;
343     }
344 
345   /* Dump IPMB unexpected stuff */
346 
347  dump_ipmb_extra:
348 
349   if ((ipmb_buf_len - ipmb_indx) > 0)
350     {
351       if (!(obj_ipmb_unexpected_data = fiid_obj_create (tmpl_unexpected_data)))
352         {
353           ERRNO_TRACE (errno);
354           goto cleanup;
355         }
356 
357       if ((len = fiid_obj_set_all (obj_ipmb_unexpected_data,
358                                    ipmb_buf + ipmb_indx,
359                                    ipmb_buf_len - ipmb_indx)) < 0)
360         {
361           FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_unexpected_data);
362           goto cleanup;
363         }
364       ipmb_indx += len;
365 
366       if (ipmi_obj_dump (fd,
367                          prefix,
368                          ipmb_unexpected_hdr,
369                          NULL,
370                          obj_ipmb_unexpected_data) < 0)
371         {
372           ERRNO_TRACE (errno);
373           goto cleanup;
374         }
375     }
376 
377   rv = 0;
378  cleanup:
379   fiid_obj_destroy (obj_ipmb_msg_hdr);
380   fiid_obj_destroy (obj_ipmb_cmd);
381   fiid_obj_destroy (obj_ipmb_msg_trlr);
382   fiid_obj_destroy (obj_ipmb_unexpected_data);
383   return (rv);
384 
385 }
386