etc/services - sync with NetBSD-8
[minix.git] / external / bsd / tcpdump / dist / util.c
blob4593d246197a42f2892787d6b5f42f0d519461e3
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 #include <sys/cdefs.h>
23 #ifndef lint
24 __RCSID("$NetBSD: util.c,v 1.5 2015/03/31 21:59:35 christos Exp $");
25 #endif
28 * txtproto_print() derived from original code by Hannes Gredler
29 * (hannes@juniper.net):
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that: (1) source code
33 * distributions retain the above copyright notice and this paragraph
34 * in its entirety, and (2) distributions including binary code include
35 * the above copyright notice and this paragraph in its entirety in
36 * the documentation or other materials provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
38 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
39 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40 * FOR A PARTICULAR PURPOSE.
43 #define NETDISSECT_REWORKED
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
48 #include <tcpdump-stdinc.h>
50 #include <sys/stat.h>
52 #ifdef HAVE_FCNTL_H
53 #include <fcntl.h>
54 #endif
55 #include <stdio.h>
56 #include <stdarg.h>
57 #include <stdlib.h>
58 #include <string.h>
60 #include "interface.h"
63 * Print out a null-terminated filename (or other ascii string).
64 * If ep is NULL, assume no truncation check is needed.
65 * Return true if truncated.
67 int
68 fn_print(netdissect_options *ndo,
69 register const u_char *s, register const u_char *ep)
71 register int ret;
72 register u_char c;
74 ret = 1; /* assume truncated */
75 while (ep == NULL || s < ep) {
76 c = *s++;
77 if (c == '\0') {
78 ret = 0;
79 break;
81 if (!ND_ISASCII(c)) {
82 c = ND_TOASCII(c);
83 ND_PRINT((ndo, "M-"));
85 if (!ND_ISPRINT(c)) {
86 c ^= 0x40; /* DEL to ?, others to alpha */
87 ND_PRINT((ndo, "^"));
89 ND_PRINT((ndo, "%c", c));
91 return(ret);
95 * Print out a counted filename (or other ascii string).
96 * If ep is NULL, assume no truncation check is needed.
97 * Return true if truncated.
99 int
100 fn_printn(netdissect_options *ndo,
101 register const u_char *s, register u_int n, register const u_char *ep)
103 register u_char c;
105 while (n > 0 && (ep == NULL || s < ep)) {
106 n--;
107 c = *s++;
108 if (!ND_ISASCII(c)) {
109 c = ND_TOASCII(c);
110 ND_PRINT((ndo, "M-"));
112 if (!ND_ISPRINT(c)) {
113 c ^= 0x40; /* DEL to ?, others to alpha */
114 ND_PRINT((ndo, "^"));
116 ND_PRINT((ndo, "%c", c));
118 return (n == 0) ? 0 : 1;
122 * Print out a null-padded filename (or other ascii string).
123 * If ep is NULL, assume no truncation check is needed.
124 * Return true if truncated.
127 fn_printzp(netdissect_options *ndo,
128 register const u_char *s, register u_int n,
129 register const u_char *ep)
131 register int ret;
132 register u_char c;
134 ret = 1; /* assume truncated */
135 while (n > 0 && (ep == NULL || s < ep)) {
136 n--;
137 c = *s++;
138 if (c == '\0') {
139 ret = 0;
140 break;
142 if (!ND_ISASCII(c)) {
143 c = ND_TOASCII(c);
144 ND_PRINT((ndo, "M-"));
146 if (!ND_ISPRINT(c)) {
147 c ^= 0x40; /* DEL to ?, others to alpha */
148 ND_PRINT((ndo, "^"));
150 ND_PRINT((ndo, "%c", c));
152 return (n == 0) ? 0 : ret;
156 * Format the timestamp
158 static char *
159 ts_format(netdissect_options *ndo
160 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
162 #endif
163 , int sec, int usec)
165 static char buf[sizeof("00:00:00.000000000")];
166 const char *format;
168 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
169 switch (ndo->ndo_tstamp_precision) {
171 case PCAP_TSTAMP_PRECISION_MICRO:
172 format = "%02d:%02d:%02d.%06u";
173 break;
175 case PCAP_TSTAMP_PRECISION_NANO:
176 format = "%02d:%02d:%02d.%09u";
177 break;
179 default:
180 format = "%02d:%02d:%02d.{unknown precision}";
181 break;
183 #else
184 format = "%02d:%02d:%02d.%06u";
185 #endif
187 snprintf(buf, sizeof(buf), format,
188 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
190 return buf;
194 * Print the timestamp
196 void
197 ts_print(netdissect_options *ndo,
198 register const struct timeval *tvp)
200 register int s;
201 struct tm *tm;
202 time_t Time;
203 static unsigned b_sec;
204 static unsigned b_usec;
205 int d_usec;
206 int d_sec;
208 switch (ndo->ndo_tflag) {
210 case 0: /* Default */
211 s = (tvp->tv_sec + thiszone) % 86400;
212 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
213 break;
215 case 1: /* No time stamp */
216 break;
218 case 2: /* Unix timeval style */
219 ND_PRINT((ndo, "%u.%06u ",
220 (unsigned)tvp->tv_sec,
221 (unsigned)tvp->tv_usec));
222 break;
224 case 3: /* Microseconds since previous packet */
225 case 5: /* Microseconds since first packet */
226 if (b_sec == 0) {
227 /* init timestamp for first packet */
228 b_usec = tvp->tv_usec;
229 b_sec = tvp->tv_sec;
232 d_usec = tvp->tv_usec - b_usec;
233 d_sec = tvp->tv_sec - b_sec;
235 while (d_usec < 0) {
236 d_usec += 1000000;
237 d_sec--;
240 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
242 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
243 b_sec = tvp->tv_sec;
244 b_usec = tvp->tv_usec;
246 break;
248 case 4: /* Default + Date*/
249 s = (tvp->tv_sec + thiszone) % 86400;
250 Time = (tvp->tv_sec + thiszone) - s;
251 tm = gmtime (&Time);
252 if (!tm)
253 ND_PRINT((ndo, "Date fail "));
254 else
255 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
256 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
257 ts_format(ndo, s, tvp->tv_usec)));
258 break;
263 * Print a relative number of seconds (e.g. hold time, prune timer)
264 * in the form 5m1s. This does no truncation, so 32230861 seconds
265 * is represented as 1y1w1d1h1m1s.
267 void
268 relts_print(netdissect_options *ndo,
269 int secs)
271 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
272 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
273 const char **l = lengths;
274 const int *s = seconds;
276 if (secs == 0) {
277 ND_PRINT((ndo, "0s"));
278 return;
280 if (secs < 0) {
281 ND_PRINT((ndo, "-"));
282 secs = -secs;
284 while (secs > 0) {
285 if (secs >= *s) {
286 ND_PRINT((ndo, "%d%s", secs / *s, *l));
287 secs -= (secs / *s) * *s;
289 s++;
290 l++;
295 * this is a generic routine for printing unknown data;
296 * we pass on the linefeed plus indentation string to
297 * get a proper output - returns 0 on error
301 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
303 if (len < 0) {
304 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
305 ident));
306 return(0);
308 if (ndo->ndo_snapend - cp < len)
309 len = ndo->ndo_snapend - cp;
310 if (len < 0) {
311 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
312 ident));
313 return(0);
315 hex_print(ndo, ident,cp,len);
316 return(1); /* everything is ok */
320 * Convert a token value to a string; use "fmt" if not found.
322 const char *
323 tok2strbuf(register const struct tok *lp, register const char *fmt,
324 register u_int v, char *buf, size_t bufsize)
326 if (lp != NULL) {
327 while (lp->s != NULL) {
328 if (lp->v == v)
329 return (lp->s);
330 ++lp;
333 if (fmt == NULL)
334 fmt = "#%d";
336 (void)snprintf(buf, bufsize, fmt, v);
337 return (const char *)buf;
341 * Convert a token value to a string; use "fmt" if not found.
343 const char *
344 tok2str(register const struct tok *lp, register const char *fmt,
345 register int v)
347 static char buf[4][128];
348 static int idx = 0;
349 char *ret;
351 ret = buf[idx];
352 idx = (idx+1) & 3;
353 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
357 * Convert a bit token value to a string; use "fmt" if not found.
358 * this is useful for parsing bitfields, the output strings are seperated
359 * if the s field is positive.
361 static char *
362 bittok2str_internal(register const struct tok *lp, register const char *fmt,
363 register int v, register int sep)
365 static char buf[256]; /* our stringbuffer */
366 int buflen=0;
367 register int rotbit; /* this is the bit we rotate through all bitpositions */
368 register int tokval;
369 const char * sepstr = "";
371 while (lp != NULL && lp->s != NULL) {
372 tokval=lp->v; /* load our first value */
373 rotbit=1;
374 while (rotbit != 0) {
376 * lets AND the rotating bit with our token value
377 * and see if we have got a match
379 if (tokval == (v&rotbit)) {
380 /* ok we have found something */
381 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
382 sepstr, lp->s);
383 sepstr = sep ? ", " : "";
384 break;
386 rotbit=rotbit<<1; /* no match - lets shift and try again */
388 lp++;
391 if (buflen == 0)
392 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
393 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%d" : fmt, v);
394 return (buf);
398 * Convert a bit token value to a string; use "fmt" if not found.
399 * this is useful for parsing bitfields, the output strings are not seperated.
401 char *
402 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
403 register int v)
405 return (bittok2str_internal(lp, fmt, v, 0));
409 * Convert a bit token value to a string; use "fmt" if not found.
410 * this is useful for parsing bitfields, the output strings are comma seperated.
412 char *
413 bittok2str(register const struct tok *lp, register const char *fmt,
414 register int v)
416 return (bittok2str_internal(lp, fmt, v, 1));
420 * Convert a value to a string using an array; the macro
421 * tok2strary() in <interface.h> is the public interface to
422 * this function and ensures that the second argument is
423 * correct for bounds-checking.
425 const char *
426 tok2strary_internal(register const char **lp, int n, register const char *fmt,
427 register int v)
429 static char buf[128];
431 if (v >= 0 && v < n && lp[v] != NULL)
432 return lp[v];
433 if (fmt == NULL)
434 fmt = "#%d";
435 (void)snprintf(buf, sizeof(buf), fmt, v);
436 return (buf);
440 * Convert a 32-bit netmask to prefixlen if possible
441 * the function returns the prefix-len; if plen == -1
442 * then conversion was not possible;
446 mask2plen(uint32_t mask)
448 uint32_t bitmasks[33] = {
449 0x00000000,
450 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
451 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
452 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
453 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
454 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
455 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
456 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
457 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
459 int prefix_len = 32;
461 /* let's see if we can transform the mask into a prefixlen */
462 while (prefix_len >= 0) {
463 if (bitmasks[prefix_len] == mask)
464 break;
465 prefix_len--;
467 return (prefix_len);
470 #ifdef INET6
472 mask62plen(const u_char *mask)
474 u_char bitmasks[9] = {
475 0x00,
476 0x80, 0xc0, 0xe0, 0xf0,
477 0xf8, 0xfc, 0xfe, 0xff
479 int byte;
480 int cidr_len = 0;
482 for (byte = 0; byte < 16; byte++) {
483 u_int bits;
485 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
486 if (mask[byte] == bitmasks[bits]) {
487 cidr_len += bits;
488 break;
492 if (mask[byte] != 0xff)
493 break;
495 return (cidr_len);
497 #endif /* INET6 */
500 * Routine to print out information for text-based protocols such as FTP,
501 * HTTP, SMTP, RTSP, SIP, ....
503 #define MAX_TOKEN 128
506 * Fetch a token from a packet, starting at the specified index,
507 * and return the length of the token.
509 * Returns 0 on error; yes, this is indistinguishable from an empty
510 * token, but an "empty token" isn't a valid token - it just means
511 * either a space character at the beginning of the line (this
512 * includes a blank line) or no more tokens remaining on the line.
514 static int
515 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
516 u_char *tbuf, size_t tbuflen)
518 size_t toklen = 0;
520 for (; idx < len; idx++) {
521 if (!ND_TTEST(*(pptr + idx))) {
522 /* ran past end of captured data */
523 return (0);
525 if (!isascii(*(pptr + idx))) {
526 /* not an ASCII character */
527 return (0);
529 if (isspace(*(pptr + idx))) {
530 /* end of token */
531 break;
533 if (!isprint(*(pptr + idx))) {
534 /* not part of a command token or response code */
535 return (0);
537 if (toklen + 2 > tbuflen) {
538 /* no room for this character and terminating '\0' */
539 return (0);
541 tbuf[toklen] = *(pptr + idx);
542 toklen++;
544 if (toklen == 0) {
545 /* no token */
546 return (0);
548 tbuf[toklen] = '\0';
551 * Skip past any white space after the token, until we see
552 * an end-of-line (CR or LF).
554 for (; idx < len; idx++) {
555 if (!ND_TTEST(*(pptr + idx))) {
556 /* ran past end of captured data */
557 break;
559 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
560 /* end of line */
561 break;
563 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
564 /* not a printable ASCII character */
565 break;
567 if (!isspace(*(pptr + idx))) {
568 /* beginning of next token */
569 break;
572 return (idx);
576 * Scan a buffer looking for a line ending - LF or CR-LF.
577 * Return the index of the character after the line ending or 0 if
578 * we encounter a non-ASCII or non-printable character or don't find
579 * the line ending.
581 static u_int
582 print_txt_line(netdissect_options *ndo, const char *protoname,
583 const char *prefix, const u_char *pptr, u_int idx, u_int len)
585 u_int startidx;
586 u_int linelen;
588 startidx = idx;
589 while (idx < len) {
590 ND_TCHECK(*(pptr+idx));
591 if (*(pptr+idx) == '\n') {
593 * LF without CR; end of line.
594 * Skip the LF and print the line, with the
595 * exception of the LF.
597 linelen = idx - startidx;
598 idx++;
599 goto print;
600 } else if (*(pptr+idx) == '\r') {
601 /* CR - any LF? */
602 if ((idx+1) >= len) {
603 /* not in this packet */
604 return (0);
606 ND_TCHECK(*(pptr+idx+1));
607 if (*(pptr+idx+1) == '\n') {
609 * CR-LF; end of line.
610 * Skip the CR-LF and print the line, with
611 * the exception of the CR-LF.
613 linelen = idx - startidx;
614 idx += 2;
615 goto print;
619 * CR followed by something else; treat this
620 * as if it were binary data, and don't print
621 * it.
623 return (0);
624 } else if (!isascii(*(pptr+idx)) ||
625 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
627 * Not a printable ASCII character and not a tab;
628 * treat this as if it were binary data, and
629 * don't print it.
631 return (0);
633 idx++;
637 * All printable ASCII, but no line ending after that point
638 * in the buffer; treat this as if it were truncated.
640 trunc:
641 linelen = idx - startidx;
642 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
643 protoname));
644 return (0);
646 print:
647 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
648 return (idx);
651 void
652 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
653 const char *protoname, const char **cmds, u_int flags)
655 u_int idx, eol;
656 u_char token[MAX_TOKEN+1];
657 const char *cmd;
658 int is_reqresp = 0;
659 const char *pnp;
661 if (cmds != NULL) {
663 * This protocol has more than just request and
664 * response lines; see whether this looks like a
665 * request or response.
667 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
668 if (idx != 0) {
669 /* Is this a valid request name? */
670 while ((cmd = *cmds++) != NULL) {
671 if (strcasecmp((const char *)token, cmd) == 0) {
672 /* Yes. */
673 is_reqresp = 1;
674 break;
679 * No - is this a valid response code (3 digits)?
681 * Is this token the response code, or is the next
682 * token the response code?
684 if (flags & RESP_CODE_SECOND_TOKEN) {
686 * Next token - get it.
688 idx = fetch_token(ndo, pptr, idx, len, token,
689 sizeof(token));
691 if (idx != 0) {
692 if (isdigit(token[0]) && isdigit(token[1]) &&
693 isdigit(token[2]) && token[3] == '\0') {
694 /* Yes. */
695 is_reqresp = 1;
699 } else {
701 * This protocol has only request and response lines
702 * (e.g., FTP, where all the data goes over a
703 * different connection); assume the payload is
704 * a request or response.
706 is_reqresp = 1;
709 /* Capitalize the protocol name */
710 for (pnp = protoname; *pnp != '\0'; pnp++)
711 ND_PRINT((ndo, "%c", toupper((unsigned char)*pnp)));
713 if (is_reqresp) {
715 * In non-verbose mode, just print the protocol, followed
716 * by the first line as the request or response info.
718 * In verbose mode, print lines as text until we run out
719 * of characters or see something that's not a
720 * printable-ASCII line.
722 if (ndo->ndo_vflag) {
724 * We're going to print all the text lines in the
725 * request or response; just print the length
726 * on the first line of the output.
728 ND_PRINT((ndo, ", length: %u", len));
729 for (idx = 0;
730 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
731 idx = eol)
733 } else {
735 * Just print the first text line.
737 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
742 /* VARARGS */
743 void
744 error(const char *fmt, ...)
746 va_list ap;
748 (void)fprintf(stderr, "%s: ", program_name);
749 va_start(ap, fmt);
750 (void)vfprintf(stderr, fmt, ap);
751 va_end(ap);
752 if (*fmt) {
753 fmt += strlen(fmt);
754 if (fmt[-1] != '\n')
755 (void)fputc('\n', stderr);
757 exit(1);
758 /* NOTREACHED */
761 /* VARARGS */
762 void
763 warning(const char *fmt, ...)
765 va_list ap;
767 (void)fprintf(stderr, "%s: WARNING: ", program_name);
768 va_start(ap, fmt);
769 (void)vfprintf(stderr, fmt, ap);
770 va_end(ap);
771 if (*fmt) {
772 fmt += strlen(fmt);
773 if (fmt[-1] != '\n')
774 (void)fputc('\n', stderr);
779 * Copy arg vector into a new buffer, concatenating arguments with spaces.
781 char *
782 copy_argv(register char **argv)
784 register char **p;
785 register u_int len = 0;
786 char *buf;
787 char *src, *dst;
789 p = argv;
790 if (*p == 0)
791 return 0;
793 while (*p)
794 len += strlen(*p++) + 1;
796 buf = (char *)malloc(len);
797 if (buf == NULL)
798 error("copy_argv: malloc");
800 p = argv;
801 dst = buf;
802 while ((src = *p++) != NULL) {
803 while ((*dst++ = *src++) != '\0')
805 dst[-1] = ' ';
807 dst[-1] = '\0';
809 return buf;
813 * On Windows, we need to open the file in binary mode, so that
814 * we get all the bytes specified by the size we get from "fstat()".
815 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
816 * we define it as 0 if it's not defined, so it does nothing.
818 #ifndef O_BINARY
819 #define O_BINARY 0
820 #endif
822 char *
823 read_infile(char *fname)
825 register int i, fd, cc;
826 register char *cp;
827 struct stat buf;
829 fd = open(fname, O_RDONLY|O_BINARY);
830 if (fd < 0)
831 error("can't open %s: %s", fname, pcap_strerror(errno));
833 if (fstat(fd, &buf) < 0)
834 error("can't stat %s: %s", fname, pcap_strerror(errno));
836 cp = malloc((u_int)buf.st_size + 1);
837 if (cp == NULL)
838 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
839 fname, pcap_strerror(errno));
840 cc = read(fd, cp, (u_int)buf.st_size);
841 if (cc < 0)
842 error("read %s: %s", fname, pcap_strerror(errno));
843 if (cc != buf.st_size)
844 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
846 close(fd);
847 /* replace "# comment" with spaces */
848 for (i = 0; i < cc; i++) {
849 if (cp[i] == '#')
850 while (i < cc && cp[i] != '\n')
851 cp[i++] = ' ';
853 cp[cc] = '\0';
854 return (cp);
857 void
858 safeputs(netdissect_options *ndo,
859 const u_char *s, const u_int maxlen)
861 u_int idx = 0;
863 while (*s && idx < maxlen) {
864 safeputchar(ndo, *s);
865 idx++;
866 s++;
870 void
871 safeputchar(netdissect_options *ndo,
872 const u_char c)
874 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
877 #ifdef LBL_ALIGN
879 * Some compilers try to optimize memcpy(), using the alignment constraint
880 * on the argument pointer type. by using this function, we try to avoid the
881 * optimization.
883 void
884 unaligned_memcpy(void *p, const void *q, size_t l)
886 memcpy(p, q, l);
889 /* As with memcpy(), so with memcmp(). */
891 unaligned_memcmp(const void *p, const void *q, size_t l)
893 return (memcmp(p, q, l));
895 #endif