Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_porting_c = 00003 * "$Id: porting.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2006 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00038 #include <string.h> 00039 #ifdef WIN32 /* ---win32 exclude/include headers */ 00040 #include "process.h" 00041 #define pid_t int /* we include it non global, because there is a redefinition in python.h */ 00042 #else 00043 #include <ctype.h> 00044 #include <errno.h> 00045 #include <sys/stat.h> 00046 #include <sys/wait.h> 00047 00048 #include <sys/param.h> 00049 #include <stdio.h> 00050 00051 /* Need to pull in the HAVE_... values somehow */ 00052 /* win32 reminder: always put this in a ifndef win32 block */ 00053 #include <autoconf.h> 00054 #endif 00055 00056 #ifdef HAVE_STDLIB_H 00057 #include <stdlib.h> 00058 #endif 00059 00060 #ifdef HAVE_UNISTD_H 00061 #include <unistd.h> 00062 #endif 00063 00064 #include <stdarg.h> 00065 /* Has to be after above includes so we don't redefine some values */ 00066 #include "global.h" 00067 00069 static unsigned int curtmp = 0; 00070 00071 /***************************************************************************** 00072 * File related functions 00073 ****************************************************************************/ 00074 00087 char *tempnam_local(const char *dir, const char *pfx) { 00088 char *name; 00089 pid_t pid = getpid(); 00090 00091 /* HURD does not have a hard limit, but we do */ 00092 #ifndef MAXPATHLEN 00093 #define MAXPATHLEN 4096 00094 #endif 00095 00096 if (!pfx) 00097 pfx = "cftmp."; 00098 00099 /* This is a pretty simple method - put the pid as a hex digit and 00100 * just keep incrementing the last digit. Check to see if the file 00101 * already exists - if so, we'll just keep looking - eventually we should 00102 * find one that is free. 00103 */ 00104 if (dir != NULL) { 00105 if (!(name = (char *)malloc(MAXPATHLEN))) 00106 return(NULL); 00107 do { 00108 #ifdef HAVE_SNPRINTF 00109 (void)snprintf(name, MAXPATHLEN, "%s/%s%hx.%u", dir, pfx, pid, curtmp); 00110 #else 00111 (void)sprintf(name, "%s/%s%hx%u", dir, pfx, pid, curtmp); 00112 #endif 00113 curtmp++; 00114 } while (access(name, F_OK) != -1); 00115 return(name); 00116 } 00117 return(NULL); 00118 } 00119 00143 FILE *tempnam_secure(const char *dir, const char *pfx, char **filename) { 00144 char *tempname = NULL; 00145 int fd; 00146 int i; 00147 FILE *file = NULL; 00148 #define MAXTMPRETRY 10 00149 00150 /* Limit number of retries to MAXRETRY */ 00151 for (i = 0; i < MAXTMPRETRY; i++) { 00152 tempname = tempnam_local(dir, pfx); 00153 /* tempnam_local only fails for really bad stuff, so lets bail out right 00154 * away then. 00155 */ 00156 if (!tempname) 00157 return NULL; 00158 00159 fd = open(tempname, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); 00160 if (fd != -1) 00161 break; 00162 if (errno == EEXIST) 00163 LOG(llevError, "Created file detected in tempnam_secure. Someone hoping for a race condition?\n"); 00164 free(tempname); 00165 } 00166 /* Check that we successfully got an fd. */ 00167 if (fd == -1) 00168 return NULL; 00169 00170 file = fdopen(fd, "w+"); 00171 if (!file) { 00172 LOG(llevError, "fdopen() failed in tempnam_secure()!\n"); 00173 free(tempname); 00174 return NULL; 00175 } 00176 00177 *filename = tempname; 00178 return file; 00179 } 00180 00192 void remove_directory(const char *path) { 00193 DIR *dirp; 00194 char buf[MAX_BUF]; 00195 struct stat statbuf; 00196 int status; 00197 00198 if ((dirp = opendir(path)) != NULL) { 00199 struct dirent *de; 00200 00201 for (de = readdir(dirp); de; de = readdir(dirp)) { 00202 /* Don't remove '.' or '..' In theory we should do a better 00203 * check for .., but the directories we are removing are fairly 00204 * limited and should not have dot files in them. 00205 */ 00206 if (de->d_name[0] == '.') 00207 continue; 00208 00209 /* Linux actually has a type field in the dirent structure, 00210 * but that is not portable - stat should be portable 00211 */ 00212 status = stat(de->d_name, &statbuf); 00213 if ((status != -1) && (S_ISDIR(statbuf.st_mode))) { 00214 snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name); 00215 remove_directory(buf); 00216 continue; 00217 } 00218 snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name); 00219 if (unlink(buf)) { 00220 LOG(llevError, "Unable to remove %s\n", path); 00221 } 00222 } 00223 closedir(dirp); 00224 } 00225 if (rmdir(path)) { 00226 LOG(llevError, "Unable to remove directory %s\n", path); 00227 } 00228 } 00229 00230 #if defined(sgi) 00231 00232 #include <stdio.h> 00233 #include <stdlib.h> 00234 #include <string.h> 00235 00236 #define popen fixed_popen 00237 00253 FILE *popen_local(const char *command, const char *type) { 00254 int fd[2]; 00255 int pd; 00256 FILE *ret; 00257 if (!strcmp(type, "r")) { 00258 pd = STDOUT_FILENO; 00259 } else if (!strcmp(type, "w")) { 00260 pd = STDIN_FILENO; 00261 } else { 00262 return NULL; 00263 } 00264 if (pipe(fd) != -1) { 00265 switch (fork()) { 00266 case -1: 00267 close(fd[0]); 00268 close(fd[1]); 00269 break; 00270 00271 case 0: 00272 close(fd[0]); 00273 if ((fd[1] == pd) || (dup2(fd[1], pd) == pd)) { 00274 if (fd[1] != pd) { 00275 close(fd[1]); 00276 } 00277 execl("/bin/sh", "sh", "-c", command, NULL); 00278 close(pd); 00279 } 00280 exit(1); 00281 break; 00282 00283 default: 00284 close(fd[1]); 00285 if (ret = fdopen(fd[0], type)) { 00286 return ret; 00287 } 00288 close(fd[0]); 00289 break; 00290 } 00291 } 00292 return NULL; 00293 } 00294 00295 #endif /* defined(sgi) */ 00296 00297 /***************************************************************************** 00298 * String related function 00299 ****************************************************************************/ 00300 00310 char *strdup_local(const char *str) { 00311 char *c = (char *)malloc(strlen(str)+1); 00312 if (c != NULL) 00313 strcpy(c, str); 00314 return c; 00315 } 00316 00318 #define DIGIT(x) (isdigit(x) ? (x)-'0' : \ 00319 islower(x) ? (x)+10-'a' : (x)+10-'A') 00320 #define MBASE ('z'-'a'+1+10) 00321 00322 #if !defined(HAVE_STRTOL) 00323 00339 long strtol(register char *str, char **ptr, register int base) { 00340 register long val; 00341 register int c; 00342 int xx, neg = 0; 00343 00344 if (ptr != (char **)0) 00345 *ptr = str; /* in case no number is formed */ 00346 if (base < 0 || base > MBASE) 00347 return (0); /* base is invalid */ 00348 if (!isalnum(c = *str)) { 00349 while (isspace(c)) 00350 c = *++str; 00351 switch (c) { 00352 case '-': 00353 neg++; 00354 case '+': 00355 c = *++str; 00356 } 00357 } 00358 if (base == 0) { 00359 if (c != '0') 00360 base = 10; 00361 else { 00362 if (str[1] == 'x' || str[1] == 'X') 00363 base = 16; 00364 else 00365 base = 8; 00366 } 00367 } 00368 /* 00369 * For any base > 10, the digits incrementally following 00370 * 9 are assumed to be "abc...z" or "ABC...Z" 00371 */ 00372 if (!isalnum(c) || (xx = DIGIT(c)) >= base) 00373 return 0; /* no number formed */ 00374 if (base == 16 && c == '0' && isxdigit(str[2]) && (str[1] == 'x' || str[1] == 'X')) 00375 c = *(str += 2); /* skip over leading "0x" or "0X" */ 00376 for (val = -DIGIT(c); isalnum(c = *++str) && (xx = DIGIT(c)) < base; ) 00377 /* accumulate neg avoids surprises near 00378 MAXLONG */ 00379 val = base*val-xx; 00380 if (ptr != (char **)0) 00381 *ptr = str; 00382 return (neg ? val : -val); 00383 } 00384 #endif 00385 00401 #if !defined(HAVE_STRNCASECMP) 00402 int strncasecmp(const char *s1, const char *s2, int n) { 00403 register int c1, c2; 00404 00405 while (*s1 && *s2 && n) { 00406 c1 = tolower(*s1); 00407 c2 = tolower(*s2); 00408 if (c1 != c2) 00409 return (c1-c2); 00410 s1++; 00411 s2++; 00412 n--; 00413 } 00414 if (!n) 00415 return (0); 00416 return (int)(*s1-*s2); 00417 } 00418 #endif 00419 00420 #if !defined(HAVE_STRCASECMP) 00421 00434 int strcasecmp(const char *s1, const char *s2) { 00435 register int c1, c2; 00436 00437 while (*s1 && *s2) { 00438 c1 = tolower(*s1); 00439 c2 = tolower(*s2); 00440 if (c1 != c2) 00441 return (c1-c2); 00442 s1++; 00443 s2++; 00444 } 00445 if (*s1 == '\0' && *s2 == '\0') 00446 return 0; 00447 return (int)(*s1-*s2); 00448 } 00449 #endif 00450 00461 const char *strcasestr_local(const char *s, const char *find) { 00462 char c, sc; 00463 size_t len; 00464 00465 if ((c = *find++) != 0) { 00466 c = tolower(c); 00467 len = strlen(find); 00468 do { 00469 do { 00470 if ((sc = *s++) == 0) 00471 return NULL; 00472 } while (tolower(sc) != c); 00473 } while (strncasecmp(s, find, len) != 0); 00474 s--; 00475 } 00476 return s; 00477 } 00478 00479 #if !defined(HAVE_SNPRINTF) 00480 00498 int snprintf(char *dest, int max, const char *format, ...) { 00499 va_list var; 00500 int ret; 00501 00502 va_start(var, format); 00503 ret = vsprintf(dest, format, var); 00504 va_end(var); 00505 if (ret > max) 00506 abort(); 00507 00508 return ret; 00509 } 00510 #endif 00511 00525 char *strerror_local(int errnum, char *buf, size_t size) { 00526 #if defined(HAVE_STRERROR_R) 00527 /* Then what flavour of strerror_r... */ 00528 # if defined(STRERROR_R_CHAR_P) 00529 char *bbuf; 00530 00531 buf[0] = 0; 00532 bbuf = (char *)strerror_r(errnum, buf, size); 00533 if ((buf[0] == 0) && (bbuf != NULL)) 00534 strncpy(buf, bbuf, size); 00535 # else 00536 if (strerror_r(errnum, buf, size) != 0) { 00537 /* EINVAL and ERANGE are possible errors from this strerror_r */ 00538 if (errno == ERANGE) { 00539 strncat(buf, "Too small buffer.", size); 00540 } else if (errno == EINVAL) { 00541 strncat(buf, "Error number invalid.", size); 00542 } 00543 } 00544 # endif /* STRERROR_R_CHAR_P */ 00545 00546 #else /* HAVE_STRERROR_R */ 00547 00548 # if defined(HAVE_STRERROR) 00549 snprintf(buf, size, "%s", strerror(errnum)); 00550 # else 00551 # error If this is C89 the compiler should have strerror!; 00552 # endif 00553 #endif /* HAVE_STRERROR_R */ 00554 return buf; 00555 } 00556 00573 int isqrt(int n) { 00574 int result, sum, prev; 00575 00576 result = 0; 00577 prev = sum = 1; 00578 while (sum <= n) { 00579 prev += 2; 00580 sum += prev; 00581 ++result; 00582 } 00583 return result; 00584 } 00585 00593 const char *uncomp[NROF_COMPRESS_METHODS][3] = { 00594 { NULL, NULL, NULL }, 00595 { ".Z", UNCOMPRESS, COMPRESS }, 00596 { ".gz", GUNZIP, GZIP }, 00597 { ".bz2", BUNZIP, BZIP } 00598 }; 00599 00621 static FILE *open_and_uncompress_file(const char *ext, const char *uncompressor, const char *name, int flag, int *compressed) { 00622 struct stat st; 00623 char buf[MAX_BUF]; 00624 char buf2[MAX_BUF]; 00625 int ret; 00626 00627 if (ext == NULL) { 00628 ext = ""; 00629 } 00630 00631 if (strlen(name)+strlen(ext) >= sizeof(buf)) { 00632 errno = ENAMETOOLONG; /* File name too long */ 00633 return NULL; 00634 } 00635 snprintf(buf, sizeof(buf), "%s%s", name, ext); 00636 00637 if (stat(buf, &st) != 0) { 00638 return NULL; 00639 } 00640 00641 if (!S_ISREG(st.st_mode)) { 00642 errno = EISDIR; /* Not a regular file */ 00643 return NULL; 00644 } 00645 00646 if (uncompressor == NULL) { 00647 /* open without uncompression */ 00648 return fopen(buf, "rb"); 00649 } 00650 00651 /* The file name buf (and its substring name) is passed as an argument to a 00652 * shell command, therefore check for characters that could confuse the 00653 * shell. 00654 */ 00655 if (strpbrk(buf, "'\\\r\n") != NULL) { 00656 errno = ENOENT; /* Pretend the file does not exist */ 00657 return NULL; 00658 } 00659 00660 if (!flag) { 00661 /* uncompress via pipe */ 00662 00663 if (strlen(uncompressor)+4+strlen(buf)+1 >= sizeof(buf2)) { 00664 errno = ENAMETOOLONG; /* File name too long */ 00665 return NULL; 00666 } 00667 snprintf(buf2, sizeof(buf2), "%s < '%s'", uncompressor, buf); 00668 return popen(buf2, "r"); 00669 } 00670 00671 /* remove compression from file, then open file */ 00672 00673 if (stat(name, &st) == 0 && !S_ISREG(st.st_mode)) { 00674 errno = EISDIR; 00675 return NULL; 00676 } 00677 00678 if (strlen(uncompressor)+4+strlen(buf)+5+strlen(name)+1 >= sizeof(buf2)) { 00679 errno = ENAMETOOLONG; /* File name too long */ 00680 return NULL; 00681 } 00682 snprintf(buf2, sizeof(buf2), "%s < '%s' > '%s'", uncompressor, buf, name); 00683 00684 ret = system(buf2); 00685 if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) { 00686 LOG(llevError, "system(%s) returned %d\n", buf2, ret); 00687 errno = ENOENT; 00688 return NULL; 00689 } 00690 00691 unlink(buf); /* Delete the original */ 00692 *compressed = 0; /* Change to "uncompressed file" */ 00693 chmod(name, st.st_mode); /* Copy access mode from compressed file */ 00694 00695 return fopen(name, "rb"); 00696 } 00697 00724 FILE *open_and_uncompress(const char *name, int flag, int *compressed) { 00725 size_t i; 00726 FILE *fp; 00727 00728 for (i = 0; i < NROF_COMPRESS_METHODS; i++) { 00729 *compressed = i; 00730 fp = open_and_uncompress_file(uncomp[i][0], uncomp[i][1], name, flag, compressed); 00731 if (fp != NULL) { 00732 return fp; 00733 } 00734 } 00735 00736 errno = ENOENT; 00737 return NULL; 00738 } 00739 00748 void close_and_delete(FILE *fp, int compressed) { 00749 if (compressed) 00750 pclose(fp); 00751 else 00752 fclose(fp); 00753 } 00754 00764 void make_path_to_file(const char *filename) { 00765 char buf[MAX_BUF], *cp = buf; 00766 struct stat statbuf; 00767 00768 if (!filename || !*filename) 00769 return; 00770 00771 strcpy(buf, filename); 00772 LOG(llevDebug, "make_path_tofile %s...\n", filename); 00773 while ((cp = strchr(cp+1, (int)'/'))) { 00774 *cp = '\0'; 00775 if (stat(buf, &statbuf) || !S_ISDIR(statbuf.st_mode)) { 00776 LOG(llevDebug, "Was not dir: %s\n", buf); 00777 if (mkdir(buf, SAVE_DIR_MODE)) { 00778 char err[MAX_BUF]; 00779 00780 LOG(llevError, "Cannot mkdir %s: %s\n", buf, strerror_local(errno, err, sizeof(err))); 00781 return; 00782 } 00783 } 00784 *cp = '/'; 00785 } 00786 }