/* * ircaux.c: some extra routines... not specific to irc... that I needed * * Written By Michael Sandrof * * Copyright (c) 1990, 1991 Michael Sandrof. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-2004 Matthew R. Green. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "irc.h" IRCII_RCSID("@(#)$eterna: ircaux.c,v 1.94 2005/09/21 22:19:20 mrg Exp $"); #if defined(MIPS_SYSV) # define _TERMIOS_INCLUDED # define _INCLUDE_TERMIO # include #endif /* MIPS_SYSV */ #ifdef HAVE_SYS_UN_H #include #endif /* HAVE_SYS_UN_H */ #ifndef _Windows #include #endif /* _Windows */ #include "ircaux.h" #include "output.h" #include "ircterm.h" #include "newio.h" #include "server.h" static int bind_local_addr(u_char *, u_char *, int, int); #ifdef ALLOC_DEBUG # ifdef _IBMR2 struct HeapDesc { u_long Link; u_long Size; }; # endif /* _IBMR2 */ #define ALLOC_LIST 2048 static u_char *MemList[ALLOC_LIST]; static long MemSize[ALLOC_LIST]; static int Init = 0; static void dump_mem(void); static void dump_mem() { int i; FILE *fp; # ifdef _IBMR2 struct HeapDesc *HeapElement; u_char *lowest; u_char *highest; long size; # endif /* _IBMR2 */ int fits; fp = fopen("debug.log", "w"); fprintf(fp, "ircII failed because of a segmentation violation\nKnown allocations follow:\n\n"); for (i = 0; i < ALLOC_LIST; i++) if (MemList[i]) { # ifdef _IBMR2 /* * The following determines if the size shown for this element of * memory matches the size we have recorded in the allocation list. * this is very much machine dependant, and could even vary between * SysV and BSD on the same machine. */ size = (0x08 << (*((long *) MemList[i] - 1))); if (size - 0x08 >= MemSize[i] && (size >> 1) - 0x08 (u_long) highest) highest = MemList[i]; } fprintf(fp, "\nKnown allocations start at %08x and end at %08x\n", lowest, highest); fprintf(fp, "\nHeap walks as follows:\n\n"); for (HeapElement = lowest-0x08; HeapElementLink == 0xefL || !HeapElement->Link)? (HeapElement+(0x01<Size)): ((struct HeapDesc *) HeapElement->Link)) { fprintf(fp, " %08x %08x %08x\n", HeapElement + 1, HeapElement->Link, HeapElement->Size); } # endif /* _IBMR2 */ fclose(fp); fprintf(stderr, "Segmentation violation. Debug information saved to debug.log\n"); /* * If we resume on a segmentation violation, hopefully it repeats the * violation and we get both our log and the core dump from the point * at which things fail. */ (void) MY_SIGNAL(SIGSEGV, (sigfunc *)SIG_DFL, 0); return; } #endif /* ALLOC_DEBUG */ /* * new_free: Why do this? Why not? Saves me a bit of trouble here and * there */ void new_free(iptr) void *iptr; { void **ptr = (void **) iptr; #ifdef ALLOC_DEBUG FILE *fp; int i; #endif /* ALLOC_DEBUG */ #ifdef DO_USER2 int oldmask; #endif /* DO_USER2 */ /* cheap hack. */ if (*ptr == empty_string || *ptr == zero || *ptr == one) *ptr = (void *) 0; else if (*ptr) { #ifdef DO_USER2 oldmask = sigblock(sigmask(SIGUSR2)); #endif /* DO_USER2 */ #ifdef FREE_DEBUG if (free(*ptr) < 0) put_it("*debug* free failed '%s'", (u_char *) ptr); #else free(*ptr); #endif /* FREE_DEBUG */ #ifdef DO_USER2 sigblock(oldmask); #endif /* DO_USER2 */ #ifdef ALLOC_DEBUG for (i = 0; i < ALLOC_LIST; i++) { if ((void *) MemList[i] == *ptr) break; } if (i == ALLOC_LIST) { fprintf(stderr, "Memory freed that was never allocated\n"); fp=fopen("debug.log", "w"); fprintf(fp, "failed by freeing %08lx\n", (long) *ptr); fprintf(fp, "List is as follows:\n"); for (i = 0; i < ALLOC_LIST; i++) if (MemList[i]) fprintf(fp, " %08lx %08lx\n", (long) MemList[i], MemSize[i]); fclose(fp); abort(); } MemList[i] = (void *) 0; MemSize[i] = 0L; #endif /* ALLOC_DEBUG */ *ptr = (void *) 0; } } #define WAIT_BUFFER 2048 static u_char * FAR wait_pointers[WAIT_BUFFER] = {0}, **current_wait_ptr = wait_pointers; /* * wait_new_free: same as new_free() except that free() is postponed. */ void wait_new_free(ptr) u_char **ptr; { if (*current_wait_ptr) new_free(current_wait_ptr); *current_wait_ptr++ = *ptr; if (current_wait_ptr >= wait_pointers + WAIT_BUFFER) current_wait_ptr = wait_pointers; *ptr = (u_char *) 0; } /* * really_free: really free the data if level == 0 */ void really_free(level) int level; { if (level != 0) return; for (current_wait_ptr = wait_pointers; current_wait_ptr < wait_pointers + WAIT_BUFFER; current_wait_ptr++) if (*current_wait_ptr) new_free(current_wait_ptr); current_wait_ptr = wait_pointers; } u_char * new_realloc(ptr, size) u_char *ptr; size_t size; { u_char *new_ptr; #ifdef ALLOC_DEBUG int i; #endif /* ALLOC_DEBUG */ if ((new_ptr = (u_char *) realloc(ptr, size)) == (u_char *) 0) { fprintf(stderr, "realloc failed (%d): %s\nIrc Aborted!\n", (int)size, strerror(errno)); exit(1); } #ifdef ALLOC_DEBUG for (i = 0;i < ALLOC_LIST; i++) if ((u_char *) MemList[i] == ptr) break; if (i == ALLOC_LIST) { fprintf(stderr, "Memory freed that was never allocated"); abort(); } MemList[i] = new_ptr; MemSize[i] = size; #endif /* ALLOC_DEBUG */ return (new_ptr); } u_char * new_malloc(size) size_t size; { u_char *ptr; #ifdef ALLOC_DEBUG int i; if (!Init) { Init = 1; for (i = 0; i < ALLOC_LIST; i++) { MemList[i] = (void *) 0; MemSize[i] = 0L; } if (getenv("DEBUG")) (void) MY_SIGNAL(SIGSEGV, dump_mem, 0); } #endif /* ALLOC_DEBUG */ if ((ptr = (u_char *) malloc(size)) == (u_char *) 0) { static char error[] = "Malloc failed: \nIrc Aborted!\n"; write(2, error, my_strlen(error)); write(2, strerror(errno), my_strlen(strerror(errno))); term_reset(); exit(1); } #ifdef ALLOC_DEBUG for (i = 0; i < ALLOC_LIST && MemList[i]; i++) ; if (i == ALLOC_LIST) { FILE *fp; int j; fprintf(stderr, "Out of space in memory record. Probable memory leak\n"); fp = fopen("debug.log", "w"); for (i = 0; i < ALLOC_LIST; i++) { fprintf(fp, " %08lx %08lx \"", (long) MemList[i], MemSize[i]); for (j = 0; j < MemSize[i] && j < 45; j++) { if (MemList[i][j] < 32 || MemList[i][j] > 127) putc('.', fp); else putc(MemList[i][j], fp); } fprintf(fp, "\"\n"); } fclose(fp); abort(); } MemList[i]=ptr; MemSize[i]=size; #endif /* ALLOC_DEBUG */ return (ptr); } #ifdef ALLOC_DEBUG void alloc_cmd(command, args, subargs) u_char *command, *args, *subargs; { u_char *arg; int f_count = 0, f_dump = 0; int i, j; int count; long size; FILE *fp; while ((arg = next_arg(args, &args))) { while (*arg) { switch(*arg++) { case 'c': case 'C': f_count = 1; break; case 'd': case 'D': f_dump = 1; break; } } } if (f_dump) fp = fopen("debug.log", "w"); else fp = NULL; for (size = count = i = 0; i < ALLOC_LIST; i++) { if (fp && MemList[i]) { fprintf(fp, " %08lx %08lx \"", (long) MemList[i], MemSize[i]); for (j = 0; j < MemSize[i] && j < 45; j++) { if (MemList[i][j] < 32 || MemList[i][j] > 127) putc('.', fp); else putc(MemList[i][j], fp); } fprintf(fp, "\"\n"); } if (MemList[i]) { count++; size += MemSize[i]; } } if (fp) fclose(fp); if (f_count) { say("%d blocks allocated out of %d", count, ALLOC_LIST); say("%ld bytes allocated, an average of %ld per block", size, size/count); } } #endif /* ALLOC_DEBUG */ /* * malloc_strcpy: Mallocs enough space for src to be copied in to where * ptr points to. * * Never call this with ptr pointing to an uninitialised string, as the * call to new_free() might crash the client... - phone, jan, 1993. */ void malloc_strcpy(ptr, src) u_char **ptr; u_char *src; { malloc_strncpy(ptr, src, 0); } void malloc_strncpy(ptr, src, extra) u_char **ptr; u_char *src; size_t extra; { /* no point doing anything else */ if (src == *ptr) return; new_free(ptr); /* cheap hack. */ if ((src == empty_string || src == zero || src == one) && extra == 0) *ptr = src; else if (src) { *ptr = new_malloc(my_strlen(src) + 1 + extra); my_strcpy(*ptr, src); } else *ptr = (u_char *) 0; } /* malloc_strcat: Yeah, right */ void malloc_strcat(ptr, src) u_char **ptr; u_char *src; { malloc_strncat(ptr, src, 0); } /* malloc_strncat: Yeah, right */ void malloc_strncat(ptr, src, extra) u_char **ptr; u_char *src; size_t extra; { u_char *new; if (*ptr) { new = (u_char *) new_malloc(my_strlen(*ptr) + my_strlen(src) + 1 + extra); my_strcpy(new, *ptr); my_strcat(new, src); new_free(ptr); *ptr = new; } else malloc_strcpy(ptr, src); } void malloc_strcat_ue(ptr, src) u_char **ptr; u_char *src; { u_char *new; if (*ptr) { size_t len = my_strlen(*ptr) + my_strlen(src) + 1; new = (u_char *) new_malloc(len); my_strcpy(new, *ptr); strmcat_ue(new, src, len); new_free(ptr); *ptr = new; } else malloc_strcpy(ptr, src); } u_char * upper(s) u_char *s; { u_char *t = (u_char *) 0; if (s) for (t = s; *s; s++) if (islower(*s)) *s = toupper(*s); return (t); } u_char * lower(s) u_char *s; { u_char *t = (u_char *) 0; if (s) for (t = s; *s; s++) if (isupper(*s)) *s = tolower(*s); return t; } /* * Connect_By_Number Performs a connecting to socket 'service' on host * 'host'. Host can be a hostname or ip-address. If 'host' is null, the * local host is assumed. The parameter full_hostname will, on return, * contain the expanded hostname (if possible). Note that full_hostname is a * pointer to a u_char *, and is allocated by connect_by_numbers() * * The following special values for service exist: * * 0 Create a socket for accepting connections * * -2 Connect to the address passed in place of the hostname parameter * * Errors: * * -1 get service failed * * -2 get host failed * * -3 socket call failed * * -4 connect call failed */ int connect_by_number(service, host, nonblocking, oldres, oldres0) int service; u_char *host; int nonblocking; struct addrinfo **oldres; struct addrinfo **oldres0; { int s = -1; u_char buf[100]; int err = -1; u_char strhost[NI_MAXHOST], strservice[NI_MAXSERV], *serv; SOCKADDR_STORAGE *server; struct addrinfo hints, *res, *res0; if (service == -2) { server = (SOCKADDR_STORAGE *) host; if (getnameinfo((struct sockaddr *)server, SA_LEN((struct sockaddr *)server), CP(strhost), sizeof(strhost), CP(strservice), sizeof(strservice), NI_NUMERICHOST|NI_NUMERICSERV)) return -1; serv = strservice; host = strhost; } else { snprintf(CP(strservice), sizeof strservice, "%d", service); serv = strservice; if (service > 0) { if (host == (u_char *) 0) { gethostname(CP(buf), sizeof(buf)); host = buf; } } } if (oldres && *oldres && oldres0 && *oldres0) { res = *oldres; res0 = *oldres0; *oldres = 0; *oldres0 = 0; } else { memset(&hints, 0, sizeof hints); hints.ai_flags = 0; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if (service == -1) hints.ai_socktype = SOCK_DGRAM; else hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; errno = 0; err = getaddrinfo(CP(host), CP(serv), &hints, &res0); if (err != 0) return (-2); res = res0; } for (; res; res = res->ai_next) { err = 0; if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) continue; set_socket_options(s); if (source_host) { if (bind_local_addr(source_host, 0, s, res->ai_family) < 0) err = -2; else if (service <= 0 && service != -2 && listen(s, 1) == -1) err = -4; if (err) goto again; } #ifdef NON_BLOCKING_CONNECTS if (nonblocking && set_non_blocking(s) < 0) { err = -4; goto again; } #endif /* NON_BLOCKING_CONNECTS */ err = connect(s, res->ai_addr, res->ai_addrlen); if (err < 0) { if (!(errno == EINPROGRESS && nonblocking)) { err = -4; goto again; } /* * if we're non blocking, and we got an EINPROGRESS * save the res0 away so we can re-continue if this * fails to connect. */ if (oldres && oldres0) { *oldres = res->ai_next; *oldres0 = res0; res0 = 0; } err = 0; } again: if (err == 0) break; new_close(s); } if (res0) { freeaddrinfo(res0); res0 = 0; } if (err < 0) { new_close(s); return err; } return s; } /* * Binds to specified socket, host, port using specified family. * Returns: * 0 if everythins is OK * -2 if host wasn't found * -10 if family type wasn't supported for specified host */ static int bind_local_addr(localhost, localport, fd, family) u_char *localhost; u_char *localport; int fd; int family; { struct addrinfo hintsx, *resx, *res0x; int err = -1; memset(&hintsx, 0, sizeof(hintsx)); hintsx.ai_family = family; hintsx.ai_socktype = SOCK_STREAM; hintsx.ai_flags = AI_PASSIVE; err = getaddrinfo(CP(localhost), CP(localport), &hintsx, &res0x); if (err != 0) { # ifndef EAI_ADDRFAMILY # ifdef EAI_FAMILY # define EAI_ADDRFAMILY EAI_FAMILY # else # error "no EAI_ADDRFAMILY or EAI_FAMILY" # endif # endif if (err == EAI_ADDRFAMILY) return -10; else return -2; } err = -1; for (resx = res0x; resx; resx = resx->ai_next) { if (bind(fd, resx->ai_addr, resx->ai_addrlen) == 0) { err = 0; break; } } freeaddrinfo(res0x); if (err < 0) return -2; return 0; } u_char * next_arg(str, new_ptr) u_char *str, **new_ptr; { u_char *ptr; if ((ptr = sindex(str, UP("^ "))) != NULL) { if ((str = my_index(ptr, ' ')) != NULL) *str++ = (u_char) 0; else str = empty_string; } else str = empty_string; if (new_ptr) *new_ptr = str; return ptr; } u_char * new_next_arg(str, new_ptr) u_char *str, **new_ptr; { u_char *ptr, *start; if ((ptr = sindex(str, UP("^ \t"))) != NULL) { if (*ptr == '"') { start = ++ptr; while ((str = sindex(ptr, UP("\"\\"))) != NULL) { switch (*str) { case '"': *str++ = '\0'; if (*str == ' ') str++; if (new_ptr) *new_ptr = str; return (start); case '\\': if (*(str + 1) == '"') my_strcpy(str, str + 1); ptr = str + 1; } } str = empty_string; } else { if ((str = sindex(ptr, UP(" \t"))) != NULL) *str++ = '\0'; else str = empty_string; } } else str = empty_string; if (new_ptr) *new_ptr = str; return ptr; } /* my_stricmp: case insensitive version of strcmp */ int my_stricmp(str1, str2) u_char *str1, *str2; { int xor; if (!str1) return -1; if (!str2) return 1; for (; *str1 || *str2 ; str1++, str2++) { if (!*str1 || !*str2) return (*str1 - *str2); if (isalpha(*str1) && isalpha(*str2)) { xor = *str1 ^ *str2; if (xor != 32 && xor != 0) return (*str1 - *str2); } else { if (*str1 != *str2) return (*str1 - *str2); } } return 0; } /* my_strnicmp: case insensitive version of strncmp */ int my_strnicmp(str1, str2, n) u_char *str1, *str2; size_t n; { size_t i; int xor; for (i = 0; i < n; i++, str1++, str2++) { if (isalpha(*str1) && isalpha(*str2)) { xor = *str1 ^ *str2; if (xor != 32 && xor != 0) return (*str1 - *str2); } else { if (*str1 != *str2) return (*str1 - *str2); } } return 0; } /* * strmcpy: Well, it's like this, strncpy doesn't append a trailing null if * strlen(str) == maxlen. strmcpy always makes sure there is a trailing null */ void strmcpy(dest, src, maxlen) u_char *dest, *src; size_t maxlen; { my_strncpy(dest, src, maxlen); dest[maxlen-1] = '\0'; } /* * strmcat: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen+1 (for the null)) */ void strmcat(dest, src, maxlen) u_char *dest, *src; size_t maxlen; { size_t srclen, len; srclen = my_strlen(src); if ((len = my_strlen(dest) + srclen) > maxlen) my_strncat(dest, src, srclen - (len - maxlen)); else my_strcat(dest, src); } /* * strmcat_ue: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen + 1 (for the null)). Also unescapes * backslashes. */ void strmcat_ue(dest, src, maxlen) u_char *dest, *src; size_t maxlen; { size_t dstlen; dstlen = my_strlen(dest); dest += dstlen; maxlen -= dstlen; while (*src && maxlen > 0) { if (*src == '\\') { if (my_index("npr0", src[1])) *dest++ = '\020'; else if (*(src + 1)) *dest++ = *++src; else *dest++ = '\\'; } else *dest++ = *src; src++; } *dest = '\0'; } /* * scanstr: looks for an occurrence of str in source. If not found, returns * 0. If it is found, returns the position in source (1 being the first * position). Not the best way to handle this, but what the hell */ extern int scanstr(source, str) u_char *str, *source; { int i, max; size_t len; len = my_strlen(str); max = my_strlen(source) - len; for (i = 0; i <= max; i++, source++) { if (!my_strnicmp(source, str, len)) return (i + 1); } return (0); } /* expand_twiddle: expands ~ in pathnames. */ u_char * expand_twiddle(str) u_char *str; { u_char lbuf[BIG_BUFFER_SIZE]; if (*str == '~') { str++; if (*str == '/' || *str == '\0') { my_strmcpy(lbuf, my_path, sizeof lbuf); my_strmcat(lbuf, str, sizeof lbuf); } else { u_char *rest; #ifndef _Windows struct passwd *entry; #endif /* _Windows */ if ((rest = my_index(str, '/')) != NULL) *rest++ = '\0'; #ifdef _Windows if (GetProfileString("IRC", "StartDir", "", lbuf, sizeof lbuf)) { #else if ((entry = getpwnam(CP(str))) != NULL) { my_strmcpy(lbuf, entry->pw_dir, sizeof lbuf); #endif /* _Windows */ if (rest) { my_strmcat(lbuf, "/", sizeof lbuf); my_strmcat(lbuf, rest, sizeof lbuf); } } else return (u_char *) NULL; } } else my_strmcpy(lbuf, str, sizeof lbuf); str = '\0'; malloc_strcpy(&str, lbuf); return (str); } /* * sindex: much like index(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ u_char * sindex(string, group) u_char *string, *group; { u_char *ptr; if (!string || !group) return (u_char *) NULL; if (*group == '^') { group++; for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) break; } if (*ptr == '\0') return string; } } else { for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) return string; } } } return (u_char *) NULL; } /* * srindex: much like rindex(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ u_char * srindex(string, group) u_char *string, *group; { u_char *ptr, *str; if (!string || !group) return (u_char *) NULL; str = string + my_strlen(string); if (*group == '^') { group++; for (; str != (string-1); str--) { for (ptr = group; *ptr; ptr++) { if (*ptr == *str) break; } if (*ptr == '\0') return str; } } else { for (; str != (string-1); str--) { for (ptr = group; *ptr; ptr++) { if (*ptr == *str) return str; } } } return (u_char *) NULL; } /* is_number: returns true if the given string is a number, false otherwise */ int is_number(str) u_char *str; { while (*str == ' ') str++; if (*str == '-') str++; if (*str) { for (; *str; str++) { if (!isdigit((*str))) return (0); } return 1; } else return 0; } /* rfgets: exactly like fgets, cept it works backwards through a file! */ char * rfgets(lbuf, size, file) char *lbuf; int size; FILE *file; { char *ptr; off_t pos; if (fseek(file, -2L, 1)) return NULL; do { switch (fgetc(file)) { case EOF: return NULL; case '\n': pos = ftell(file); ptr = fgets(lbuf, size, file); fseek(file, (long)pos, 0); return ptr; } } while (fseek(file, -2L, 1) == 0); rewind(file); pos = 0L; ptr = fgets(lbuf, size, file); fseek(file, (long)pos, 0); return ptr; } /* * path_search: given a file called name, this will search each element of * the given path to locate the file. If found in an element of path, the * full path name of the file is returned in a static string. If not, null * is returned. Path is a colon separated list of directories */ u_char * path_search(name, path) u_char *name; u_char *path; { static u_char FAR lbuf[BIG_BUFFER_SIZE] = ""; u_char *ptr, *free_path = (u_char *) 0; malloc_strcpy(&free_path, path); path = free_path; while (path) { #ifdef __MSDOS__ if ((ptr = my_index(path, ';')) != NULL) #else if ((ptr = my_index(path, ':')) != NULL) #endif /* __MSDOS */ *(ptr++) = '\0'; lbuf[0] = 0; if (path[0] == '~') { my_strmcat(lbuf, my_path, sizeof lbuf); path++; } my_strmcat(lbuf, path, sizeof lbuf); my_strmcat(lbuf, "/", sizeof lbuf); my_strmcat(lbuf, name, sizeof lbuf); if (access(CP(lbuf), F_OK) == 0) break; path = ptr; } new_free(&free_path); return (path) ? lbuf : (u_char *) 0; } /* * double_quote: Given a str of text, this will quote any character in the * set stuff with the QUOTE_CHAR. It returns a malloced quoted, null * terminated string */ u_char * double_quote(str, stuff) u_char *str; u_char *stuff; { u_char lbuf[BIG_BUFFER_SIZE]; u_char *ptr = NULL; u_char c; int pos; if (str && stuff) { for (pos = 0; (c = *str); str++) { if (my_index(stuff, c)) { if (c == '$') lbuf[pos++] = '$'; else lbuf[pos++] = '\\'; } lbuf[pos++] = c; } lbuf[pos] = '\0'; malloc_strcpy(&ptr, lbuf); } else malloc_strcpy(&ptr, str); return ptr; } #ifdef ZCAT /* Here another interesting stuff: * it handle zcat of compressed files * You can manage compressed files in this way: * * IN: u_char *name, the compressed file FILENAME * OUT: a FILE *, from which read the expanded file * */ FILE * zcat(name) u_char *name; { FILE *fp; int in[2]; in[0] = -1; in[1] = -1; if (pipe(in)) { say("Unable to start decompression process: %s", strerror(errno)); if(in[0] != -1) { new_close(in[0]); new_close(in[1]); } return(NULL); } switch(fork()) { case -1: say("Unable to start decompression process: %s", strerror(errno)); return(NULL); case 0: (void) MY_SIGNAL(SIGINT, (sigfunc *) SIG_IGN, 0); dup2(in[1], 1); new_close(in[0]); setuid(getuid()); setgid(getgid()); #ifdef ZARGS execlp(ZCAT, ZCAT, ZARGS, name, NULL); #else execlp(ZCAT, ZCAT, name, NULL); #endif /* ZARGS */ exit(0); default: new_close(in[1]); if ((fp = fdopen(in[0], "r")) == (FILE *) 0) { say("Cannot open pipe file descriptor: %s", strerror(errno)); return(NULL); } break; } return(fp); } #endif /* ZCAT */ #ifdef NEED_INDEX extern char * index(s, c) char *s; char c; { # ifdef HAVE_STRSTR return strstr(s, c); # else int len = my_strlen(s); for (; len > 0 && c != *s; s++, len--) ; return (len) ? s : (char *) NULL; # endif /* HAVE_STRSTD */ } #endif /* NEED_INDEX */ #ifdef NEED_RINDEX extern char * rindex(s, c) char *s; char c; { # ifdef HAVE_STRRSTR return strrstr(s, c); # else int len = my_strlen(s); char *t = s; s += len; for (; s >= t && c != *s; s--) ; return (s < t) ? (char *) NULL : s; # endif /* HAVE_STRRSTR */ } #endif /* NEED_RINDEX */ #ifdef NON_BLOCKING_CONNECTS int set_non_blocking(fd) int fd; { int res, nonb = 0; #if defined(NBLOCK_POSIX) nonb |= O_NONBLOCK; #else # if defined(NBLOCK_BSD) nonb |= O_NDELAY; # else # if defined(NBLOCK_SYSV) res = 1; if (ioctl (fd, FIONBIO, &res) < 0) return -1; # else no idea how to set an fd to non-blocking # endif /* NBLOCK_SYSV */ # endif /* NBLOCK_BSD */ #endif /* NON_POSIX */ #if (defined(NBLOCK_POSIX) || defined(NBLOCK_BSD)) && !defined(NBLOCK_SYSV) if ((res = fcntl(fd, F_GETFL, 0)) == -1) return -1; else if (fcntl(fd, F_SETFL, res | nonb) == -1) return -1; #endif /* (NBLOCK_POSIX || NBLOCK_BSD) && !NBLOCK_SYSV */ return 0; } int set_blocking(fd) int fd; { int res, nonb = 0; #if defined(NBLOCK_POSIX) nonb |= O_NONBLOCK; #else # if defined(NBLOCK_BSD) nonb |= O_NDELAY; # else # if defined(NBLOCK_SYSV) res = 0; if (ioctl (fd, FIONBIO, &res) < 0) return -1; # else no idea how to return an fd blocking # endif /* NBLOCK_SYSV */ # endif /* NBLOCK_BSD */ #endif /* NBLOCK_POSIX */ #if (defined(NBLOCK_POSIX) || defined(NBLOCK_BSD)) && !defined(NBLOCK_SYSV) if ((res = fcntl(fd, F_GETFL, 0)) == -1) return -1; else if (fcntl(fd, F_SETFL, res &~ nonb) == -1) return -1; #endif /* (NBLOCK_POSIX || NBLOCK_BSD) && !NBLOCK_SYSV */ return 0; } #endif /* NON_BLOCKING_CONNECTS */