File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / arping / src / arping_test.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Mar 16 23:40:57 2021 UTC (3 years, 3 months ago) by misho
Branches: arping, MAIN
CVS tags: v2_21, HEAD
arping 2.21

    1: /* arping/src/arping_test.c
    2:  *
    3:  *  Copyright (C) 2015-2019 Thomas Habets <thomas@habets.se>
    4:  *
    5:  *  This program is free software; you can redistribute it and/or modify
    6:  *  it under the terms of the GNU General Public License as published by
    7:  *  the Free Software Foundation; either version 2 of the License, or
    8:  *  (at your option) any later version.
    9:  *
   10:  *  This program is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13:  *  GNU General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU General Public License along
   16:  *  with this program; if not, write to the Free Software Foundation, Inc.,
   17:  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   18:  */
   19: #include"config.h"
   20: #define _GNU_SOURCE
   21: #include<assert.h>
   22: #include<errno.h>
   23: #include<fcntl.h>
   24: #include<inttypes.h>
   25: #include<pthread.h>
   26: #include<stdio.h>
   27: #include<stdlib.h>
   28: 
   29: #include<check.h>
   30: #include<libnet.h>
   31: #include<pcap.h>
   32: 
   33: #include"arping.h"
   34: 
   35: #ifndef ETH_ALEN
   36: #define ETH_ALEN 6
   37: #endif
   38: 
   39: extern libnet_t* libnet;
   40: extern int mock_libnet_lo_ok;
   41: extern int mock_libnet_null_ok;
   42: 
   43: struct registered_test {
   44:         void* fn;
   45:         const char* name;
   46: };
   47: 
   48: static int numtests = 0;
   49: static struct registered_test test_registry[1024];
   50: 
   51: static int num_exit_tests = 0;
   52: static struct registered_test test_exit_registry[1024];
   53: 
   54: int get_mac_addr(const char *in, char *out);
   55: void strip_newline(char* s);
   56: 
   57: 
   58: #define MYTEST(a) static void a(int);__attribute__((constructor)) \
   59: static void cons_##a() {                           \
   60:                 test_registry[numtests].fn = a;    \
   61:                 test_registry[numtests].name = #a; \
   62:                 numtests++;                        \
   63: } START_TEST(a)
   64: 
   65: #define MY_EXIT_TEST(a) static void a(int);__attribute__((constructor)) \
   66: static void cons_##a() {                                      \
   67:                 test_exit_registry[num_exit_tests].fn = a;    \
   68:                 test_exit_registry[num_exit_tests].name = #a; \
   69:                 num_exit_tests++;                             \
   70: } START_TEST(a)
   71: 
   72: /**
   73:  *
   74:  */
   75: static void
   76: xclose(int* fd)
   77: {
   78:         if (0 > close(*fd)) {
   79:                 fprintf(stderr, "close(%d): %s", *fd, strerror(errno));
   80:                 *fd = -1;
   81:         }
   82: }
   83: 
   84: struct captured_output {
   85:         int saved_fd;  // Old fd, will be dup2()ed back in place when done.
   86:         int fno;       // Overridden fd (e.g. stdout or stderr).
   87:         int reader_fd; // Reader end of the pipe.
   88:         char* buffer;  // Output buffer.
   89:         size_t bufsize; // Buffer size.
   90:         pthread_t thread;  // Reader thread.
   91: };
   92: 
   93: /**
   94:  * Helper function for stdout/stderr catching.
   95:  *
   96:  * This is the main() for the thread that reads from the fake stdout pipe
   97:  * and writes into the buffer.
   98:  *
   99:  */
  100: static void*
  101: read_main(void* p)
  102: {
  103:         struct captured_output* out = p;
  104:         char *cur = out->buffer;
  105: 
  106:         for (;;) {
  107:                 ssize_t n;
  108:                 n = out->bufsize - (cur - out->buffer);
  109:                 assert(n > 0);
  110:                 n = read(out->reader_fd, cur, n);
  111:                 if (n > 0) {
  112:                         cur += n;
  113:                 }
  114:                 if (n == 0) {
  115:                         return NULL;
  116:                 }
  117:         }
  118: }
  119: 
  120: /**
  121:  * Helper function to capture stdout/stderr output.
  122:  *
  123:  * Args:
  124:  *   fd:  The fd to capture.
  125:  * Returns:
  126:  *   A structure to be used as a handle. Only thing caller should do with
  127:  *   this structure is call stop_capture(), read its .buffer member, and
  128:  *   uncapture().
  129:  */
  130: static struct captured_output*
  131: capture(int fd)
  132: {
  133:         struct captured_output* out;
  134: 
  135:         out = calloc(1, sizeof(struct captured_output));
  136:         fail_if(out == NULL);
  137: 
  138:         out->fno = fd;
  139:         out->saved_fd = dup(fd);
  140:         out->bufsize = 1024*100;
  141:         out->buffer = calloc(1, out->bufsize);
  142: 
  143:         fail_if(0 > out->saved_fd);
  144:         fail_if(out->buffer == NULL);
  145: 
  146:         // set up pipe
  147:         int fds[2];
  148:         fail_if(0 > pipe(fds));
  149:         fail_if(0 > dup2(fds[1], fd));
  150:         out->reader_fd = fds[0];
  151:         xclose(&fds[1]);
  152: 
  153:         fail_if(pthread_create(&out->thread, NULL, read_main, (void*)out));
  154:         return out;
  155: }
  156: 
  157: /**
  158:  * Helper function to capture stdout/stderr output.
  159:  *
  160:  * Stop capture, so that .buffer becomes readable.
  161:  */
  162: static void
  163: stop_capture(struct captured_output* out)
  164: {
  165:         fail_if(0 > dup2(out->saved_fd, out->fno));
  166:         xclose(&out->saved_fd);
  167:         fail_if(pthread_join(out->thread, NULL));
  168:         xclose(&out->reader_fd);
  169: }
  170: 
  171: /**
  172:  * Helper function to capture stdout/stderr output.
  173:  *
  174:  * Deallocate buffer. stop_capture() must be called before uncapture().
  175:  */
  176: static void
  177: uncapture(struct captured_output* out)
  178: {
  179:         free(out->buffer);
  180:         out->buffer = NULL;
  181:         free(out);
  182: }
  183: 
  184: static uint8_t*
  185: mkpacket(struct pcap_pkthdr* pkthdr)
  186: {
  187:         uint8_t* packet = calloc(1, 1500);
  188:         fail_if(packet == NULL);
  189: 
  190:         struct libnet_802_3_hdr* heth;
  191:         struct libnet_arp_hdr* harp;
  192: 
  193:         // Set up ethernet header
  194:         heth = (void*)packet;
  195:         memcpy(heth->_802_3_dhost, "\x11\x22\x33\x44\x55\x66", 6);
  196:         memcpy(heth->_802_3_shost, "\x77\x88\x99\xaa\xbb\xcc", 6);
  197:         heth->_802_3_len = 0;  // FIXME: is this correct?
  198: 
  199:         // Set up ARP header.
  200:         harp = (void*)((char*)heth + LIBNET_ETH_H);
  201:         harp->ar_hln = 6;
  202:         harp->ar_pln = 4;
  203:         harp->ar_hrd = htons(ARPHRD_ETHER);
  204:         harp->ar_op = htons(ARPOP_REPLY);
  205:         harp->ar_pro = htons(ETHERTYPE_IP);
  206: 
  207:         memcpy((char*)harp + LIBNET_ARP_H, heth->_802_3_shost, 6);
  208:         memcpy((char*)harp + LIBNET_ARP_H + harp->ar_hln, &dstip, 4);
  209: 
  210:         memcpy((char*)harp + LIBNET_ARP_H
  211:                + harp->ar_hln
  212:                + harp->ar_pln, heth->_802_3_dhost, 6);
  213:         memcpy((char*)harp + LIBNET_ARP_H
  214:                + harp->ar_hln
  215:                + harp->ar_pln
  216:                + harp->ar_hln, &srcip, 4);
  217: 
  218:         pkthdr->ts.tv_sec = time(NULL);
  219:         pkthdr->ts.tv_usec = 0;
  220:         pkthdr->len = 60;
  221:         pkthdr->caplen = 60;
  222: 
  223:         return packet;
  224: }
  225: 
  226: static void
  227: dump_packet(uint8_t* packet, int len)
  228: {
  229:         int c;
  230:         for (c = 0; c < len; c++) {
  231:                 fprintf(stderr, "0x%.2x, ", (int)packet[c]);
  232:                 if (!((c+1) % 10)) {
  233:                         fprintf(stderr, "\n");
  234:                 }
  235:         }
  236:         fprintf(stderr, "\n");
  237: }
  238: 
  239: MYTEST(test_mkpacket)
  240: {
  241:         uint8_t correct_packet[] = {
  242:                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
  243:                 0xbb, 0xcc, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,
  244:                 0x00, 0x02, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0x12, 0x34,
  245:                 0x56, 0x78, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x87, 0x65,
  246:                 0x43, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  247:                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  248:         };
  249:         struct pcap_pkthdr pkthdr;
  250:         dstip = htonl(0x12345678);
  251:         srcip = htonl(0x87654321);
  252: 
  253:         uint8_t* packet = mkpacket(&pkthdr);
  254:         fail_if(packet == NULL);
  255:         fail_unless(pkthdr.caplen == 60);
  256:         if (memcmp(packet, correct_packet, pkthdr.caplen)) {
  257:                 dump_packet(packet, pkthdr.caplen);
  258:         }
  259:         fail_unless(!memcmp(packet, correct_packet, pkthdr.caplen));
  260: } END_TEST
  261: 
  262: 
  263: // Received uninteresting packet, should not record anything.
  264: MYTEST(pingip_uninteresting_packet)
  265: {
  266:         struct pcap_pkthdr pkthdr;
  267:         uint8_t* packet;
  268:         struct libnet_802_3_hdr* heth;
  269:         struct libnet_arp_hdr* harp;
  270: 
  271:         int prev_numrecvd = numrecvd;
  272:         struct captured_output* sout;
  273: 
  274:         // Completely broken packet.
  275:         packet = calloc(1, 1500);
  276:         sout = capture(1);
  277:         pingip_recv(NULL, &pkthdr, packet);
  278:         stop_capture(sout);
  279:         fail_unless(strlen(sout->buffer) == 0);
  280:         fail_unless(prev_numrecvd == numrecvd);
  281:         uncapture(sout);
  282:         free(packet);
  283: 
  284:         // Not ETHERTYPE_IP.
  285:         packet = mkpacket(&pkthdr);
  286:         harp = (void*)((char*)packet + LIBNET_ETH_H);
  287:         harp->ar_pro = 0;
  288:         sout = capture(1);
  289:         pingip_recv(NULL, &pkthdr, packet);
  290:         stop_capture(sout);
  291:         fail_unless(prev_numrecvd == numrecvd);
  292:         fail_unless(strlen(sout->buffer) == 0);
  293:         uncapture(sout);
  294:         free(packet);
  295: 
  296:         // Not ARPHRD_ETHER
  297:         packet = mkpacket(&pkthdr);
  298:         harp = (void*)((char*)packet + LIBNET_ETH_H);
  299:         harp->ar_hrd = 0;
  300:         sout = capture(1);
  301:         pingip_recv(NULL, &pkthdr, packet);
  302:         stop_capture(sout);
  303:         fail_unless(prev_numrecvd == numrecvd);
  304:         fail_unless(strlen(sout->buffer) == 0);
  305:         uncapture(sout);
  306:         free(packet);
  307: 
  308:         // Wrong dstip
  309:         if (0) {
  310:                 uint32_t wrongip = 123;
  311:                 packet = mkpacket(&pkthdr);
  312:                 harp = (void*)((char*)packet + LIBNET_ETH_H);
  313:                 memcpy((char*)harp + harp->ar_hln + LIBNET_ARP_H, &wrongip, 4);
  314:                 sout = capture(1);
  315:                 pingip_recv(NULL, &pkthdr, packet);
  316:                 stop_capture(sout);
  317:                 fail_unless(prev_numrecvd == numrecvd);
  318:                 fail_unless(strlen(sout->buffer) == 0);
  319:                 uncapture(sout);
  320:                 free(packet);
  321:         }
  322: 
  323:         // Short packet.
  324:         packet = mkpacket(&pkthdr);
  325:         pkthdr.caplen = pkthdr.len = 41;
  326:         sout = capture(1);
  327:         pingip_recv(NULL, &pkthdr, packet);
  328:         stop_capture(sout);
  329:         fail_unless(prev_numrecvd == numrecvd);
  330:         fail_unless(strlen(sout->buffer) == 0);
  331:         uncapture(sout);
  332:         free(packet);
  333: 
  334:         // Short captured packet.
  335:         packet = mkpacket(&pkthdr);
  336:         pkthdr.caplen = 41;
  337:         sout = capture(1);
  338:         pingip_recv(NULL, &pkthdr, packet);
  339:         stop_capture(sout);
  340:         fail_unless(prev_numrecvd == numrecvd);
  341:         fail_unless(strlen(sout->buffer) == 0);
  342:         uncapture(sout);
  343:         free(packet);
  344: 
  345:         // Wrong length of hardware address.
  346:         {
  347:                 uint8_t packet[] = {
  348:                         0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // dst
  349:                         0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // src
  350:                         0x00, 0x00, // type
  351:                         0x00, 0x01, // hardware
  352:                         0x08, 0x00, // protocol
  353:                         0x04, 0x04, // lengths (for this test length is wrong)
  354:                         0x00, 0x02, // operator
  355: 
  356:                         0x77, 0x88, 0x99, 0xaa, // sender (wrong length for test)
  357:                         0x12, 0x34, 0x56, 0x78, // sender protocol address
  358: 
  359:                         0x11, 0x22, 0x33, 0x44, // receiver (wrong length for test)
  360:                         0x87, 0x65, 0x43, 0x21, // receiver protocol address
  361: 
  362:                         0x00, 0x00, 0x00, 0x00,
  363:                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  364:                         0x00, 0x00, 0x00, 0x00,
  365:                         0x00, 0x00, 0x00, 0x00,
  366:                         0x00, 0x00, 0x00, 0x00,
  367:                         0x6f, 0xa8, 0x58, 0x63,
  368:         };
  369:                 pkthdr.len = 60;
  370:                 pkthdr.caplen = 60;
  371:                 sout = capture(1);
  372:                 pingip_recv(NULL, &pkthdr, packet);
  373:                 stop_capture(sout);
  374:                 fail_unless(strlen(sout->buffer) == 0, sout->buffer);
  375:                 fail_unless(prev_numrecvd == numrecvd);
  376:                 uncapture(sout);
  377:         }
  378: 
  379:         // Wrong length of protocol address.
  380:         packet = mkpacket(&pkthdr);
  381:         ((struct libnet_arp_hdr*)((char*)packet + LIBNET_ETH_H))->ar_pln = 6;
  382:         sout = capture(1);
  383:         pingip_recv(NULL, &pkthdr, packet);
  384:         stop_capture(sout);
  385:         fail_unless(prev_numrecvd == numrecvd);
  386:         fail_unless(strlen(sout->buffer) == 0);
  387:         uncapture(sout);
  388:         free(packet);
  389: } END_TEST
  390: 
  391: // Received reply that actually matches. Things should happen.
  392: MYTEST(pingip_interesting_packet)
  393: {
  394:         struct pcap_pkthdr pkthdr;
  395:         extern uint8_t srcmac[ETH_ALEN];
  396:         memcpy(srcmac, "\x11\x22\x33\x44\x55\x66", ETH_ALEN);
  397:         uint8_t packet[] = {
  398:                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // dst
  399:                 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // src
  400:                 0x00, 0x00, // type
  401:                 0x00, 0x01, // hardware
  402:                 0x08, 0x00, // protocol
  403:                 0x06, 0x04, // lengths
  404:                 0x00, 0x02, // operator
  405: 
  406:                 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // sender
  407:                 0x12, 0x34, 0x56, 0x78, // sender protocol address
  408: 
  409:                 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // receiver
  410:                 0x87, 0x65, 0x43, 0x21, // receiver protocol address
  411: 
  412:                 0x00, 0x00, 0x00, 0x00,
  413:                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  414:                 0x6f, 0xa8, 0x58, 0x63,
  415:         };
  416:         numrecvd = 0;
  417:         int prev_numrecvd = numrecvd;
  418: 
  419:         dstip = htonl(0x12345678);
  420: 
  421:         pkthdr.ts.tv_sec = time(NULL);
  422:         pkthdr.ts.tv_usec = 0;
  423:         pkthdr.len = 60;
  424:         pkthdr.caplen = 60;
  425: 
  426:         struct captured_output *sout;
  427: 
  428:         // First ping.
  429:         const char* correct0 =
  430:                         "60 bytes from 77:88:99:aa:bb:cc (18.52.86.120): "
  431:                         "index=0 time=";
  432:         sout = capture(1);
  433:         pingip_recv(NULL, &pkthdr, packet);
  434:         stop_capture(sout);
  435: 
  436:         char* emsg = NULL;
  437:         fail_unless(0 < asprintf(&emsg, "Captured: <%s> (%zd), want   <%s> %zd\n",
  438:                          sout->buffer, strlen(sout->buffer),
  439:                                  correct0, strlen(correct0)));
  440:         fail_unless(!strncmp(sout->buffer, correct0, strlen(correct0)), emsg);
  441:         uncapture(sout);
  442:         free(emsg);
  443: 
  444:         fail_unless(numrecvd == prev_numrecvd + 1,
  445:                     "numrecvd not incremented");
  446: 
  447:         pingip_recv(NULL, &pkthdr, packet);
  448:         fail_unless(numrecvd == prev_numrecvd + 2,
  449:                     "numrecvd not incremented second time");
  450: } END_TEST
  451: 
  452: MYTEST(strip_newline_test)
  453: {
  454:         const char *tests[][2] = {
  455:                 {"", ""},
  456:                 {"\n", ""},
  457:                 {"\n\n\n", ""},
  458:                 {"foo", "foo"},
  459:                 {"foo\n", "foo"},
  460:                 {"foo\n\n\n", "foo"},
  461:                 {NULL, NULL},
  462:         };
  463:         int c;
  464:         for (c = 0; tests[c][0]; c++){
  465:                 char buf[128];
  466:                 strcpy(buf, tests[c][0]);
  467:                 strip_newline(buf);
  468:                 fail_unless(!strcmp(buf, tests[c][1]));
  469:         }
  470: } END_TEST
  471: 
  472: MYTEST(get_mac_addr_success)
  473: {
  474:         const char *tests[][2] = {
  475:                 // Null.
  476:                 {"0000.0000.0000", "\x00\x00\x00\x00\x00\x00"},
  477:                 {"00:00:00:00:00:00", "\x00\x00\x00\x00\x00\x00"},
  478:                 {"00-00-00-00-00-00", "\x00\x00\x00\x00\x00\x00"},
  479: 
  480:                 // Broadcast.
  481:                 {"FFFF.FFFF.FFFF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
  482:                 {"FF:FF:FF:FF:FF:FF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
  483:                 {"FF-FF-FF-FF-FF-FF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
  484: 
  485:                 // Normal looking.
  486:                 {"1122.3344.5566", "\x11\x22\x33\x44\x55\x66"},
  487:                 {"11:22:33:44:55:66", "\x11\x22\x33\x44\x55\x66"},
  488:                 {"11-22-33-44-55-66", "\x11\x22\x33\x44\x55\x66"},
  489: 
  490:                 // Has some zeroes.
  491:                 {"1100.0000.5566", "\x11\x00\x00\x00\x55\x66"},
  492:                 {"11:00:00:00:55:66", "\x11\x00\x00\x00\x55\x66"},
  493:                 {"11-00-00-00-55-66", "\x11\x00\x00\x00\x55\x66"},
  494:                 {NULL, NULL},
  495:         };
  496:         int c;
  497:         for (c = 0; tests[c][0]; c++){
  498:                 char buf[6];
  499:                 fail_unless(get_mac_addr(tests[c][0], buf));
  500:                 fail_unless(!memcmp(buf, tests[c][1], 6));
  501:         }
  502: } END_TEST
  503: 
  504: MYTEST(get_mac_addr_fail)
  505: {
  506:         const char *tests[] = {
  507:                 "",
  508:                 "blaha",
  509:                 "11:22:33:44:55",
  510:                 "11:22:33:44:55:zz",
  511:                 NULL,
  512:         };
  513:         int c;
  514:         for (c = 0; tests[c]; c++){
  515:                 char buf[6];
  516:                 fail_if(get_mac_addr(tests[c], buf));
  517:         }
  518: } END_TEST
  519: 
  520: MY_EXIT_TEST(libnet_init_bad_nolo)
  521: {
  522:         // It'll only try lo if named interface fails.
  523:         // So by accepting lo, we make sure it doesn't try lo.
  524:         mock_libnet_lo_ok = 1;
  525:         do_libnet_init("bad", 0);
  526: } END_TEST
  527: 
  528: MY_EXIT_TEST(libnet_init_null_nolo_nonull)
  529: {
  530:         mock_libnet_lo_ok = 0;
  531:         mock_libnet_null_ok = 0;
  532:         do_libnet_init(NULL, 0);
  533: } END_TEST
  534: 
  535: MYTEST(libnet_init_good)
  536: {
  537:         mock_libnet_lo_ok = 0; // Don't even try falling back to lo.
  538:         do_libnet_init("good", 0);
  539:         fail_if(libnet == NULL);
  540: } END_TEST
  541: 
  542: MYTEST(libnet_init_null_nolo)
  543: {
  544:         mock_libnet_lo_ok = 0;
  545:         mock_libnet_null_ok = 1;
  546:         do_libnet_init(NULL, 0);
  547:         fail_if(libnet == NULL);
  548: } END_TEST
  549: 
  550: static Suite*
  551: arping_suite(void)
  552: {
  553:         int c;
  554:         Suite* s = suite_create("Arping");
  555: 
  556:         //tcase_add_checked_fixture (tc_core, setup, teardown);
  557:         for (c = 0; c < numtests; c++) {
  558:                 TCase *tc_core = tcase_create(test_registry[c].name);
  559:                 tcase_add_test(tc_core, test_registry[c].fn);
  560:                 suite_add_tcase(s, tc_core);
  561:         }
  562:         for (c = 0; c < num_exit_tests; c++) {
  563:                 TCase *tc_core = tcase_create(test_exit_registry[c].name);
  564:                 tcase_add_exit_test(tc_core, test_exit_registry[c].fn, 1);
  565:                 suite_add_tcase(s, tc_core);
  566:         }
  567:         return s;
  568: }
  569: 
  570: int
  571: main()
  572: {
  573:         int number_failed;
  574:         Suite *s = arping_suite();
  575:         SRunner *sr = srunner_create (s);
  576:         srunner_run_all (sr, CK_NORMAL);
  577:         number_failed = srunner_ntests_failed (sr);
  578:         srunner_free (sr);
  579:         return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  580: }
  581: /* ---- Emacs Variables ----
  582:  * Local Variables:
  583:  * c-basic-offset: 8
  584:  * indent-tabs-mode: nil
  585:  * End:
  586:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>