![]() |
中国DOS联盟-- 联合DOS 推动DOS 发展DOS --联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum |
| 游客 | 登录 | 注册 | 会员 | 搜索 | 中国DOS联盟 |
|
中国DOS联盟论坛 现在时间是 2026-09-13 22:40 |
共 47,812 主题排行 / 349,916 发帖 / 今日 0 篇 / 48,268 会员排行 |
| 网络日志(Blog) » C语言(四个字)http://www.shucunwang.com/RunCode/c/ |
| 可打印版本 24,924 / 75 |
| 第76楼 zzz19760225 | 发表于 2016-06-26 20:12 |
| 超级版主 发帖 2,020 积分 3,673 | |
|
一个微盘下载的文件 http://upload.cn-dos.net/img/2311.zip
/* * sh.c是UNIX V6下的一个shell解释器实现,源码位于http://minnie.tuhs.org/Archive/PDP-11/Distributions/research/Dennis_v6/ * UNIX v6是受BSD许可证保护的自由软件,其中sh.c的原作者是Ken Thompson(1943 - )于1971年初步实现,于1975年移植到Unix V6。 * 本人主要工作是对源码进行重新注解,并将K&R C转成ANSI C,除此之外未做任何改动。 * 该文件在gcc-4.4.3下通过编译,但本人不能担保该shell应用于任何交互引起的任何问题。 * 任何人可用作学习、改写或者重新发布等其它用途,请遵循BSD许可协议。 * 最近修订时间: 2013-4-15 * 修订人: Leo Ma * 联系方式: begeekmyfriend@gmail.com */ #include <stdlib.h> #define NULL ((void *)0) #define INTR 2 /* 进程终止信号*/ #define QUIT 3 /* 同上*/ #define LINSIZ 1000 /* 命令参数行缓冲空间*/ #define ARGSIZ 50 /* Token指针列表 */ #define TRESIZ 100 /* 语法树所有节点空间*/ #define QUOTE 0200 /* 引用字符标志位,表明该字符前缀为斜杠或引号,限制字符集为ascii,八进制 */ /* 以下为语法树节点的属性标识,用于DFLG字段*/ #define FAND 1 /* And: 该命令以后台异步进程方式执行*/ #define FCAT 2 /* Catenate: 以追加方式重定向输出,相当于>> 符号*/ #define FPIN 4 /* Pipe in: 命令输入重定向到管道线,即从左子树流入*/ #define FPOU 8 /* Pipe out: 命令输出重定向到管道线,即向右子树流出*/ #define FPAR 16 /* Parentheses: 标识复合命令中最后一个简单命令,即右括弧前的命令。Shell会为每个外部 命令(非内置)fork一个子进程上执行,但复合命令中最后一个子命令仍在原来的进程上执行。*/ #define FINT 32 /* Interrupt: 如果命令是后台异步执行,则忽略进程终止信号。*/ #define FPRS 64 /* Print string: 以字符串的形式打印后台进程的pid */ /* 以下为语法树节点的类型声明,用于DTYP字段 */ #define TCOM 1 /* Command: 简单命令*/ #define TPAR 2 /* Parentheses: 复合命令,包含在圆形括弧中的命令序列集合 */ #define TFIL 3 /* Filter: 过滤器或者管道线,由单独的'|'或'^'符号表示 */ #define TLST 4 /* List: 命令序列,多个简单命令集合,由单独的; 或'&'或'\n'符号分隔 */ /* 以下为语法树节点的各个字段,指定了节点大小*/ #define DTYP 0 /* 节点类型,唯一标识*/ #define DLEF 1 /* 左子树节点,视当前节点的类型而定*/ #define DRIT 2 /* 右子树节点,视当前节点的类型而定*/ #define DFLG 3 /* 节点属性,影响所属命令的状态和执行方式*/ #define DSPR 4 /* 若是复合命令类型,该字段为子语法树节点*/ #define DCOM 5 /* 命令参数字符串 */ #define ENOMEM 12 /* 命令执行失败,内存空间不足*/ #define ENOEXEC 8 /* 命令执行失败,找不到可执行文件*/ char *dolp; /* Dollar: 指向以'$'开头的特殊变量*/ char pidp; /* 字符串形式存储进程pid */ char **dolv; /* 以空格分隔的命令行参数序列*/ int dolc; /* 命令行参数个数*/ char *promp; /* 输入提示符,不为空即交互模式,为空即非交互模式*/ char *linep; /* 命令参数缓冲指针,存放下一个字符位置*/ char *elinep; /* 命令参数缓冲区末端*/ char **argp; /* Token列表指针,存放下一个token的位置*/ char **eargp; /* Token列表末端*/ int *treep; /* 语法树列表指针,存放下一个节点位置*/ int *treeend; /* 语法树列表末端*/ char peekc; /* 预读一个字符缓冲*/ char gflg; /* 两种用途: 列表指针溢出标记,通配符标记*/ char error; /* 错误计数*/ char acctf; /* */ char uid; /* User id */ char setintr; /* 忽略中断信号标识*/ char *arginp; /* 当存在选项'-c'时,从该指针指向的字串中扫描命令参数*/ int onelflg; /* 当存在选项'-t'时,从标准输入中扫描命令参数*/ /* 中断信号消息列表*/ char *mesg = { 0, "Hangup", 0, "Quit", "Illegal instruction", "Trace/BPT trap", "IOT trap", "EMT trap", "Floating exception", "Killed", "Bus error", "Memory fault", "Bad system call", 0, "Sig 14", "Sig 15", "Sig 16", "Sig 17", "Sig 18", "Sig 19", }; /* 记录系统时间*/ struct stime { int proct; int cputim; int systim; } timeb; char line; /* 命令参数缓冲区*/ char *args; /* Token列表缓冲区*/ int trebuf; /* 语法树节点缓冲区*/ void main1(); void word(); char getc(); int *syntax(char **p1, char **p2); int *syn1(char **p1, char **p2); int *syn2(char **p1, char **p2); int *syn3(char **p1, char **p2); void execute(int *t, int *pf1, int *pf2); void texec(char *f, int *at); void err(char *s); void prs(char *as); void prn(int n); void pwait(int i, int *t); void acct(int *t); void enacct(char *as); void put(int c); /* Shell入口*/ void main(int c, char **av) { int f; char *acname, **v; for(f=2; f<15; f++) /* close_on_exec,因为shell可能来自外部进程或自身fork */ close(f); if((f=dup(1)) != 2) /* 将stdout重定向到stderr,dup()将返回尚未打开的最小文件句柄*/ close(f); dolc = getpid(); /* 记录当前进程pid */ for(f=4; f>=0; f--) { pidp = dolc%10+'0'; /* itoa */ dolc = dolc/10; } v = av; acname = "/usr/adm/sha"; /* SHA加密序列,目前Unix版本已废弃*/ promp = "% "; /* 普通用户交互提示符*/ if(((uid = getuid())&0377) == 0) promp = "# "; /* root用户交互提示符*/ acctf = open(acname, 1); if(c > 1) { promp = 0; /* 进入非交互模式*/ if (*v=='-') { /* 存在选项*/ **v = '-'; /* 用第一个序列字符临时标记*/ if (v=='c' && c>2) /* '-c'选项,从arginp中扫描*/ arginp = v; else if (v=='t') /* '-t'选项,从stdin中扫描*/ onelflg = 2; } else { /* 直接从命令文件中扫描*/ close(0); f = open(v, 0); /* 重定向stdin到文件*/ if(f < 0) { prs(v); err(": cannot open"); } } } if(**v == '-') { setintr++; /* 非交互模式下带选项,则初始化忽略所有信号*/ signal(QUIT, 1); signal(INTR, 1); } dolv = v+1; dolc = c-1; loop: /* 每次loop执行一次shell语句解释,直到遇上换行符,无限循环除非整个shell进程终止 */ if(promp != 0) prs(promp); /* 打印交互提示符*/ peekc = getc(); /* 对于I/O流,预读一个字符,以便将来再次读取*/ main1(); /* 进入解释器 */ goto loop; } /* * 该函数包含一次shell交互的整个解释过程 * Preprocessor: 对输入的命令参数进行预处理 * Lexical scanning: 对命令参数进行词法分析,分割成token列表 * Syntax parser: 构建语法树 * Semantic analyzer: 设置语法树节点属性,I/O等 * Executor: 为每个命令分配进程并执行 */ void main1() { char c, *cp; int *t; argp = args; eargp = args+ARGSIZ-5; /* 初始化token列表*/ linep = line; elinep = line+LINSIZ-5; /* 初始化命令参数缓冲区*/ error = 0; /* 错误计数清零*/ gflg = 0; /* 溢出标志位清零*/ do { cp = linep; word(); } while(*cp != '\n'); /* 扫描所有命令参数,生成token列表,遇上换行符终止*/ treep = trebuf; treeend = &trebuf; /* 语法树缓冲区清零*/ if(gflg == 0) { if(error == 0) { setexit(); if (error) return; t = syntax(args, argp); /* Scanner没有发生缓冲溢出,没有错误计数,对token列表建立语法树 */ } if(error != 0) err("syntax error"); else /* 语法分析发生错误,提示并退出shell */ execute(t, NULL, NULL); /* 没有错误计数,从根节点开始进行语义分析 */ } } /* * 对命令参数扫描并分割token * readc直接从流中读取一个字符,getc对前者的字符进行预处理 */ void word() { char c, c1; *argp++ = linep; /* 将当前命令参数作为一个token放入列表,以'\0'结束,argp指向下一个token位置 */ loop: switch(c = getc()) { case ' ': case '\t': goto loop; /* 过滤空格和tab字符 */ case '\'': case '"': c1 = c; while((c=readc()) != c1) { /* 多读一个字符,判断是否成对(如引号) */ if(c == '\n') { error++; /* 引用未结束遇上换行符,错误计数 */ peekc = c; /* 推回预读字符 */ return; } *linep++ = c|QUOTE; /* 加上引用标识 */ } goto pack; /* 引用结束,跳转至pack */ case '&': case ';': case '<': case '>': case '(': case ')': case '|': case '^': case '\n': *linep++ = c; *linep++ = '\0'; /* 元字符等特殊字符单独作为一个token返回 */ return; } peekc = c; /* 若为普通字符,推回预读 */ pack: for(;;) { c = getc(); if(any(c, " '\"\t;&<>()|^\n")) { /* 遇上元字符、分隔符等特殊字符 */ peekc = c; /* 推回预读字符 */ if(any(c, "\"'")) goto loop; /* 遇上引用字符,跳转到loop继续扫描 */ *linep++ = '\0'; /* 分割一个token出来 */ return; } *linep++ = c; } } /* 分配一个语法树节点,大小根据n指定,为n*4字节 */ int* tree(int n) { int *t; t = treep; treep += n; if (treep>treeend) { prs("Command line overflow\n"); /* 空间不足 */ error++; reset(); } return(t); } /* * 读取一个字符,并做一些预处理 * 1.从预读缓存中读取 * 2.从流中直接读取 */ char getc() { char c; if(peekc) { c = peekc; /* 如果有预读缓存,读取缓存并返回 */ peekc = 0; /* 清除预读缓存 */ return(c); } if(argp > eargp) { /* Token列表溢出 */ argp -= 10; while((c=getc()) != '\n'); /* 取完换行符前所有字符 */ argp += 10; err("Too many args"); gflg++; return(c); } if(linep > elinep) { /* 命令参数缓存溢出 */ linep -= 10; while((c=getc()) != '\n'); /* 取完换行符之前所有字符 */ linep += 10; err("Too many characters"); gflg++; return(c); } getd: if(dolp) { /* 存在带'$'前缀的命令参数字符 */ c = *dolp++; if(c != '\0') return(c); dolp = 0; /* 带'$'前缀的参数扫描完毕,dolp清零 */ } c = readc(); /* 从流中读取一个字符 */ if(c == '\\') { c = readc(); /* 遇到转义符,继续读取下一个字符 */ if(c == '\n') return(' '); /* 斜杠在行末,返回空格接续下一行 */ return(c|QUOTE); /* 引用该字符 */ } if(c == '$') { c = readc(); /* 遇到'$',继续读取一个字符 */ if(c>='0' && c<='9') { /* 位置变量 */ if(c-'0' < dolc) /* 位置参数在合法范围内 */ dolp = dolv; /* dolp指向替代的命令参数字符 */ goto getd; /* 跳转getd处理 */ } if(c == '$') { /* 当前进程pid */ dolp = pidp; /* dolp指向之前记录的pid字符串 */ goto getd; /* 跳转getd处理 */ } } return(c&0177); /* 普通字符直接返回,限定在ascii */ } /* * 从流中读取一个字符 * arginp!=NULL(onelflg==0):带"-c"选项,从后面附加的字符串中扫描 * arginp==1(oneflg==0):带"-c"选项,扫描终止,退出shell进程 * onelflg==2(arginp==NULL): 带"-t"选项,从stdin中扫描 * onelflg==1(arginp==NULL): 带"-t"选项,扫描终止,退出shell进程 */ int readc() { char cc; int c; if (arginp) { /* "-c"选项 */ if (arginp == (void *)1) exit(-1); /* 没有新的命令参数,退出shell进程 */ if ((c = *arginp++) == 0) { arginp = (void *)1; /* 扫描终止 */ c = '\n'; /* 追加换行符返回 */ } return(c); } if (onelflg==1) exit(0); /* "-t"选项,扫描终止,退出shell进程 */ if(read(0, &cc, 1) != 1) /* 从标准输入中读取一个字符 */ exit(-1); if (cc=='\n' && onelflg) /* onelflg == 2,"-t"选项 */ onelflg--; /* 扫描一行完毕 */ return(cc); } /* * syntax * empty * syn1 * * 从这里开始构建语法树,遍历之前扫描生成的token列表 * p1指向token列表头部,p2指向token列表末尾的下一个 * 自顶向下三级结构: syn1、syn2、syn3,函数调用关系如下 * 1.左子树:左边列表递进一层 * 2.右子树:右边列表回溯或者递归 * 3.找不到符号:所有列表递进一层 * 4.生成节点:直接返回 */ int *syntax(char **p1, char **p2) { while(p1 != p2) { if(any(**p1, ";&\n")) /* 列表前缀为命令序列分隔字符,过滤掉该token,对syntax回溯中碰到*/ p1++; else return(syn1(p1, p2)); /* 所有列表递进一层至syn1 */ } return(0); } /* * syn1 * syn2 * syn2 & syntax * syn2 ; syntax * * syn1生成命令序列节点,查找分隔符, * 自顶向下生成左子树,回溯生成右子树。 * p1指向token列表头部,p2指向token列表末尾的下一个。 */ int *syn1(char **p1, char **p2) { char **p; int *t, *t1; int l; l = 0; for(p=p1; p!=p2; p++) switch(**p) { case '(': l++; continue; /* 此处等同于break */ case ')': l--; if(l < 0) error++; continue; case '&': case ';': case '\n': if(l == 0) { /* 没有圆括弧嵌套 */ l = **p; t = tree(4); t = TLST; /* 生成命令序列节点*/ t = (int)syn2(p1, p); /* 左边列表递进一层生成左子树节点*/ t = 0; /* 命令序列节点不设置任何标志位*/ if(l == '&') { t1 = (int *)t; t1 |= FAND|FPRS|FINT; /* 若有后台进程,其属性下推到左子树节点*/ } t = (int)syntax(p+1, p2); /* 右边列表回溯到syntax生成右子树节点*/ return(t); } } if(l == 0) return(syn2(p1, p2)); /* 没有找到命令分隔符,所有列表递进一层至syn2 */ error++; /* 如果嵌套不归零发生错误*/ } /* * syn2 * syn3 * syn3 | syn2 * * syn2负责构建管道线节点,搜索管道线符号, * 自顶向下生成左子树,递归生成右子树。 * p1指向token列表头部,p2指向token列表末尾的下一个。 */ int *syn2(char **p1, char **p2) { char **p; int l, *t; l = 0; for(p=p1; p!=p2; p++) switch(**p) { case '(': l++; continue; /* 此处等同于break */ case ')': l--; continue; case '|': case '^': if(l == 0) { /* 没有圆括弧嵌套 */ t = tree(4); t = TFIL; /* 建立管道线节点*/ t = (int)syn3(p1, p); /* 左边列表递进一层生成左子树节点*/ t = (int)syn2(p+1, p2); /* 右边递归生成右子树节点*/ t = 0; /* 标志位继承自上层节点*/ return(t); } } return(syn3(p1, p2)); /* 没有找到管道线,所有列表递进一层,不需要判断嵌套是否归零*/ } /* * syn3 * ( syn1 ) * word word* * * syn3负责构建复合命令和简单命令节点,前者以圆括号标记,括号内所有token列表回溯至syn1构建子命令节点; * 简单命令是语法树叶子,其左右子树节点为I/O重定向文件,并存储命令参数字符串,生成节点后直接返回。 * p1指向token列表头部,p2指向token列表末尾的下一个。 */ int *syn3(char **p1, char **p2) { char **p; char **lp, **rp; int *t; int n, l, i, o, c, flg; flg = 0; if(**p2 == ')') flg |= FPAR; /* 复合命令中最后一个子命令不需要fork子进程*/ lp = 0; /* 子命令开头*/ rp = 0; /* 子命令末尾*/ i = 0; /* 输入文件路径*/ o = 0; /* 输出文件路径*/ n = 0; /* 字符计数*/ l = 0; /* 嵌套层数*/ for(p=p1; p!=p2; p++) switch(c = **p) { case '(': if(l == 0) { if(lp != 0) error++; lp = p+1; /* 当前嵌套最外层,lp指向子命令第一个字符*/ } l++; continue; /* 同break */ case ')': l--; if(l == 0) rp = p; /* 当前嵌套最外层,rp指向子命令后面的')' */ continue; case '>': p++; if(p!=p2 && **p=='>') /* 追加模式FCAT标识*/ flg |= FCAT; else p--; /* 注意这里没有break,继续往下走*/ case '<': if(l == 0) { p++; if(p == p2) { error++; /* 后面没有字符,发生错误 */ p--; } if(any(**p, "<>(")) /* 非法字符 */ error++; if(c == '<') { if(i != 0) error++; i = (int)*p; /* 重定向到输入文件,只对简单命令有效*/ continue; } if(o != 0) error++; o = (int)*p; /* 重定向到输出文件,只对简单命令有效*/ } continue; default: if(l == 0) p1 = *p; /* 命令参数前移清除以往记录,并用n计数*/ } if(lp != 0) { if(n != 0) error++; /* 复合命令,n必须为0 */ t = tree(5); t = TPAR; /* 分配复合命令类型节点*/ t = (int)syn1(lp, rp); /* 括号内所有token列表回溯至syn1构建子命令节点 */ goto out; } if(n == 0) error++; /* 简单命令,n必须不为0 */ p1 = 0; /* 字符串结束*/ t = tree(n+5); /* 分配简单命令节点,大小为5个字段(DSPR字段为空)加上命令字符数*/ t = TCOM; for(l=0; l<n; l++) t = (int)p1; out: t = flg; /* 固有属性或者继承自上层节点属性*/ t = i; /* 对于简单命令,左右子树是重定向的I/O文件*/ t = o; /* 对于复合命令,左右子树为空*/ return(t); } /* 用函数指针f扫描所有字符 */ void scan(int *at, int (*f)()) { char *p, c; int *t; t = at+DCOM; while(p = (char *)*t++) while(c = *p) *p++ = (*f)(c); } /* 查找通配符*/ int tglob(int c) { if(any(c, " : 管道线输入端句柄 * pf1: 闲置 * pf2: 闲置 * pf2: 管道线输出端句柄 */ void execute(int *t, int *pf1, int *pf2) { int i, f, pv; int *t1; char *cp1, *cp2; extern int errno; if(t != 0) switch(t) { case TCOM: cp1 = (char *)t; /* 以下为内置命令*/ if(equal(cp1, "chdir")) { if(t != 0) { if(chdir(t) < 0) err("chdir: bad directory"); } else err("chdir: arg count"); return; } if(equal(cp1, "shift")) { if(dolc < 1) { prs("shift: no args\n"); return; } dolv = dolv; dolv++; dolc--; return; } if(equal(cp1, "login")) { if(promp != 0) { close(acctf); execv("/bin/login", t+DCOM); } prs("login: cannot execute\n"); return; } if(equal(cp1, "newgrp")) { if(promp != 0) { close(acctf); execv("/bin/newgrp", t+DCOM); } prs("newgrp: cannot execute\n"); return; } if(equal(cp1, "wait")) { pwait(-1, 0); return; } if(equal(cp1, ":")) return; /* 注意,这里没有break,筛选掉内置命令后,外部命令会继续往下走*/ case TPAR: f = t; i = 0; if((f&FPAR) == 0) /* 除了复合命令中最后一个子命令,其它一律fork子进程*/ i = fork(); if(i == -1) { err("try again"); return; } if(i != 0) { /* 父进程代码*/ if((f&FPIN) != 0) { close(pf1); /* fork之后,子进程获得父进程的管道线句柄拷贝,我们要在父进程中关闭它,以免资源泄漏*/ close(pf1); /* 注意,这里只关闭pf1,因为pf1、pf2都是pv的镜像,因此关闭pf1就是关闭pf2 */ } if((f&FPRS) != 0) {/* 打印子进程pid */ prn(i); prs("\n"); } if((f&FAND) != 0) /* 后台异步进程无需等待*/ return; if((f&FPOU) == 0) /* 节点为管道线末端,等待子进程终止*/ pwait(i, t); return; } /* 以下为子进程代码,或者FPAR属性节点命令进程*/ if(t != 0) { close(0); i = open(t, 0); /* 重定向stdin到左子树节点*/ if(i < 0) { prs((char *)t); err(": cannot open"); exit(-1); } } if(t != 0) { if((f&FCAT) != 0) { i = open(t, 1); if(i >= 0) { seek(i, 0, 2); /* 追加模式*/ goto f1; } } i = creat(t, 0666); /* 创建新的文件句柄*/ if(i < 0) { prs((char *)t); err(": cannot create"); exit(-1); } f1: close(1); dup(i); /* 重定向stdout到右子树节点*/ close(i); } if((f&FPIN) != 0) { close(0); dup(pf1); /* 重定向stdin到管道线输入端*/ close(pf1); close(pf1); /* 子进程关闭管道线句柄*/ } if((f&FPOU) != 0) { close(1); dup(pf2); /* 重定向stdout 到管道线输出*/ close(pf2); close(pf2); /* 子进程关闭管道线句柄*/ } if((f&FINT)!=0 && t==0 && (f&FPIN)==0) { close(0); /* 若忽略中断,且不存在管道线输入,则关闭stdin并重定向到位桶*/ open("/dev/null", 0); /* 以免来自其它进程stdin干扰,但stdout是保留的*/ } if((f&FINT) == 0 && setintr) { signal(INTR, 0); /* 无FINT标识,则恢复中断信号响应(默认是忽略的) */ signal(QUIT, 0); } if(t == TPAR) { /* 如果是复合类型,则执行子命令,同时下推FINT标识*/ if(t1 = (int *)t) t1 |= f&FINT; execute(t1, NULL, NULL); exit(0); } close(acctf); gflg = 0; scan(t, &tglob); /* 扫描通配符*/ if(gflg) { t = (int)"/etc/glob"; execv(t, t+DSPR); /* 包含通配符的命令在/etc/glob中执行*/ prs("glob: cannot execute\n"); exit(-1); } scan(t, &trim); /* 解除引用标识*/ *linep = 0; texec((char *)t, t); /* 最先执行当前目录下的命令*/ cp1 = linep; cp2 = "/usr/bin/"; while(*cp1 = *cp2++) /* strcpy,cp1停在'\0'位置 */ cp1++; cp2 = (char *)t; while(*cp1++ = *cp2++); /* strcpy,'\0'结束 */ texec(linep+4, t); /* 接着执行/bin目录下的命令*/ texec(linep, t); /* 最后执行/usr/bin目录下的命令*/ prs((char *)t); /* 若进程异常退出,表示找不到命令,退出shell */ err(": not found"); exit(-1); case TFIL: f = t; pipe(pv); /* 创建管道线,pv为输入句柄,pv为输出句柄*/ t1 = (int *)t; t1 |= FPOU | (f&(FPIN|FINT|FPRS)); execute(t1, pf1, pv); /* 对于左子树节点,pv作为管道线输出句柄传入,pv闲置*/ t1 = (int *)t; t1 |= FPIN | (f&(FPOU|FINT|FAND|FPRS)); /* 只有管道线末端命令才能继承FAND属性,与FPOU排斥*/ execute(t1, pv, pf2); /* 对于右子树节点,pv作为管道线输入句柄传入,pv闲置*/ return; case TLST: f = t&FINT; /* 对于命令序列节点,下推FINT属性到左右子树*/ if(t1 = (int *)t) t1 |= f; execute(t1, NULL, NULL); /* 先左后右依次执行 */ if(t1 = (int *)t) t1 |= f; execute(t1, NULL, NULL); return; } } /* * 执行命令 * f为可执行文件路径 * at为语法树节点 */ void texec(char *f, int *at) { extern int errno; int *t; t = at; execv(f, t+DCOM); /* 重新加载并执行命令,不需要设置环境*/ if (errno==ENOEXEC) { if (*linep) t = (int)linep; t = (int)"/bin/sh"; execv(t, t+DSPR); /* 找不到命令可执行文件*/ prs("No shell!\n"); exit(-1); } if (errno==ENOMEM) { prs((char *)t); err(": too large"); /* 内存不足*/ exit(-1); } } /* 打印错误,非交互模式则清空stdin缓存并退出shell进程*/ void err(char *s) { prs(s); prs("\n"); if(promp == 0) { seek(0, 0, 2); exit(-1); } } /* 打印字符串*/ void prs(char *as) { char *s; s = as; while(*s) put(*s++); } /* 输出一个字符*/ void put(int c) { write(2, &c, 1); } /* itoa */ void prn(int n) { int a; if(a=n/10) prn(a); put(n%10+'0'); } /* 字符串中是否包含某个字符*/ int any(int c, char *as) { char *s; s = as; while(*s) if(*s++ == c) return(1); return(0); } /* 字符串比较*/ int equal(char *as1, char *as2) { char *s1, *s2; s1 = as1; s2 = as2; while(*s1++ == *s2) if(*s2++ == '\0') return(1); return(0); } /* * 父进程等待子进程终止 * i为子进程pid,-1表示等待所有子进程 * t为语法树节点 */ void pwait(int i, int *t) { int p, e; int s; if(i != 0) for(;;) { times(&timeb); time(timeb.proct); p = wait(&s); if(p == -1) /* 等待失败 */ break; e = s&0177; /* 保留状态环境 */ if(mesg != 0) { /* 子进程异常终止 */ if(p != i) { prn(p); prs(": "); } prs(mesg); /* 打印对应的消息 */ if(s&0200) /* 内核奔溃 */ prs(" -- Core dumped"); } if(e != 0) err(""); /* 等待正常终止 */ if(i == p) { acct(t); break; } else acct(0); } } void acct(int *t) { if(t == 0) enacct("**gok"); else if(*t == TPAR) enacct("()"); else enacct((char *)t); } void enacct(char *as) { struct stime timbuf; struct { char cname; char shf; char uid; int datet; int realt; int bcput; int bsyst; } tbuf; int i; char *np, *s; s = as; times(&timbuf); time(timbuf.proct); lsub(tbuf.realt, timbuf.proct, timeb.proct); lsub(tbuf.bcput, timbuf.cputim, timeb.cputim); lsub(tbuf.bsyst, timbuf.systim, timeb.systim); do { np = s; while (*s != '\0' && *s != '/') s++; } while (*s++ != '\0'); for (i=0; i<14; i++) { tbuf.cname = *np; if (*np) np++; } tbuf.datet = timbuf.proct; tbuf.datet = timbuf.proct; tbuf.uid = uid; tbuf.shf = 0; if (promp==0) tbuf.shf = 1; seek(acctf, 0, 2); write(acctf, &tbuf, sizeof(tbuf)); } [ Last edited by zzz19760225 on 2016-12-11 at 00:32 ] |
|
| 上一页 1 … 3 4 5 6 |
|
[ 联系联盟系统管理团队 -
中国DOS联盟 -
标准版 ] Sponsored by ifanr Inc | © 2001–2023 |