"Fossies" - the Fresh Open Source Software Archive

Member "vpnc-0.5.3/sysdep.c" (19 Nov 2008, 17084 Bytes) of package /linux/privat/old/vpnc-0.5.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sysdep.c" see the Fossies "Dox" file reference documentation.

    1 /* IPSec VPN client compatible with Cisco equipment.
    2     Copyright (C) 2007      Maurice Massar
    3     Copyright (C) 2007      Paolo Zarpellon <paolo.zarpellon@gmail.com> (Cygwin support)
    4 
    5     based on VTun - Virtual Tunnel over TCP/IP network.
    6     Copyright (C) 1998-2000  Maxim Krasnyansky <max_mk@yahoo.com>
    7     VTun has been derived from VPPP package by Maxim Krasnyansky. 
    8 
    9     This program is free software; you can redistribute it and/or modify
   10     it under the terms of the GNU General Public License as published by
   11     the Free Software Foundation; either version 2 of the License, or
   12     (at your option) any later version.
   13 
   14     This program is distributed in the hope that it will be useful,
   15     but WITHOUT ANY WARRANTY; without even the implied warranty of
   16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17     GNU General Public License for more details.
   18  */
   19 
   20 #include <unistd.h>
   21 #include <fcntl.h>
   22 #include <stdlib.h>
   23 #include <stdio.h>
   24 #include <string.h>
   25 #include <syslog.h>
   26 #include <sys/ioctl.h>
   27 #include <errno.h>
   28 
   29 #include <sys/socket.h>
   30 #include <net/if.h>
   31 
   32 #ifdef __sun__
   33 #include <ctype.h>
   34 #include <sys/time.h>
   35 #include <sys/wait.h>
   36 #include <sys/types.h>
   37 #include <sys/socket.h>
   38 #include <sys/sockio.h>
   39 #include <signal.h>
   40 #include <stropts.h>
   41 #include <netinet/in.h>
   42 #include <netinet/in_systm.h>
   43 #include <netinet/ip.h>
   44 #include <netinet/tcp.h>
   45 #endif
   46 
   47 #if defined(__CYGWIN__)
   48 #include <io.h>
   49 #include <w32api/windef.h>
   50 #include <w32api/winbase.h>
   51 #include <w32api/winnt.h>
   52 #include <w32api/winioctl.h>
   53 #include <w32api/iphlpapi.h>
   54 #include <w32api/iptypes.h>
   55 #include <w32api/winreg.h>
   56 #include <sys/cygwin.h>
   57 #endif
   58 
   59 #if defined(__DragonFly__)
   60 #include <net/tun/if_tun.h>
   61 #elif defined(__linux__)
   62 #include <linux/if_tun.h>
   63 #elif defined(__APPLE__)
   64 /* no header for tun */
   65 #elif defined(__CYGWIN__)
   66 #include "tap-win32.h"
   67 #else
   68 #include <net/if_tun.h>
   69 #endif
   70 
   71 #include "sysdep.h"
   72 
   73 #if !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF) || !defined(HAVE_ERROR)
   74 #include <stdarg.h>
   75 #endif
   76 
   77 #if defined(__sun__)
   78 extern char **environ;
   79 static int ip_fd = -1, muxid;
   80 #endif
   81 
   82 #if defined(__CYGWIN__)
   83 /*
   84  * Overlapped structures for asynchronous read and write
   85  */
   86 static OVERLAPPED overlap_read, overlap_write;
   87 
   88 typedef enum {
   89     SEARCH_IF_GUID_FROM_NAME,
   90     SEARCH_IF_NAME_FROM_GUID
   91 } search_if_en;
   92 #endif
   93 
   94 /* 
   95  * Allocate TUN/TAP device, returns opened fd. 
   96  * Stores dev name in the first arg(must be large enough).
   97  */
   98 #if defined(__sun__)
   99 int tun_open(char *dev, enum if_mode_enum mode)
  100 {
  101     int tun_fd, if_fd, ppa = -1;
  102     struct ifreq ifr;
  103     char *ptr;
  104 
  105     if (*dev) {
  106         ptr = dev;
  107         while (*ptr && !isdigit((int)*ptr))
  108             ptr++;
  109         ppa = atoi(ptr);
  110     }
  111 
  112     if ((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
  113         syslog(LOG_ERR, "Can't open /dev/ip");
  114         return -1;
  115     }
  116 
  117     if ((tun_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
  118         syslog(LOG_ERR, "Can't open /dev/tun");
  119         return -1;
  120     }
  121 
  122     /* Assign a new PPA and get its unit number. */
  123     if ((ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0) {
  124         syslog(LOG_ERR, "Can't assign new interface");
  125         return -1;
  126     }
  127 
  128     if ((if_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
  129         syslog(LOG_ERR, "Can't open /dev/tun (2)");
  130         return -1;
  131     }
  132     if (ioctl(if_fd, I_PUSH, "ip") < 0) {
  133         syslog(LOG_ERR, "Can't push IP module");
  134         return -1;
  135     }
  136 
  137     /* Assign ppa according to the unit number returned by tun device */
  138     if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0 && errno != EEXIST) {
  139         syslog(LOG_ERR, "Can't set PPA %d", ppa);
  140         return -1;
  141     }
  142     if ((muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
  143         syslog(LOG_ERR, "Can't link TUN device to IP");
  144         return -1;
  145     }
  146     close(if_fd);
  147 
  148     snprintf(dev, IFNAMSIZ, "%s%d", ((mode == IF_MODE_TUN) ? "tun" : "tap"), ppa);
  149 
  150     memset(&ifr, 0, sizeof(ifr));
  151     strcpy(ifr.ifr_name, dev);
  152     ifr.ifr_ip_muxid = muxid;
  153 
  154     if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
  155         ioctl(ip_fd, I_PUNLINK, muxid);
  156         syslog(LOG_ERR, "Can't set multiplexor id");
  157         return -1;
  158     }
  159 
  160     return tun_fd;
  161 }
  162 #elif defined(__CYGWIN__)
  163 /*
  164  * Get interface guid/name from registry
  165  */
  166 static char *search_if(char *value, char *key, search_if_en type)
  167 {
  168     int i = 0;
  169     LONG status;
  170     DWORD len;
  171     HKEY net_conn_key;
  172     BOOL found = FALSE;
  173     char guid[256];
  174     char ifname[256];
  175     char conn_string[512];
  176     HKEY conn_key;
  177     DWORD value_type;
  178     
  179     if (!value || !key) {
  180         return NULL;
  181     }
  182     
  183     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  184         NETWORK_CONNECTIONS_KEY,
  185         0,
  186         KEY_READ,
  187         &net_conn_key);
  188     
  189     if (status != ERROR_SUCCESS) {
  190         printf("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY);
  191         return NULL;
  192     }
  193     
  194     while (!found) {
  195         len = sizeof(guid);
  196         status = RegEnumKeyEx(net_conn_key, i++, guid, &len,
  197             NULL, NULL, NULL, NULL);
  198         if (status == ERROR_NO_MORE_ITEMS) {
  199             break;
  200         } else if (status != ERROR_SUCCESS) {
  201             continue;
  202         }
  203         snprintf(conn_string, sizeof(conn_string),
  204             "%s\\%s\\Connection",
  205             NETWORK_CONNECTIONS_KEY, guid);
  206         status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  207             conn_string,
  208             0,
  209             KEY_READ,
  210             &conn_key);
  211         if (status != ERROR_SUCCESS) {
  212             continue;
  213         }
  214         len = sizeof(ifname);
  215         status = RegQueryValueEx(conn_key, "Name", NULL,
  216             &value_type, ifname, &len);
  217         if (status != ERROR_SUCCESS || value_type != REG_SZ) {
  218             RegCloseKey(conn_key);
  219             continue;
  220         }
  221         
  222         switch (type) {
  223         case SEARCH_IF_GUID_FROM_NAME:
  224             if (!strcmp(key, ifname)) {
  225                 strcpy(value, guid);
  226                 found = TRUE;
  227             }
  228             break;
  229         case SEARCH_IF_NAME_FROM_GUID:
  230             if (!strcmp(key, guid)) {
  231                 strcpy(value, ifname);
  232                 found = TRUE;
  233             }
  234             break;
  235         default:
  236             break;
  237         }
  238         RegCloseKey(conn_key);
  239     }
  240     RegCloseKey(net_conn_key);
  241     
  242     if (found) {
  243         return value;
  244     }
  245     
  246     return NULL;
  247 }
  248 
  249 /*
  250  * Open the TUN/TAP device with the provided guid
  251  */
  252 static int open_tun_device (char *guid, char *dev, enum if_mode_enum mode)
  253 {
  254     HANDLE handle;
  255     ULONG len, status, info[3];
  256     char device_path[512];
  257     
  258     printf("Device: %s\n", dev);
  259     
  260     if (mode == IF_MODE_TUN) {
  261         printf("TUN mode is not supported\n");
  262         return -1;
  263     }
  264     
  265     /*
  266      * Let's try to open Windows TAP-Win32 adapter
  267      */
  268     snprintf(device_path, sizeof(device_path), "%s%s%s",
  269         USERMODEDEVICEDIR, guid, TAPSUFFIX);
  270     
  271     handle = CreateFile(device_path,
  272         GENERIC_READ | GENERIC_WRITE,
  273         0, /* Don't let other processes share or open
  274         the resource until the handle's been closed */
  275         0,
  276         OPEN_EXISTING,
  277         FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  278         0);
  279     
  280     if (handle == INVALID_HANDLE_VALUE) {
  281         return -1;
  282     }
  283     
  284     /*
  285      * get driver version info
  286      */
  287     memset(info, 0, sizeof(info));
  288     if (DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
  289         &info, sizeof(info),
  290         &info, sizeof(info), &len, NULL)) {
  291         printf("TAP-Win32 Driver Version %d.%d %s\n",
  292         (int) info[0],
  293         (int) info[1],
  294         (info[2] ? "(DEBUG)" : ""));
  295     }
  296     
  297     /*
  298      * Set driver media status to 'connected'
  299      */
  300     status = TRUE;
  301     if (!DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
  302         &status, sizeof(status),
  303         &status, sizeof(status), &len, NULL)) {
  304         printf("WARNING: The TAP-Win32 driver rejected a "
  305         "TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.\n");
  306     }
  307     
  308     /*
  309      * Initialize overlapped structures
  310      */
  311     overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  312     overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  313     if (!overlap_read.hEvent || !overlap_write.hEvent) {
  314         return -1;
  315     }
  316     
  317     /*
  318      * Return fd
  319      */
  320     return cygwin_attach_handle_to_fd(NULL, -1, handle, 1, GENERIC_READ | GENERIC_WRITE);
  321 }
  322 
  323 /*
  324  * Allocate TUN device, returns opened fd.
  325  * Stores dev name in the first arg (must be large enough).
  326  */
  327 int tun_open (char *dev, enum if_mode_enum mode)
  328 {
  329     int fd = -1;
  330     HKEY unit_key;
  331     char guid[256];
  332     char comp_id[256];
  333     char enum_name[256];
  334     char unit_string[512];
  335     BOOL found = FALSE;
  336     HKEY adapter_key;
  337     DWORD value_type;
  338     LONG status;
  339     DWORD len;
  340     
  341     if (!dev) {
  342         return -1;
  343     }
  344     
  345     /*
  346      * Device name has been provided. Open such device.
  347      */
  348     if (*dev != '\0') {
  349         if (!search_if(guid, dev, SEARCH_IF_GUID_FROM_NAME)) {
  350             return -1;
  351         }
  352         return open_tun_device(guid, dev, mode);
  353     }
  354     
  355     /*
  356      * Device name has non been specified. Look for one available!
  357      */
  358     int i = 0;
  359     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  360         ADAPTER_KEY,
  361         0,
  362         KEY_READ,
  363         &adapter_key);
  364     if (status != ERROR_SUCCESS) {
  365         printf("Error opening registry key: %s", ADAPTER_KEY);
  366         return -1;
  367     }
  368     
  369     while (!found) {
  370         len = sizeof(enum_name);
  371         status = RegEnumKeyEx(adapter_key, i++,
  372             enum_name, &len,
  373             NULL, NULL, NULL, NULL);
  374         if (status == ERROR_NO_MORE_ITEMS) {
  375             break;
  376         } else if (status != ERROR_SUCCESS) {
  377             continue;
  378         }
  379         snprintf(unit_string, sizeof(unit_string), "%s\\%s",
  380             ADAPTER_KEY, enum_name);
  381         status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  382             unit_string,
  383             0,
  384             KEY_READ,
  385             &unit_key);
  386         if (status != ERROR_SUCCESS) {
  387             continue;
  388         }
  389         len = sizeof(comp_id);
  390         status = RegQueryValueEx(unit_key,
  391             "ComponentId", NULL,
  392             &value_type, comp_id, &len);
  393         if (status != ERROR_SUCCESS || value_type != REG_SZ) {
  394             RegCloseKey(unit_key);
  395             continue;
  396         }
  397         len = sizeof(guid);
  398         status = RegQueryValueEx(unit_key,
  399             "NetCfgInstanceId", NULL,
  400             &value_type, guid, &len);
  401         if (status != ERROR_SUCCESS || value_type != REG_SZ) {
  402             RegCloseKey(unit_key);
  403             continue;
  404         }
  405 
  406         int j = 0;
  407         while (TAP_COMPONENT_ID[j]) {
  408             if (!strcmp(comp_id, TAP_COMPONENT_ID[j])) {
  409                 break;
  410             }
  411             j++;
  412         }
  413         if (!TAP_COMPONENT_ID[j]) {
  414             RegCloseKey(unit_key);
  415             continue;
  416         }
  417         
  418         /*
  419          * Let's try to open this device
  420          */
  421         search_if(dev, guid, SEARCH_IF_NAME_FROM_GUID);
  422         fd = open_tun_device(guid, dev, mode);
  423         if (fd != -1) {
  424             found = TRUE;
  425         }
  426         
  427         RegCloseKey(unit_key);
  428     }
  429     RegCloseKey(adapter_key);
  430     
  431     return fd;
  432 }
  433 #elif defined(IFF_TUN)
  434 int tun_open(char *dev, enum if_mode_enum mode)
  435 {
  436     struct ifreq ifr;
  437     int fd, err;
  438 
  439     if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
  440         error(0, errno,
  441             "can't open /dev/net/tun, check that it is either device char 10 200 or (with DevFS) a symlink to ../misc/net/tun (not misc/net/tun)");
  442         return -1;
  443     }
  444 
  445     memset(&ifr, 0, sizeof(ifr));
  446     ifr.ifr_flags = ((mode == IF_MODE_TUN) ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
  447     if (*dev)
  448         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
  449 
  450     if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
  451         close(fd);
  452         return err;
  453     }
  454     strcpy(dev, ifr.ifr_name);
  455     return fd;
  456 }
  457 #else
  458 int tun_open(char *dev, enum if_mode_enum mode)
  459 {
  460     char tunname[14];
  461     int i, fd;
  462 
  463     if (*dev) {
  464         if (strncmp(dev, ((mode == IF_MODE_TUN) ? "tun" : "tap"), 3))
  465             error(1, 0,
  466                 "error: arbitrary naming tunnel interface is not supported in this version\n");
  467         snprintf(tunname, sizeof(tunname), "/dev/%s", dev);
  468         return open(tunname, O_RDWR);
  469     }
  470 
  471     for (i = 0; i < 255; i++) {
  472         snprintf(tunname, sizeof(tunname), "/dev/%s%d",
  473             ((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
  474         /* Open device */
  475         if ((fd = open(tunname, O_RDWR)) > 0) {
  476             snprintf(dev, IFNAMSIZ, "%s%d",
  477                 ((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
  478             return fd;
  479         }
  480     }
  481     return -1;
  482 }
  483 #endif /* New driver support */
  484 
  485 /* 
  486  * Close TUN device. 
  487  */
  488 #if defined(__sun__)
  489 int tun_close(int fd, char *dev)
  490 {
  491     struct ifreq ifr;
  492 
  493     memset(&ifr, 0, sizeof(ifr));
  494     strcpy(ifr.ifr_name, dev);
  495     if (ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0) {
  496         syslog(LOG_ERR, "Can't get iface flags");
  497         return 0;
  498     }
  499 
  500     if (ioctl(ip_fd, I_PUNLINK, muxid) < 0) {
  501         syslog(LOG_ERR, "Can't unlink interface");
  502         return 0;
  503     }
  504 
  505     close(ip_fd);
  506     ip_fd = -1;
  507     close(fd);
  508     return 0;
  509 }
  510 #elif defined(__CYGWIN__)
  511 int tun_close(int fd, char *dev)
  512 {
  513     dev = NULL; /* unused */
  514     return CloseHandle((HANDLE) get_osfhandle(fd));
  515 }
  516 #else
  517 int tun_close(int fd, char *dev)
  518 {
  519     dev = NULL; /*unused */
  520     return close(fd);
  521 }
  522 #endif
  523 
  524 
  525 #if defined(__sun__)
  526 int tun_write(int fd, unsigned char *buf, int len)
  527 {
  528     struct strbuf sbuf;
  529     sbuf.len = len;
  530     sbuf.buf = buf;
  531     return putmsg(fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;
  532 }
  533 
  534 int tun_read(int fd, unsigned char *buf, int len)
  535 {
  536     struct strbuf sbuf;
  537     int f = 0;
  538 
  539     sbuf.maxlen = len;
  540     sbuf.buf = buf;
  541     return getmsg(fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
  542 }
  543 #elif defined(__CYGWIN__)
  544 int tun_read(int fd, unsigned char *buf, int len)
  545 {
  546     DWORD read_size;
  547     
  548     ResetEvent(overlap_read.hEvent);
  549     if (ReadFile((HANDLE) get_osfhandle(fd), buf, len, &read_size, &overlap_read)) {
  550         return read_size;
  551     }
  552     switch (GetLastError()) {
  553     case ERROR_IO_PENDING:
  554         WaitForSingleObject(overlap_read.hEvent, INFINITE);
  555         GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_read, &read_size, FALSE);
  556         return read_size;
  557         break;
  558     default:
  559         break;
  560     }
  561     
  562     return -1;
  563 }
  564 
  565 int tun_write(int fd, unsigned char *buf, int len)
  566 {
  567     DWORD write_size;
  568     
  569     ResetEvent(overlap_write.hEvent);
  570     if (WriteFile((HANDLE) get_osfhandle(fd),
  571         buf,
  572         len,
  573         &write_size,
  574         &overlap_write)) {
  575         return write_size;
  576     }
  577     switch (GetLastError()) {
  578     case ERROR_IO_PENDING:
  579         WaitForSingleObject(overlap_write.hEvent, INFINITE);
  580         GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_write,
  581             &write_size, FALSE);
  582         return write_size;
  583         break;
  584     default:
  585         break;
  586     }
  587     
  588     return -1;
  589 }
  590 #elif defined(NEW_TUN)
  591 #define MAX_MRU 2048
  592 struct tun_data {
  593     union {
  594         uint32_t family;
  595         uint32_t timeout;
  596     } header;
  597     u_char data[MAX_MRU];
  598 };
  599 
  600 /* Read/write frames from TUN device */
  601 int tun_write(int fd, unsigned char *buf, int len)
  602 {
  603     char *data;
  604     struct tun_data tun;
  605 
  606     if (len > (int)sizeof(tun.data))
  607         return -1;
  608 
  609     memcpy(tun.data, buf, len);
  610     tun.header.family = htonl(AF_INET);
  611     len += (sizeof(tun) - sizeof(tun.data));
  612     data = (char *)&tun;
  613 
  614     return write(fd, data, len) - (sizeof(tun) - sizeof(tun.data));
  615 }
  616 
  617 int tun_read(int fd, unsigned char *buf, int len)
  618 {
  619     struct tun_data tun;
  620     char *data;
  621     size_t sz;
  622     int pack;
  623 
  624     data = (char *)&tun;
  625     sz = sizeof(tun);
  626     pack = read(fd, data, sz);
  627     if (pack == -1)
  628         return -1;
  629 
  630     pack -= sz - sizeof(tun.data);
  631     if (pack > len)
  632         pack = len; /* truncate paket */
  633 
  634     memcpy(buf, tun.data, pack);
  635 
  636     return pack;
  637 }
  638 
  639 #else
  640 
  641 int tun_write(int fd, unsigned char *buf, int len)
  642 {
  643     return write(fd, buf, len);
  644 }
  645 
  646 int tun_read(int fd, unsigned char *buf, int len)
  647 {
  648     return read(fd, buf, len);
  649 }
  650 
  651 #endif
  652 
  653 /*
  654  * Get HW addr
  655  */
  656 int tun_get_hwaddr(int fd, char *dev, uint8_t *hwaddr)
  657 {
  658 #if defined(__CYGWIN__)
  659     ULONG len;
  660     
  661     dev = NULL; /* unused */
  662     if (!DeviceIoControl((HANDLE) get_osfhandle(fd), TAP_IOCTL_GET_MAC,
  663         hwaddr, ETH_ALEN, hwaddr, ETH_ALEN, &len, NULL)) {
  664         printf("Cannot get HW address\n");
  665         return -1;
  666     }
  667     
  668     return 0;
  669 #elif defined(SIOCGIFHWADDR)
  670     struct ifreq ifr;
  671     
  672     /* Use a new socket fd! */
  673     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  674         return -1;
  675     }
  676     
  677     memset(&ifr, 0, sizeof(struct ifreq));
  678     strncpy(ifr.ifr_name, dev, IFNAMSIZ);
  679     
  680     if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
  681         return -1;
  682     }
  683     
  684     memcpy(hwaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
  685     
  686     return 0;
  687 #else
  688     /* todo: implement using SIOCGLIFADDR */
  689     fd = 0;
  690     dev = 0;
  691     hwaddr = 0;
  692     errno = ENOSYS;
  693     return -1;
  694 #endif
  695 }
  696 
  697 /***********************************************************************/
  698 /* other support functions */
  699 
  700 #ifndef HAVE_VASPRINTF
  701 int vasprintf(char **strp, const char *fmt, va_list ap)
  702 {
  703     int ret;
  704     char *strbuf;
  705 
  706     ret = vsnprintf(NULL, 0, fmt, ap);
  707     strbuf = (char *)malloc(ret + 1);
  708     if (strbuf == NULL) {
  709         errno = ENOMEM;
  710         ret = -1;
  711     }
  712     vsnprintf(strbuf, ret + 1, fmt, ap);
  713     *strp = strbuf;
  714     return ret;
  715 }
  716 #endif
  717 
  718 #ifndef HAVE_ASPRINTF
  719 int asprintf(char **strp, const char *fmt, ...)
  720 {
  721     int ret;
  722     va_list ap;
  723 
  724     va_start(ap, fmt);
  725     ret = vasprintf(strp, fmt, ap);
  726     va_end(ap);
  727 
  728     return ret;
  729 }
  730 #endif
  731 
  732 #ifndef HAVE_ERROR
  733 void error(int status, int errornum, const char *fmt, ...)
  734 {
  735     char *buf2;
  736     va_list ap;
  737 
  738     va_start(ap, fmt);
  739     vasprintf(&buf2, fmt, ap);
  740     va_end(ap);
  741     fprintf(stderr, "%s", buf2);
  742     if (errornum)
  743         fprintf(stderr, ": %s\n", strerror(errornum));
  744     else
  745         fprintf(stderr, "\n");
  746     free(buf2);
  747 
  748     if (status)
  749         exit(status);
  750 }
  751 #endif
  752 
  753 #ifndef HAVE_GETLINE
  754 int getline(char **line, size_t * length, FILE * stream)
  755 {
  756     size_t len;
  757 #ifdef HAVE_FGETLN
  758     char *tmpline;
  759 
  760     tmpline = fgetln(stream, &len);
  761 #else
  762     char tmpline[512];
  763 
  764     fgets(tmpline, sizeof(tmpline), stream);
  765     len = strlen(tmpline);
  766 #endif
  767     if (feof(stream))
  768         return -1;
  769     if (*line == NULL) {
  770         *line = malloc(len + 1);
  771         *length = len + 1;
  772     }
  773     if (*length < len + 1) {
  774         *line = realloc(*line, len + 1);
  775         *length = len + 1;
  776     }
  777     if (*line == NULL)
  778         return -1;
  779     memcpy(*line, tmpline, len);
  780     (*line)[len] = '\0';
  781     return len;
  782 }
  783 #endif
  784 
  785 #ifndef HAVE_UNSETENV
  786 int unsetenv(const char *name)
  787 {
  788     int i, len;
  789 
  790     len = strlen(name);
  791     for (i = 0; environ[i]; i++)
  792         if (!strncmp(name, environ[i], len))
  793             if (environ[i][len] == '=')
  794                 break;
  795 
  796     for (; environ[i] && environ[i + 1]; i++)
  797         environ[i] = environ[i + 1];
  798     
  799     return 0;
  800 }
  801 #endif
  802 
  803 #ifndef HAVE_SETENV
  804 int setenv(const char *name, const char *value, int overwrite)
  805 {
  806     int ret;
  807     char *newenv;
  808 
  809     if (overwrite == 0)
  810         if (getenv(name) != NULL)
  811             return 0;
  812 
  813     newenv = malloc(strlen(name) + 1 + strlen(value) + 1);
  814     if (newenv == NULL)
  815         return -1;
  816 
  817     *newenv = '\0';
  818     strcat(newenv, name);
  819     strcat(newenv, "=");
  820     strcat(newenv, value);
  821 
  822     ret = putenv(newenv);
  823     if (ret == -1)
  824         free(newenv);
  825 
  826     return ret;
  827 }
  828 #endif