/* * 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-2000 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("@(#)$Id: ircaux.c,v 1.71 2000/08/06 14:26:07 mrg Exp $"); #if defined(ESIX) || defined(MIPS_SYSV) # define _TERMIOS_INCLUDED # define _INCLUDE_TERMIO # include #endif /* ESIX || 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" #ifdef INET6 extern u_char FAR MyHostName[]; #else extern struct in_addr MyHostAddr; #endif extern u_char *source_host; 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 */ if (*ptr == empty_string) *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; { /* no point doing anything else */ if (src == *ptr) return; new_free(ptr); if (src) { *ptr = new_malloc(my_strlen(src) + 1); my_strcpy(*ptr, src); } else *ptr = (u_char *) 0; } /* malloc_strcat: Yeah, right */ void malloc_strcat(ptr, src) u_char **ptr; u_char *src; { u_char *new; if (*ptr) { new = (u_char *) new_malloc(my_strlen(*ptr) + my_strlen(src) + 1); 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 * * -1 Create a UDP socket * * -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) int service; u_char *host; int nonblocking; { int s = -1; u_char buf[100]; int err = -1; #ifndef INET6 struct sockaddr_in server; struct hostent *hp; #else u_char strhost[1025], strservice[32]; struct sockaddr_storage server; struct addrinfo hints, *res, *res0; my_strncpy(strhost, host, sizeof(strhost) - 1); strhost[sizeof(strhost) - 1] = 0; sprintf(strservice, "%d", service); strservice[sizeof(strservice) - 1] = 0; #endif if (service == -2) { #ifdef INET6 #ifndef SA_LEN # ifdef HAVE_SOCKADDR_SA_LEN # define SA_LEN(x) (x)->sa_len # else # ifdef SIN6_LEN # define SA_LEN(x) SIN6_LEN(x) # else # ifdef SIN_LEN # define SA_LEN(x) SIN_LEN(x) # else # define SA_LEN(x) sizeof(*x) # endif # endif # endif #endif server = (*(struct sockaddr_storage *) host); getnameinfo((struct sockaddr *)&server, SA_LEN((struct sockaddr *)&server), strhost, sizeof(strhost), strservice, sizeof(strservice), NI_NUMERICHOST|NI_NUMERICSERV); #else server = (*(struct sockaddr_in *) host); #endif } else if (service > 0) { if (host == (u_char *) 0) { gethostname(CP(buf), sizeof(buf)); host = buf; } #ifndef INET6 if ((server.sin_addr.s_addr = inet_addr(CP(host))) == -1) { if ((hp = gethostbyname(CP(host))) != NULL) { bzero((char *) &server, sizeof(server)); bcopy(hp->h_addr, (char *) &server.sin_addr, (size_t)hp->h_length); server.sin_family = hp->h_addrtype; } else return (-2); } else server.sin_family = AF_INET; server.sin_port = (unsigned short) htons(service); #endif } #ifdef INET6 memset(&hints, 0, sizeof(hints)); if (service == -1) hints.ai_socktype = SOCK_DGRAM; else hints.ai_socktype = SOCK_STREAM; /* If strhost is empty then probably DCC connection was requested. * In this case we must use AF_INET */ errno = 0; if (my_strlen(strhost) == 0) { hints.ai_family = AF_INET; err = getaddrinfo(NULL, strservice, &hints, &res0); } else { hints.ai_family = AF_UNSPEC; err = getaddrinfo(strhost, strservice, &hints, &res0); } if (err != 0) { #if 0 /* zero errno to get "unknown host" error message */ errno = 0; #endif return (-2); } err = -1; for (res = res0; res; res = res->ai_next) { if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) continue; if (service != -1) set_socket_options(s); #else if (((service == -1) && ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)) || ((service != -1) && ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0))) return (-3); if (service != -1) set_socket_options(s); #endif if (service <= 0 && service != -2) { #ifdef INET6 if (bind_local_addr(NULL, "0", s, res->ai_family) < 0) return -2; freeaddrinfo(res0); if (listen(s, 1) == -1) { new_close(s); return -4; } #else struct sockaddr_in localaddr; bzero(&localaddr, sizeof(struct sockaddr_in)); localaddr.sin_family = AF_INET; if (!service) localaddr.sin_addr.s_addr = INADDR_ANY; else localaddr.sin_addr = MyHostAddr; localaddr.sin_port = 0; if (bind(s, (struct sockaddr *) &localaddr, sizeof(localaddr)) == -1 || (!service && listen(s, 1) == -1)) { new_close(s); return -4; } service = sizeof(localaddr); getsockname(s, (struct sockaddr *) &localaddr, &service); #endif return (s); } if (source_host) { #ifdef INET6 int retcode; if ((retcode = bind_local_addr(MyHostName, "0", s, res->ai_family)) < 0) { /* this fail must be ignored because maybe * res->ai_family != MyHostName's family (ie. hapens in DCC req) */ if (retcode != -10) { freeaddrinfo(res0); return -3; } } #else struct sockaddr_in localaddr; bzero(&localaddr, sizeof localaddr); localaddr.sin_family = AF_INET; localaddr.sin_addr = MyHostAddr; if (bind(s, (struct sockaddr *)&localaddr, sizeof localaddr) == -1) return -3; #endif } #ifdef NON_BLOCKING_CONNECTS if (nonblocking && set_non_blocking(s) < 0) { #ifdef INET6 freeaddrinfo(res0); #endif # ifdef ESIX t_close(s); unmark_socket(s); # endif /* ESIX */ new_close(s); return -4; } #endif /* NON_BLOCKING_CONNECTS */ #ifdef INET6 err = connect(s, res->ai_addr, res->ai_addrlen); #else err = connect(s, (struct sockaddr *) &server, sizeof(server)); #endif if (err < 0) { if (!(errno == EINPROGRESS && nonblocking)) { #ifdef INET6 continue; #endif #ifdef ESIX t_close(s); unmark_socket(s); #endif /* ESIX */ new_close(s); return -4; } #ifdef INET6 err = 0; break; #endif } #ifdef INET6 } /* for () */ if (err < 0) { #ifdef ESIX t_close(s); unmark_socket(s); #endif /* ESIX */ new_close(s); return -4; } #endif return s; } #ifdef INET6 /* * 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(localhost, localport, &hintsx, &res0x); if (err != 0) #if defined(__linux__) && 0 /* * Due to bug in glibc implementation in getaddrinfo() we always * return -10. This will be fixed, soon */ return -10; #else { if (err == EAI_ADDRFAMILY) return -10; else return -2; } #endif 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; } #endif 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] = '\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 + 1]; if (*str == '~') { str++; if (*str == '/' || *str == '\0') { my_strmcpy(lbuf, my_path, BIG_BUFFER_SIZE); my_strmcat(lbuf, str, BIG_BUFFER_SIZE); } 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, BIG_BUFFER_SIZE)) { #else if ((entry = getpwnam(CP(str))) != NULL) { my_strmcpy(lbuf, entry->pw_dir, BIG_BUFFER_SIZE); #endif /* _Windows */ if (rest) { my_strmcat(lbuf, "/", BIG_BUFFER_SIZE); my_strmcat(lbuf, rest, BIG_BUFFER_SIZE); } } else return (u_char *) NULL; } } else my_strmcpy(lbuf, str, BIG_BUFFER_SIZE); 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 + 1] = ""; 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'; my_strcpy(lbuf, empty_string); if (path[0] == '~') { my_strmcat(lbuf, my_path, BIG_BUFFER_SIZE); path++; } my_strmcat(lbuf, path, BIG_BUFFER_SIZE); my_strmcat(lbuf, "/", BIG_BUFFER_SIZE); my_strmcat(lbuf, name, BIG_BUFFER_SIZE); 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 + 1]; 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; } /* * new_stty: given a string of stty commands sets the tty * via ioctls TCGETA/TCSETA. * * WARNING: if someone of the architectures specified in * #if statement don't work ... please comment out * the relative statement and send a report to * * mez002@cdc835.cdc.polimi.it or * rfac@ghost.unimi.it * * or talk with me on IRC ... (i think is better) * * - Allanon - * */ void new_stty(option) u_char *option; { #if defined(ESIX) || defined(MIPS_SYSV) struct termio ttyset; ioctl(0, TCGETA, &ttyset); if (strstr(option, "opost")) ttyset.c_oflag |= OPOST; if (strstr(option, "sane")) { ttyset.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF); ttyset.c_lflag &= ~(XCASE | ECHOE | ECHONL | NOFLSH); ttyset.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY); ttyset.c_iflag |= (BRKINT | IGNPAR | ISTRIP | ICRNL | IXON); ttyset.c_lflag |= (ISIG | ICANON | ECHO | ECHOK); ttyset.c_oflag |= (OPOST | ONLCR); ttyset.c_cc[VERASE] = CERASE; ttyset.c_cc[VKILL] = CKILL; ttyset.c_cc[VQUIT] = CQUIT; ttyset.c_cc[VINTR] = CINTR; ttyset.c_cc[VEOF] = CEOF; ttyset.c_cc[VEOL] = CNUL; ttyset.c_cc[VSWTCH] = CNUL; } if (strstr(option, "cooked")) /* cooked == -raw */ { ttyset.c_cflag &= ~CSIZE; ttyset.c_cflag |= PARENB; ttyset.c_iflag |= (BRKINT | IGNPAR | ISTRIP | IXON); ttyset.c_oflag |= OPOST; ttyset.c_lflag |= (ICANON | ISIG); ttyset.c_cc[VEOF] = CEOF; ttyset.c_cc[VEOL] = CNUL; } if (strstr(option, "raw")) { ttyset.c_cflag &= ~(CSIZE | PARENB); ttyset.c_iflag &= ~(-1); ttyset.c_lflag &= ~(ISIG | ICANON | XCASE); ttyset.c_oflag &= ~OPOST; ttyset.c_cflag |= CS8; ttyset.c_cc[VMIN] = 1; ttyset.c_cc[VTIME] = 1; } if (strstr(option, "-echo")) ttyset.c_lflag &= ~ECHO; ioctl(0, TCSETAW, &ttyset); #endif /* ESIX || MIPS_SYSV */ } #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 */ .