1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00
Files
nmap/nbase/nbase_misc.c
david ed2ba4e168 Copy nping, nsock, nbase, zenmap, ncat from their homes in /.
If you have trouble updating after this revision you need to follow
these instructions. You have probably just seen an error like this:

svn: URL 'svn://svn.insecure.org/nping' of existing directory 'nping'
does not match expected URL 'svn://svn.insecure.org/nmap/nping'

This is caused by the replacement of SVN externals.

Here's what you need to do. First, save any local changes you might have
in the nping, nsock, nbase, ncat, and zenmap directories. (For example
by running "cd nping; svn diff > ../nping.diff".) If you don't have any
local changes you can skip this step.

Then run these commands:

rm -rf nping/ nsock/ nbase/ ncat/ zenmap/
svn update
svn cleanup

If all else fails, you can just delete your whole working directory and
check out anew:

svn co --username guest --password "" svn://svn.insecure.org/nmap

There may be further discussion in the mailing list thread at
http://seclists.org/nmap-dev/2011/q4/303.
2011-11-16 21:49:44 +00:00

835 lines
28 KiB
C

/***************************************************************************
* nbase_misc.c -- Some small miscelaneous utility/compatability *
* functions. *
* *
***********************IMPORTANT NMAP LICENSE TERMS************************
* *
* The Nmap Security Scanner is (C) 1996-2011 Insecure.Com LLC. Nmap is *
* also a registered trademark of Insecure.Com LLC. This program is free *
* software; you may redistribute and/or modify it under the terms of the *
* GNU General Public License as published by the Free Software *
* Foundation; Version 2 with the clarifications and exceptions described *
* below. This guarantees your right to use, modify, and redistribute *
* this software under certain conditions. If you wish to embed Nmap *
* technology into proprietary software, we sell alternative licenses *
* (contact sales@insecure.com). Dozens of software vendors already *
* license Nmap technology such as host discovery, port scanning, OS *
* detection, and version detection. *
* *
* Note that the GPL places important restrictions on "derived works", yet *
* it does not provide a detailed definition of that term. To avoid *
* misunderstandings, we consider an application to constitute a *
* "derivative work" for the purpose of this license if it does any of the *
* following: *
* o Integrates source code from Nmap *
* o Reads or includes Nmap copyrighted data files, such as *
* nmap-os-db or nmap-service-probes. *
* o Executes Nmap and parses the results (as opposed to typical shell or *
* execution-menu apps, which simply display raw Nmap output and so are *
* not derivative works.) *
* o Integrates/includes/aggregates Nmap into a proprietary executable *
* installer, such as those produced by InstallShield. *
* o Links to a library or executes a program that does any of the above *
* *
* The term "Nmap" should be taken to also include any portions or derived *
* works of Nmap. This list is not exclusive, but is meant to clarify our *
* interpretation of derived works with some common examples. Our *
* interpretation applies only to Nmap--we don't speak for other people's *
* GPL works. *
* *
* If you have any questions about the GPL licensing restrictions on using *
* Nmap in non-GPL works, we would be happy to help. As mentioned above, *
* we also offer alternative license to integrate Nmap into proprietary *
* applications and appliances. These contracts have been sold to dozens *
* of software vendors, and generally include a perpetual license as well *
* as providing for priority support and updates as well as helping to *
* fund the continued development of Nmap technology. Please email *
* sales@insecure.com for further information. *
* *
* As a special exception to the GPL terms, Insecure.Com LLC grants *
* permission to link the code of this program with any version of the *
* OpenSSL library which is distributed under a license identical to that *
* listed in the included docs/licenses/OpenSSL.txt file, and distribute *
* linked combinations including the two. You must obey the GNU GPL in all *
* respects for all of the code used other than OpenSSL. If you modify *
* this file, you may extend this exception to your version of the file, *
* but you are not obligated to do so. *
* *
* If you received these files with a written license agreement or *
* contract stating terms other than the terms above, then that *
* alternative license agreement takes precedence over these comments. *
* *
* Source is provided to this software because we believe users have a *
* right to know exactly what a program is going to do before they run it. *
* This also allows you to audit the software for security holes (none *
* have been found so far). *
* *
* Source code also allows you to port Nmap to new platforms, fix bugs, *
* and add new features. You are highly encouraged to send your changes *
* to nmap-dev@insecure.org for possible incorporation into the main *
* distribution. By sending these changes to Fyodor or one of the *
* Insecure.Org development mailing lists, it is assumed that you are *
* offering the Nmap Project (Insecure.Com LLC) the unlimited, *
* non-exclusive right to reuse, modify, and relicense the code. Nmap *
* will always be available Open Source, but this is important because the *
* inability to relicense code has caused devastating problems for other *
* Free Software projects (such as KDE and NASM). We also occasionally *
* relicense the code to third parties as discussed above. If you wish to *
* specify special license conditions of your contributions, just say so *
* when you send them. *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License v2.0 for more details at *
* http://www.gnu.org/licenses/gpl-2.0.html , or in the COPYING file *
* included with Nmap. *
* *
***************************************************************************/
/* $Id$ */
#include "nbase.h"
#ifndef WIN32
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#else
#include <winsock2.h>
#endif
#include <limits.h>
#include <stdio.h>
#include "nbase_ipv6.h"
#include "nbase_crc32ct.h"
#include <assert.h>
#include <fcntl.h>
#ifdef WIN32
#include <conio.h>
#endif
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
/* Returns the UNIX/Windows errno-equivalent. Note that the Windows
call is socket/networking specific. The windows error number
returned is like WSAMSGSIZE, but nbase.h includes #defines to
correlate many of the common UNIX errors with their closest Windows
equivalents. So you can use EMSGSIZE or EINTR. */
int socket_errno() {
#ifdef WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
/* We can't just use strerror to get socket errors on Windows because it has
its own set of error codes: WSACONNRESET not ECONNRESET for example. This
function will do the right thing on Windows. Call it like
socket_strerror(socket_errno())
*/
char *socket_strerror(int errnum) {
#ifdef WIN32
static char buffer[128];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
0, errnum, 0, buffer, sizeof(buffer), NULL);
return buffer;
#else
return strerror(errnum);
#endif
}
/* Compares two sockaddr_storage structures with a return value like strcmp.
First the address families are compared, then the addresses if the families
are equal. The structures must be real full-length sockaddr_storage
structures, not something shorter like sockaddr_in. */
int sockaddr_storage_cmp(const struct sockaddr_storage *a,
const struct sockaddr_storage *b) {
if (a->ss_family < b->ss_family)
return -1;
else if (a->ss_family > b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
struct sockaddr_in *sin_a = (struct sockaddr_in *) a;
struct sockaddr_in *sin_b = (struct sockaddr_in *) b;
if (sin_a->sin_addr.s_addr < sin_b->sin_addr.s_addr)
return -1;
else if (sin_a->sin_addr.s_addr > sin_b->sin_addr.s_addr)
return 1;
else
return 0;
} else if (a->ss_family == AF_INET6) {
struct sockaddr_in6 *sin6_a = (struct sockaddr_in6 *) a;
struct sockaddr_in6 *sin6_b = (struct sockaddr_in6 *) b;
return memcmp(sin6_a->sin6_addr.s6_addr, sin6_b->sin6_addr.s6_addr,
sizeof(sin6_a->sin6_addr.s6_addr));
} else {
assert(0);
}
return 0; /* Not reached */
}
int sockaddr_storage_equal(const struct sockaddr_storage *a,
const struct sockaddr_storage *b) {
return sockaddr_storage_cmp(a, b) == 0;
}
/* This function is an easier version of inet_ntop because you don't
need to pass a dest buffer. Instead, it returns a static buffer that
you can use until the function is called again (by the same or another
thread in the process). If there is a wierd error (like sslen being
too short) then NULL will be returned. */
const char *inet_ntop_ez(const struct sockaddr_storage *ss, size_t sslen) {
const struct sockaddr_in *sin = (struct sockaddr_in *) ss;
static char str[INET6_ADDRSTRLEN];
#if HAVE_IPV6
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ss;
#endif
str[0] = '\0';
if (sin->sin_family == AF_INET) {
if (sslen < sizeof(struct sockaddr_in))
return NULL;
return inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
}
#if HAVE_IPV6
else if(sin->sin_family == AF_INET6) {
if (sslen < sizeof(struct sockaddr_in6))
return NULL;
return inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
}
#endif
//Some laptops report the ip and address family of disabled wifi cards as null
//so yes, we will hit this sometimes.
return NULL;
}
/* Create a new socket inheritable by subprocesses. On non-Windows systems it's
just a normal socket. */
int inheritable_socket(int af, int style, int protocol) {
#ifdef WIN32
/* WSASocket is just like socket, except that the sockets it creates are
inheritable by subprocesses (such as are created by CreateProcess), while
those created by socket are not. */
return WSASocket(af, style, protocol, NULL, 0, 0);
#else
return socket(af, style, protocol);
#endif
}
/* The dup function on Windows works only on file descriptors, not socket
handles. This function accomplishes the same thing for sockets. */
int dup_socket(int sd) {
#ifdef WIN32
HANDLE copy;
if (DuplicateHandle(GetCurrentProcess(), (HANDLE) sd,
GetCurrentProcess(), &copy,
0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
return -1;
}
return (int) copy;
#else
return dup(sd);
#endif
}
int unblock_socket(int sd) {
#ifdef WIN32
u_long one = 1;
if(sd != 501) // Hack related to WinIP Raw Socket support
ioctlsocket (sd, FIONBIO, &one);
#else
int options;
/*Unblock our socket to prevent recvfrom from blocking forever
on certain target ports. */
options = O_NONBLOCK | fcntl(sd, F_GETFL);
fcntl(sd, F_SETFL, options);
#endif //WIN32
return 1;
}
/* Convert a socket to blocking mode */
int block_socket(int sd) {
#ifdef WIN32
unsigned long options=0;
if(sd == 501) return 1;
ioctlsocket(sd, FIONBIO, &options);
#else
int options;
options = (~O_NONBLOCK) & fcntl(sd, F_GETFL);
fcntl(sd, F_SETFL, options);
#endif
return 1;
}
/* Convert a time specification into a count of seconds. A time specification is
* a non-negative real number, possibly followed by a units suffix. The suffixes
* are "ms" for milliseconds, "s" for seconds, "m" for minutes, or "h" for
* hours. Seconds is the default with no suffix. -1 is returned if the string
* can't be parsed. */
double tval2secs(const char *tspec) {
double d;
char *tail;
errno = 0;
d = strtod(tspec, &tail);
if (*tspec == '\0' || errno != 0)
return -1;
if (strcasecmp(tail, "ms") == 0)
return d / 1000.0;
else if (*tail == '\0' || strcasecmp(tail, "s") == 0)
return d;
else if (strcasecmp(tail, "m") == 0)
return d * 60.0;
else if (strcasecmp(tail, "h") == 0)
return d * 60.0 * 60.0;
else
return -1;
}
long tval2msecs(const char *tspec) {
double s, ms;
s = tval2secs(tspec);
if (s == -1)
return -1;
ms = s * 1000.0;
if (ms > LONG_MAX || ms < LONG_MIN)
return -1;
return (long) ms;
}
/* Returns the unit portion of a time specification (such as "ms", "s", "m", or
"h"). Returns NULL if there was a parsing error or no unit is present. */
const char *tval_unit(const char *tspec) {
double d;
char *tail;
errno = 0;
d = strtod(tspec, &tail);
/* Avoid GCC 4.6 error "variable 'd' set but not used
[-Wunused-but-set-variable]". */
(void) d;
if (*tspec == '\0' || errno != 0 || *tail == '\0')
return NULL;
return tail;
}
/* A replacement for select on Windows that allows selecting on stdin
* (file descriptor 0) and selecting on zero file descriptors (just for
* the timeout). Plain Windows select doesn't work on non-sockets like
* stdin and returns an error if no file descriptors were given, because
* they were NULL or empty. This only works for sockets and stdin; if
* you have a descriptor referring to a normal open file in the set,
* Windows will return WSAENOTSOCK. */
int fselect(int s, fd_set *rmaster, fd_set *wmaster, fd_set *emaster, struct timeval *tv)
{
#ifdef WIN32
static int stdin_thread_started = 0;
int fds_ready = 0;
int iter = -1, i;
struct timeval stv;
fd_set rset, wset, eset;
/* Figure out whether there are any FDs in the sets, as @$@!$# Windows
returns WSAINVAL (10022) if you call a select() with no FDs, even though
the Linux man page says that doing so is a good, reasonably portable way
to sleep with subsecond precision. Sigh. */
for(i = s; i > STDIN_FILENO; i--) {
if ((rmaster != NULL && FD_ISSET(i, rmaster))
|| (wmaster != NULL && FD_ISSET(i, wmaster))
|| (emaster != NULL && FD_ISSET(i, emaster)))
break;
s--;
}
/* Handle the case where stdin is not being read from. */
if (rmaster == NULL || !FD_ISSET(STDIN_FILENO, rmaster)) {
if (s > 0) {
/* Do a normal select. */
return select(s, rmaster, wmaster, emaster, tv);
} else {
/* No file descriptors given. Just sleep. */
if (tv == NULL) {
/* Sleep forever. */
while (1)
sleep(10000);
} else {
usleep(tv->tv_sec * 1000000UL + tv->tv_usec);
return 0;
}
}
}
/* This is a hack for Windows, which doesn't allow select()ing on
* non-sockets (like stdin). We remove stdin from the fd_set and
* loop while select()ing on everything else, with a timeout of
* 125ms. Then we check if stdin is ready and increment fds_ready
* and set stdin in rmaster if it looks good. We just keep looping
* until we have something or it times out.
*/
/* nbase_winunix.c has all the nasty details behind checking if
* stdin has input. It involves a background thread, which we start
* now if necessary. */
if (!stdin_thread_started) {
int ret = win_stdin_start_thread();
assert(ret != 0);
stdin_thread_started = 1;
}
FD_CLR(STDIN_FILENO, rmaster);
if (tv) {
int usecs = (tv->tv_sec * 1000000) + tv->tv_usec;
iter = usecs / 125000;
if (usecs % 125000)
iter++;
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
while (!fds_ready && iter) {
stv.tv_sec = 0;
stv.tv_usec = 125000;
if (rmaster)
rset = *rmaster;
if (wmaster)
wset = *wmaster;
if (emaster)
eset = *emaster;
fds_ready = 0;
/* selecting on anything other than stdin? */
if (s > 1)
fds_ready = select(s, &rset, &wset, &eset, &stv);
if (fds_ready > -1 && win_stdin_ready()) {
FD_SET(STDIN_FILENO, &rset);
fds_ready++;
}
if (tv)
iter--;
}
if (rmaster)
*rmaster = rset;
if (wmaster)
*wmaster = wset;
if (emaster)
*emaster = eset;
return fds_ready;
#else
return select(s, rmaster, wmaster, emaster, tv);
#endif
}
/*
* CRC32 Cyclic Redundancy Check
*
* From: http://www.ietf.org/rfc/rfc1952.txt
*
* Copyright (c) 1996 L. Peter Deutsch
*
* Permission is granted to copy and distribute this document for any
* purpose and without charge, including translations into other
* languages and incorporation into compilations, provided that the
* copyright notice and this notice are preserved, and that any
* substantive changes or deletions from the original are clearly
* marked.
*
*/
/* Table of CRCs of all 8-bit messages. */
static unsigned long crc_table[256];
/* Flag: has the table been computed? Initially false. */
static int crc_table_computed = 0;
/* Make the table for a fast CRC. */
static void make_crc_table(void)
{
unsigned long c;
int n, k;
for (n = 0; n < 256; n++) {
c = (unsigned long) n;
for (k = 0; k < 8; k++) {
if (c & 1) {
c = 0xedb88320L ^ (c >> 1);
} else {
c = c >> 1;
}
}
crc_table[n] = c;
}
crc_table_computed = 1;
}
/*
Update a running crc with the bytes buf[0..len-1] and return
the updated crc. The crc should be initialized to zero. Pre- and
post-conditioning (one's complement) is performed within this
function so it shouldn't be done by the caller. Usage example:
unsigned long crc = 0L;
while (read_buffer(buffer, length) != EOF) {
crc = update_crc(crc, buffer, length);
}
if (crc != original_crc) error();
*/
static unsigned long update_crc(unsigned long crc,
unsigned char *buf, int len)
{
unsigned long c = crc ^ 0xffffffffL;
int n;
if (!crc_table_computed)
make_crc_table();
for (n = 0; n < len; n++) {
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
}
return c ^ 0xffffffffL;
}
/* Return the CRC of the bytes buf[0..len-1]. */
unsigned long nbase_crc32(unsigned char *buf, int len)
{
return update_crc(0L, buf, len);
}
/*
* CRC-32C (Castagnoli) Cyclic Redundancy Check.
* Taken straight from RFC 4960 (SCTP).
*/
/* Return the CRC-32C of the bytes buf[0..len-1] */
unsigned long nbase_crc32c(unsigned char *buf, int len)
{
int i;
unsigned long crc32 = ~0L;
unsigned long result;
unsigned char byte0, byte1, byte2, byte3;
for (i = 0; i < len; i++) {
CRC32C(crc32, buf[i]);
}
result = ~crc32;
/* result now holds the negated polynomial remainder;
* since the table and algorithm is "reflected" [williams95].
* That is, result has the same value as if we mapped the message
* to a polynomial, computed the host-bit-order polynomial
* remainder, performed final negation, then did an end-for-end
* bit-reversal.
* Note that a 32-bit bit-reversal is identical to four inplace
* 8-bit reversals followed by an end-for-end byteswap.
* In other words, the bytes of each bit are in the right order,
* but the bytes have been byteswapped. So we now do an explicit
* byteswap. On a little-endian machine, this byteswap and
* the final ntohl cancel out and could be elided.
*/
byte0 = result & 0xff;
byte1 = (result >> 8) & 0xff;
byte2 = (result >> 16) & 0xff;
byte3 = (result >> 24) & 0xff;
crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
return crc32;
}
/*
* Adler32 Checksum Calculation.
* Taken straight from RFC 2960 (SCTP).
*/
#define ADLER32_BASE 65521 /* largest prime smaller than 65536 */
/*
* Update a running Adler-32 checksum with the bytes buf[0..len-1]
* and return the updated checksum. The Adler-32 checksum should
* be initialized to 1.
*/
static unsigned long update_adler32(unsigned long adler,
unsigned char *buf, int len)
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int n;
for (n = 0; n < len; n++) {
s1 = (s1 + buf[n]) % ADLER32_BASE;
s2 = (s2 + s1) % ADLER32_BASE;
}
return (s2 << 16) + s1;
}
/* Return the Adler32 of the bytes buf[0..len-1] */
unsigned long nbase_adler32(unsigned char *buf, int len)
{
return update_adler32(1L, buf, len);
}
#undef ADLER32_BASE
/* This function returns a string containing the hexdump of the supplied
* buffer. It uses current locale to determine if a character is printable or
* not. It prints 73char+\n wide lines like these:
0000 e8 60 65 86 d7 86 6d 30 35 97 54 87 ff 67 05 9e .`e...m05.T..g..
0010 07 5a 98 c0 ea ad 50 d2 62 4f 7b ff e1 34 f8 fc .Z....P.bO{..4..
0020 c4 84 0a 6a 39 ad 3c 10 63 b2 22 c4 24 40 f4 b1 ...j9.<.c.".$@..
* The lines look basically like Wireshark's hex dump.
* WARNING: This function returns a pointer to a DYNAMICALLY allocated buffer
* that the caller is supposed to free().
* */
char *hexdump(const u8 *cp, u32 length){
static char asciify[257]; /* Stores cha6acter table */
int asc_init=0; /* Flag to generate table only once */
u32 i=0, hex=0, asc=0; /* Array indexes */
u32 line_count=0; /* For byte count at line start */
char *current_line=NULL; /* Current line to write */
char *buffer=NULL; /* Dynamic buffer we return */
#define LINE_LEN 74 /* Lenght of printed line */
char line2print[LINE_LEN]; /* Stores current line */
char printbyte[16]; /* For byte conversion */
int bytes2alloc; /* For buffer */
memset(line2print, ' ', LINE_LEN); /* We fill the line with spaces */
/* On the first run, generate a list of nice printable characters
* (according to current locale) */
if( asc_init==0){
asc_init=1;
for(i=0; i<256; i++){
if( isalnum(i) || isdigit(i) || ispunct(i) ){ asciify[i]=i; }
else{ asciify[i]='.'; }
}
}
/* Allocate enough space to print the hex dump */
bytes2alloc=(length%16==0)? (1 + LINE_LEN * (length/16)) : (1 + LINE_LEN * (1+(length/16))) ;
buffer=(char *)safe_zalloc(bytes2alloc);
current_line=buffer;
#define HEX_START 7
#define ASC_START 57
/* This is how or line looks like.
0000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f .`e...m05.T..g..[\n]
01234567890123456789012345678901234567890123456789012345678901234567890123
0 1 2 3 4 5 6 7
^ ^ ^
| | |
HEX_START ASC_START Newline
*/
i=0;
while( i < length ){
memset(line2print, ' ', LINE_LEN); /* Fill line with spaces */
snprintf(line2print, sizeof(line2print), "%04x", (16*line_count++) % 0xFFFF); /* Add line No.*/
line2print[4]=' '; /* Replace the '\0' inserted by snprintf() with a space */
hex=HEX_START; asc=ASC_START;
do { /* Print 16 bytes in both hex and ascii */
if (i%16 == 8) hex++; /* Insert space every 8 bytes */
snprintf(printbyte, sizeof(printbyte), "%02x", cp[i]);/* First print the hex number */
line2print[hex++]=printbyte[0];
line2print[hex++]=printbyte[1];
line2print[hex++]=' ';
line2print[asc++]=asciify[ cp[i] ]; /* Then print its ASCII equivalent */
i++;
} while (i < length && i%16 != 0);
/* Copy line to output buffer */
line2print[LINE_LEN-1]='\n';
memcpy(current_line, line2print, LINE_LEN);
current_line += LINE_LEN;
}
buffer[bytes2alloc-1]='\0';
return buffer;
} /* End of hexdump() */
/* This is like strtol or atoi, but it allows digits only. No whitespace, sign,
or radix prefix. */
long parse_long(const char *s, char **tail)
{
if (!isdigit((int) (unsigned char) *s)) {
*tail = (char *) s;
return 0;
}
return strtol(s, (char **) tail, 10);
}
/* This function takes a byte count and stores a short ascii equivalent
in the supplied buffer. Eg: 0.122MB, 10.322Kb or 128B. */
char *format_bytecount(unsigned long long bytes, char *buf, size_t buflen) {
assert(buf != NULL);
if (bytes < 1000)
Snprintf(buf, buflen, "%uB", (unsigned int) bytes);
else if (bytes < 1000000)
Snprintf(buf, buflen, "%.3fKB", bytes / 1000.0);
else
Snprintf(buf, buflen, "%.3fMB", bytes / 1000000.0);
return buf;
}
/* Compare a canonical option name (e.g. "max-scan-delay") with a
user-generated option such as "max_scan_delay" and returns 0 if the
two values are considered equivalant (for example, - and _ are
considered to be the same), nonzero otherwise. */
int optcmp(const char *a, const char *b) {
while(*a && *b) {
if (*a == '_' || *a == '-') {
if (*b != '_' && *b != '-')
return 1;
}
else if (*a != *b)
return 1;
a++; b++;
}
if (*a || *b)
return 1;
return 0;
}
/* Returns one if the file pathname given exists, is not a directory and
* is readable by the executing process. Returns two if it is readable
* and is a directory. Otherwise returns 0. */
int fileexistsandisreadable(const char *pathname) {
char *pathname_buf = strdup(pathname);
int status = 0;
struct stat st;
#ifdef WIN32
// stat on windows only works for "dir_name" not for "dir_name/" or "dir_name\\"
int pathname_len = strlen(pathname_buf);
char last_char = pathname_buf[pathname_len - 1];
if( last_char == '/'
|| last_char == '\\')
pathname_buf[pathname_len - 1] = '\0';
#endif
if (stat(pathname_buf, &st) == -1)
status = 0;
else if (access(pathname_buf, R_OK) != -1)
status = S_ISDIR(st.st_mode) ? 2 : 1;
free(pathname_buf);
return status;
}
#if HAVE_PROC_SELF_EXE
static char *executable_path_proc_self_exe(void) {
char buf[1024];
char *path;
int n;
n = readlink("/proc/self/exe", buf, sizeof(buf));
if (n < 0 || n >= sizeof(buf))
return NULL;
path = (char *) safe_malloc(n + 1);
/* readlink does not null-terminate. */
memcpy(path, buf, n);
path[n] = '\0';
return path;
}
#endif
#if HAVE_MACH_O_DYLD_H
#include <mach-o/dyld.h>
/* See the dyld(3) man page on OS X. */
static char *executable_path_NSGetExecutablePath(void) {
char buf[1024];
uint32_t size;
size = sizeof(buf);
if (_NSGetExecutablePath(buf, &size) == 0)
return strdup(buf);
else
return NULL;
}
#endif
#if WIN32
static char *executable_path_GetModuleFileName(void) {
char buf[1024];
int n;
n = GetModuleFileName(GetModuleHandle(0), buf, sizeof(buf));
if (n <= 0 || n >= sizeof(buf))
return NULL;
return strdup(buf);
}
#endif
static char *executable_path_argv0(const char *argv0) {
if (argv0 == NULL)
return NULL;
/* We can get the path from argv[0] if it contains a directory separator.
(Otherwise it was looked up in $PATH). */
if (strchr(argv0, '/') != NULL)
return strdup(argv0);
#if WIN32
if (strchr(argv0, '\\') != NULL)
return strdup(argv0);
#endif
return NULL;
}
char *executable_path(const char *argv0) {
char *path;
path = NULL;
#if HAVE_PROC_SELF_EXE
if (path == NULL)
path = executable_path_proc_self_exe();
#endif
#if HAVE_MACH_O_DYLD_H
if (path == NULL)
path = executable_path_NSGetExecutablePath();
#endif
#if WIN32
if (path == NULL)
path = executable_path_GetModuleFileName();
#endif
if (path == NULL)
path = executable_path_argv0(argv0);
return path;
}