/* * Copyright © 2001 Novell, Inc. All Rights Reserved. * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */ /* * FILENAME : nw5.c * DESCRIPTION : Definitions for the redefined functions for NetWare. * Author : SGP, HYAK * Date : January 2001. * */ #include // For dTHX, etc. #include "nwpipe.h" // This was added since the compile failed saying "undefined P_WAIT" // when USE_ITHREADS was commented in the makefile #ifndef P_WAIT #define P_WAIT 0 #endif #ifndef P_NOWAIT #define P_NOWAIT 1 #endif #define EXECF_EXEC 1 #define EXECF_SPAWN 2 #define EXECF_SPAWN_NOWAIT 3 static BOOL has_shell_metachars(char *ptr); // The array is used to store pointer to the memory allocated to the TempPipeFile structure everytime // a call to the function, nw_Popen. If a simple variable is used, everytime the memory is allocated before // the previously allocated memory is freed, the pointer will get overwritten and the previous memory allocations // are lost! Only the most recent one will get freed when calls are made to nw_Pclose. // By using the array and the iPopenCount to index the array, all memory are freed! // The size of the array indicates the limit on the no of times the nw_Popen function can be called (and // memory allocted) from within a script through backtick operators! // This is arbitrarily set to MAX_PIPE_RECURSION=256 which indicates there can be 256 nested backtick operators possible! PTEMPPIPEFILE ptpf1[MAX_PIPE_RECURSION] = {'\0'}; int iPopenCount = 0; FILE* File1[MAX_PIPE_RECURSION] = {'\0'}; /** General: In this code, wherever there is a FILE *, the error condition is checked; and only if the FILE * is TRUE, then the corresponding operation is done. Otherwise the error value is returned. This is done because the file operations like "open" in the Perl code returns the FILE *, returning a valid value if the file is found or NULL when the particular file is not found. Now, if the return value is NULL, then an operation say "fgets", "fopen" etc. using this this NULL value for FILE * will abend the server. If the check is made then an operation on a non existing file does not abend the server. **/ void nw_abort(void) { abort(); // Terminate the NLM application abnormally. return; } int nw_access(const char *path, int mode) { return access(path, mode); } int nw_chmod(const char *path, int mode) { return chmod(path, mode); } void nw_clearerr(FILE *pf) { if(pf) clearerr(pf); } int nw_close(int fd) { return close(fd); } nw_closedir(DIR *dirp) { return (closedir(dirp)); } void nw_setbuf(FILE *pf, char *buf) { if(pf) setbuf(pf, buf); } int nw_setmode(FILE *fp, int mode) { /** // Commented since a few abends were happening in fnFpSetMode int *dummy = 0; return(fnFpSetMode(fp, mode, dummy)); **/ int handle = -1; errno = 0; handle = fileno(fp); if (errno) { errno = 0; return -1; } return setmode(handle, mode); } int nw_setvbuf(FILE *pf, char *buf, int type, size_t size) { if(pf) return setvbuf(pf, buf, type, size); else return -1; } unsigned int nw_sleep(unsigned int t) { delay(t*1000); // Put the thread to sleep for 't' seconds. Initially 't' is passed in milliseconds. return 0; } int nw_spawnvp(int mode, char *cmdname, char **argv) { // There is no pass-around environment on NetWare so we throw that // argument away for now. // The function "spawnvp" does not work in all situations. Loading // edit.nlm seems to work, for example, but the name of the file // to edit does not appear to get passed correctly. Another problem // is that on Netware, P_WAIT does not really work reliably. It only // works with NLMs built to use CLIB (according to Nile Thayne). // NLMs such as EDIT that are written directly to the system have no // way of running synchronously from another process. The whole // architecture on NetWare seems pretty busted, so we just support it // as best we can. // // The spawnvp function only launches NLMs, it will not execute a command; // the NetWare "system" function is used for that purpose. Unfortunately, "system" // always returns success whether the command is successful or not or even // if the command was not found! To avoid ambiguity--you can have both an // NLM named "perl" and a system command named "perl"--we need to // force perl scripts to carry the word "load" when loading an NLM. This // might be clearer anyway. int ret = 0; int argc = 0; if (stricmp(cmdname, LOAD_COMMAND) == 0) { if (argv[1] != NULL) ret = spawnvp(mode, argv[1], &argv[1]); } else { int i=0; while (argv[i] != '\0') i++; argc = i; fnSystemCommand(argv, argc); } return ret; } int nw_execv(char *cmdname, char **argv) { return spawnvp(P_WAIT, cmdname, (char **)argv); } int nw_execvp(char *cmdname, char **argv) { return nw_spawnvp(P_WAIT, cmdname, (char **)argv); } int nw_stat(const char *path, struct stat *sbuf) { return (stat(path, sbuf)); } FILE * nw_stderr(void) { return (stderr); } FILE * nw_stdin(void) { return (stdin); } FILE * nw_stdout() { return (stdout); } long nw_telldir(DIR *dirp) { dTHX; Perl_croak(aTHX_ "The telldir() function is not implemented on NetWare\n"); return 0l; } int nw_times(struct tms *timebuf) { clock_t now = clock(); timebuf->tms_utime = now; timebuf->tms_stime = 0; timebuf->tms_cutime = 0; timebuf->tms_cstime = 0; return 0; } FILE* nw_tmpfile(void) { return tmpfile(); } int nw_uname(struct utsname *name) { return(uname(name)); } int nw_ungetc(int c, FILE *pf) { if(pf) return ungetc(c, pf); else return -1; } int nw_unlink(const char *filename) { return(unlink(filename)); } int nw_utime(const char *filename, struct utimbuf *times) { return(utime(filename, times)); } int nw_vfprintf(FILE *fp, const char *format, va_list args) { if(fp) return (vfprintf(fp, format, args)); else return -1; } int nw_wait(int *status) { return 0; } int nw_waitpid(int pid, int *status, int flags) { return 0; } int nw_write(int fd, const void *buf, unsigned int cnt) { return write(fd, buf, cnt); } char * nw_crypt(const char *txt, const char *salt) { dTHX; #ifdef HAVE_DES_FCRYPT dTHR; return des_fcrypt(txt, salt, w32_crypt_buffer); #else Perl_croak(aTHX_ "The crypt() function is not implemented on NetWare\n"); return NULL; #endif } int nw_dup(int fd) { return dup(fd); } int nw_dup2(int fd1,int fd2) { return dup2(fd1,fd2); } void* nw_dynaload(const char* filename) { return NULL; } int nw_fclose(FILE *pf) { if(pf) return (fclose(pf)); else return -1; } FILE * nw_fdopen(int handle, const char *mode) { return(fdopen(handle, mode)); } int nw_feof(FILE *fp) { if(fp) return (feof(fp)); else return -1; } int nw_ferror(FILE *fp) { if(fp) return (ferror(fp)); else return -1; } int nw_fflush(FILE *pf) { if(pf) return fflush(pf); else return -1; } int nw_fgetpos(FILE *pf, fpos_t *p) { if(pf) return fgetpos(pf, p); else return -1; } char* nw_fgets(char *s, int n, FILE *pf) { if(pf) return(fgets(s, n, pf)); else return NULL; } int nw_fileno(FILE *pf) { if(pf) return fileno(pf); else return -1; } int nw_flock(int fd, int oper) { dTHX; Perl_croak(aTHX_ "The flock() function is not implemented on NetWare\n"); return 0; } FILE * nw_fopen(const char *filename, const char *mode) { return (fopen(filename, mode)); } int nw_fputc(int c, FILE *pf) { if(pf) return fputc(c,pf); else return -1; } int nw_fputs(const char *s, FILE *pf) { if(pf) return fputs(s, pf); else return -1; } size_t nw_fread(void *buf, size_t size, size_t count, FILE *fp) { if(fp) return fread(buf, size, count, fp); else return -1; } FILE * nw_freopen(const char *path, const char *mode, FILE *stream) { if(stream) return freopen(path, mode, stream); else return NULL; } int nw_fseek(FILE *pf, long offset, int origin) { if(pf) return (fseek(pf, offset, origin)); else return -1; } int nw_fsetpos(FILE *pf, const fpos_t *p) { if(pf) return fsetpos(pf, p); else return -1; } long nw_ftell(FILE *pf) { if(pf) return ftell(pf); else return -1; } size_t nw_fwrite(const void *buf, size_t size, size_t count, FILE *fp) { if(fp) return fwrite(buf, size, count, fp); else return -1; } long nw_get_osfhandle(int fd) { return 0l; } int nw_getc(FILE *pf) { if(pf) return getc(pf); else return -1; } int nw_putc(int c, FILE *pf) { if(pf) return putc(c,pf); else return -1; } int nw_fgetc(FILE *pf) { if(pf) return fgetc(pf); else return -1; } int nw_getpid(void) { return GetThreadGroupID(); } int nw_kill(int pid, int sig) { return 0; } int nw_link(const char *oldname, const char *newname) { return 0; } long nw_lseek(int fd, long offset, int origin) { return lseek(fd, offset, origin); } int nw_chdir(const char *dir) { return chdir(dir); } int nw_rmdir(const char *dir) { return rmdir(dir); } DIR * nw_opendir(const char *filename) { char *buff = NULL; int len = 0; DIR *ret = NULL; len = strlen(filename); buff = malloc(len + 5); if (buff) { strcpy(buff, filename); if (buff[len-1]=='/' || buff[len-1]=='\\') { buff[--len] = 0; } strcpy(buff+len, "/*.*"); ret = opendir(buff); free (buff); buff = NULL; return ret; } else { return NULL; } } int nw_open(const char *path, int flag, ...) { va_list ap; int pmode = -1; va_start(ap, flag); pmode = va_arg(ap, int); va_end(ap); if (stricmp(path, "/dev/null")==0) path = "NWNUL"; return open(path, flag, pmode); } int nw_open_osfhandle(long handle, int flags) { return 0; } unsigned long nw_os_id(void) { return 0l; } int nw_Pipe(int* a, int* e) { int ret = 0; errno = 0; ret = pipe(a); if(errno) e = &errno; return ret; } FILE* nw_Popen(char* command, char* mode, int* e) { int i = -1; FILE* ret = NULL; PTEMPPIPEFILE ptpf = NULL; // this callback is supposed to call _popen, which spawns an // asynchronous command and opens a pipe to it. The returned // file handle can be read or written to; if read, it represents // stdout of the called process and will return EOF when the // called process finishes. If written to, it represents stdin // of the called process. Naturally _popen is not available on // NetWare so we must do some fancy stuff to simulate it. We will // redirect to and from temp files; this has the side effect // of having to run the process synchronously rather than // asynchronously. This means that you will only be able to do // this with CLIB NLMs built to run on the calling thread. errno = 0; ptpf1[iPopenCount] = (PTEMPPIPEFILE) malloc(sizeof(TEMPPIPEFILE)); if (!ptpf1[iPopenCount]) return NULL; ptpf = ptpf1[iPopenCount]; iPopenCount ++; if(iPopenCount > MAX_PIPE_RECURSION) iPopenCount = MAX_PIPE_RECURSION; // Limit to the max no of pipes to be open recursively. fnTempPipeFile(ptpf); ret = fnPipeFileOpen((PTEMPPIPEFILE) ptpf, (char *) command, (char *) mode); if (ret) File1[iPopenCount-1] = ret; // Store the obtained Pipe file handle. else { // Pipe file not obtained. So free the allocated memory. if(ptpf1[iPopenCount-1]) { free(ptpf1[iPopenCount-1]); ptpf1[iPopenCount-1] = NULL; ptpf = NULL; iPopenCount --; } } if (errno) e = &errno; return ret; } int nw_Pclose(FILE* file, int* e) { int i=0, j=0; errno = 0; if(file) { if(iPopenCount > 0) { for (i=0; i) or pipe * characters (|) that are not in a quoted string. * Shell variable interpolation (%VAR%) can also happen inside strings. */ while (*ptr) { switch(*ptr) { case '%': return TRUE; case '\'': case '\"': if (inquote) { if (quote == *ptr) { inquote = 0; quote = '\0'; } } else { quote = *ptr; inquote++; } break; case '>': case '<': case '|': if (!inquote) return TRUE; default: break; } ++ptr; } return FALSE; } int fork(void) { return 0; } // added to remove undefied symbol error in CodeWarrior compilation int Perl_Ireentrant_buffer_ptr(aTHX) { return 0; }