📄 sfpopen.c
字号:
/* Copyright (c) Colorado School of Mines, 2006.*//* All rights reserved. */#include "sfhdr.h"/* Create a coprocess.** Written by Kiem-Phong Vo.*/#if _PACKAGE_ast#include <proc.h>#else#define EXIT_NOTFOUND 127#define READ 0#define WRITE 1#ifndef CHAR_BIT#define CHAR_BIT 8#endifstatic char Meta[1<<CHAR_BIT], **Path;/* execute command directly if possible; else use the shell */#if __STD_Cstatic void execute(const char* argcmd)#elsestatic void execute(argcmd)char* argcmd;#endif{ reg char *s, *cmd, **argv, **p, *interp; reg int n; /* define interpreter */ if(!(interp = getenv("SHELL")) || !interp[0]) interp = "/bin/sh"; if(strcmp(interp,"/bin/sh") != 0 && strcmp(interp,"/bin/ksh") != 0 ) { if(access(interp,X_OK) == 0) goto do_interp; else interp = "/bin/sh"; } /* if there is a meta character, let the shell do it */ for(s = (char*)argcmd; *s; ++s) if(Meta[(uchar)s[0]]) goto do_interp; /* try to construct argv */ if(!(cmd = (char*)malloc(strlen(argcmd)+1)) ) goto do_interp; strcpy(cmd,argcmd); if(!(argv = (char**)malloc(16*sizeof(char*))) ) goto do_interp; for(n = 0, s = cmd;; ) { while(isspace(s[0])) s += 1; if(s[0] == 0) break; /* new argument */ argv[n++] = s; if((n%16) == 0 && !(argv = (char**)realloc(argv,(n+16)*sizeof(char*))) ) goto do_interp; /* make this into a C string */ while(s[0] && !isspace(s[0])) s += 1; if(!s[0]) *s++ = 0; } if(n == 0) goto do_interp; argv[n] = NIL(char*); /* get the command name */ cmd = argv[0]; for(s = cmd+strlen(cmd)-1; s >= cmd; --s) if(*s == '/') break; argv[0] = s+1; /* Non-standard pathnames as in nDFS should be handled by the shell */ for(s = cmd+strlen(cmd)-1; s >= cmd+2; --s) if(s[0] == '.' && s[-1] == '.' && s[-2] == '.') goto do_interp; if(cmd[0] == '/' || (cmd[0] == '.' && cmd[1] == '/') || (cmd[0] == '.' && cmd[1] == '.' && cmd[2] == '/') ) { if(access(cmd,X_OK) != 0) goto do_interp; else execv(cmd,argv); } else { for(p = Path; *p; ++p) { s = sfprints("%s/%s", *p, cmd); if(access(s,X_OK) == 0) execv(s,argv); } } /* if get here, let the interpreter do it */do_interp: for(s = interp+strlen(interp)-1; s >= interp; --s) if(*s == '/') break; execl(interp, s+1, "-c", argcmd, NIL(char*)); _exit(EXIT_NOTFOUND);}#endif /*_PACKAGE_ast*/#if __STD_CSfio_t* sfpopen(Sfio_t* f, const char* command, const char* mode)#elseSfio_t* sfpopen(f,command,mode)Sfio_t* f;char* command; /* command to execute */char* mode; /* mode of the stream */#endif{#if _PACKAGE_ast reg Proc_t* proc; reg int sflags; reg long flags; reg int pflags; char* av[4]; if (!command || !command[0] || !mode) return 0; sflags = _sftype(mode, NiL, NiL); if(f == (Sfio_t*)(-1)) { /* stdio compatibility mode */ f = NIL(Sfio_t*); pflags = 1; } else pflags = 0; flags = 0; if (sflags & SF_READ) flags |= PROC_READ; if (sflags & SF_WRITE) flags |= PROC_WRITE; av[0] = "sh"; av[1] = "-c"; av[2] = (char*)command; av[3] = 0; if (!(proc = procopen(0, av, 0, 0, flags))) return 0; if (!(f = sfnew(f, NIL(Void_t*), (size_t)SF_UNBOUND, (sflags&SF_READ) ? proc->rfd : proc->wfd, sflags|((sflags&SF_RDWR)?0:SF_READ))) || _sfpopen(f, (sflags&SF_READ) ? proc->wfd : -1, proc->pid, pflags) < 0) { if (f) sfclose(f); procclose(proc); return 0; } procfree(proc); return f;#else reg int pid, fd, pkeep, ckeep, sflags; int stdio, parent[2], child[2]; Sfio_t sf; /* set shell meta characters */ if(Meta[0] == 0) { reg char* s; Meta[0] = 1; for(s = "!@#$%&*(){}[]:;<>~`'|\"\\"; *s; ++s) Meta[(uchar)s[0]] = 1; } if(!Path) Path = _sfgetpath("PATH"); /* sanity check */ if(!command || !command[0] || !mode) return NIL(Sfio_t*); sflags = _sftype(mode,NIL(int*),NIL(int*)); /* make pipes */ parent[0] = parent[1] = child[0] = child[1] = -1; if(sflags&SF_RDWR) { if(syspipef(parent) < 0) goto error; if((sflags&SF_RDWR) == SF_RDWR && syspipef(child) < 0) goto error; } switch((pid = fork()) ) { default : /* in parent process */ if(sflags&SF_READ) { pkeep = READ; ckeep = WRITE; } else { pkeep = WRITE; ckeep = READ; } if(f == (Sfio_t*)(-1)) { /* stdio compatibility mode */ f = NIL(Sfio_t*); stdio = 1; } else stdio = 0; /* make the streams */ if(!(f = sfnew(f,NIL(Void_t*),(size_t)SF_UNBOUND,parent[pkeep],sflags|((sflags&SF_RDWR)?0:SF_READ)))) goto error; if(sflags&SF_RDWR) { CLOSE(parent[!pkeep]); SETCLOEXEC(parent[pkeep]); if((sflags&SF_RDWR) == SF_RDWR) { CLOSE(child[!ckeep]); SETCLOEXEC(child[ckeep]); } } /* save process info */ fd = (sflags&SF_RDWR) == SF_RDWR ? child[ckeep] : -1; if(_sfpopen(f,fd,pid,stdio) < 0) { (void)sfclose(f); goto error; } return f; case 0 : /* in child process */ /* determine what to keep */ if(sflags&SF_READ) { pkeep = WRITE; ckeep = READ; } else { pkeep = READ; ckeep = WRITE; } /* zap fd that we don't need */ if(sflags&SF_RDWR) { CLOSE(parent[!pkeep]); if((sflags&SF_RDWR) == SF_RDWR) CLOSE(child[!ckeep]); } /* use sfsetfd to make these descriptors the std-ones */ SFCLEAR(&sf,NIL(Vtmutex_t*)); /* must be careful so not to close something useful */ if((sflags&SF_RDWR) == SF_RDWR && pkeep == child[ckeep]) if((child[ckeep] = sysdupf(pkeep)) < 0) _exit(EXIT_NOTFOUND); if(sflags&SF_RDWR) { if (parent[pkeep] != pkeep) { sf.file = parent[pkeep]; CLOSE(pkeep); if(sfsetfd(&sf,pkeep) != pkeep) _exit(EXIT_NOTFOUND); } if((sflags&SF_RDWR) == SF_RDWR && child[ckeep] != ckeep) { sf.file = child[ckeep]; CLOSE(ckeep); if(sfsetfd(&sf,ckeep) != ckeep) _exit(EXIT_NOTFOUND); } } execute(command); return NIL(Sfio_t*); case -1 : /* error */ error: if(parent[0] >= 0) { CLOSE(parent[0]); CLOSE(parent[1]); } if(child[0] >= 0) { CLOSE(child[0]); CLOSE(child[1]); } return NIL(Sfio_t*); }#endif /*_PACKAGE_ast*/}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -