📄 sh.c
字号:
/****************************************************************************** * Sh.c Primitive shell-type routine. * S.Hosgood, 23.feb.84, Modded T.Barnaby May 1985 for Codata ****************************************************************************** * * When the shell is used internal to the kernal certain system calls * have to be made in a special way ie through the system wrapper, * Not direct. * The routines that are relevent to this are at the end of this file. * * xeq() called via syscall() * kwait() called via syscall() * putchar() All console io done via write() system call * because of interupt driven TTY. */# include <sys/types.h># include <errno.h>#if defined(MSDOS)#define STANDALONE 1#define WILDCARDS 1#include <sys/dirbsd.h>#include <process.h>#else# include <sys/dir.h>#endif#if defined(STANDALONE)# include <sys/stat.h># include "inbin.h"# define printk printf#else# include "../include/stat.h"# include "../include/inbin.h"# include "../include/state.h"#endif/* WILDCARDS If required define wild cards for internal shell * Is an option because it will make the kernal big * Approx + 2K */# define WILDCARDS 1 /* Wild card mode on *//* DATESET If a call to dateset is required on power up * Then define DATESET here *//* # define DATESET 1 */# define NARGS 10 /* Max number of argv's */# define NENVS 10 /* Max number of env's */# define ARGLEN 40 /* Line length enviroment varibles */# define ENVLEN 40 /* Line length enviroment varibles */# define LINELEN 100 /* Line length shell files */# define NOTFOUND -1 /* File not found to execute *//* Execute mode bits */# define EBACKGRD 1 /* Background flag */# define ENOERROR 2 /* No error check on shell files */extern int errno;extern struct Comm kercom[];/* Internal shell commands */int cd(), setenv(), echo(), pmem(), smem(), shexit(), setid(), kstate();struct Comm shcom[] = { "cd", 0, cd, "exit", 0, shexit, "shutdown", 0, shexit, "setid", 0, setid, "setenv", 0, setenv, "echo", 0, echo, "pmem", 0, pmem, "smem", 0, smem, "kstate", 0, kstate, 0, 0, 0,};int fin, fout, ferr, chfiles; /* Files opened */char shenv[NENVS][ENVLEN]; /* Shell enviroment varibles */#ifdef WILDCARDS# define MAXNARGS 50 /* Max number of args */# define MAXAAREA 200 /* Max arg area */# define MAXPATH 50 /* Max path length */struct Args { int nargs; /* Number of args */ char *argp[MAXNARGS]; /* Argument pointers */ char *endarg; /* Last entry in arg area */ char area[MAXAAREA]; /* Area where args is stored */};struct Args wargv;#endif WILDCARDS/* * Sh() Internal shell program itself */sh(){ char input[100], *argv[NARGS], *env[NENVS]; int nbytes, argc, c, in, error, backgnd, wargc;#if defined(STANDALONE) printk("Unix look-alike shell (testing)\n");#else if(-1==chdir("/")) panic("change dir error\n"); /* Opens all files for shell */ openfiles(); printk("68000 One-Man-Unix System. Version 4.0\n"); printk("Steve Hosgood, 1984 + Terry Barnaby 1985 + 1986\n");#endif /* Setup enviroment pointers to enviroment area */ for(c = 0; c < NENVS; c++) env[c] = shenv[c]; /* Sets up dummy enviroment */ strcpy(shenv[0],"PATH=:/bin:/usr/bin:/INBIN"); strcpy(shenv[1],"HOME=/usr"); strcpy(shenv[2],"TERM=terries1"); strcpy(shenv[3],"TERMCAP=/etc/termcap"); strcpy(shenv[4],"EXINIT=map #0 i|map #1 x|set sm"); strcpy(shenv[5],"SHELL=/bin/csh"); env[5] = 0;# ifdef DATESET /* set time */ argv[0] = "date"; printk("Enter date yymmddhhmm ? "); if(getin(input)){ argv[1] = input; argv[2] = 0; if(execute("/bin/date", 2, argv, env, 0)) printk("Internal sh: Unable to execute /bin/date\n"); }# endif /* Execute /etc/rc if present */ argv[0] = "rc"; argv[1] = 0; execute("/etc/rc", 1, argv, env, ENOERROR); /* Main shell internal loop */ while (1){ /* Prints prompt depending if root or not */ if(getuid()) write(1, "$> ", 3); else write(1, "INSH# ", 6); /* Gets input line */ nbytes = getin(input); /* If no command continue to start of loop */ if (nbytes <= 1) continue; /* Parse the input command line into arguments */ argc = parse(input, argv); /* Checks if process is to run background */ if(argv[argc-1][0] == '&'){ backgnd = 1; argv[--argc] = 0; } else backgnd = 0; /* Check if any file redirections required * Sets file numbers as apropriate and sets chfiles * To indicate files have changed */ if((argc = chredir(argc, argv)) == -1) continue;#ifdef WILDCARDS /* Clear all previous args */ clearargs(&wargv); wargc = 0; for(c = 0; c < argc; c++){ /* Check if argument has wild cards if so do wild * card expansion */ if(wiswild(argv[c])){ if((in = wildexp(argv[c], "", &wargv)) == -1){ printk("Two many args\n"); break; } } /* Else just add argument to args */ else{ if(!(in = addarg(argv[c], &wargv))){ printk("Two many args\n"); break; } } wargc += in; } /* Try and execute program */ error = execute(wargv.argp[0], wargv.nargs, wargv.argp, env, backgnd); /* If any redirections set to origanal files */ if(chfiles){ close(0); close(1); close(2); openfiles(); }#else /* Try and execute program */ error = execute(argv[0], argc, argv, env, backgnd); /* If any redirections set to origanal files */ if(chfiles){ close(0); close(1); close(2); openfiles(); }#endif WILDCARDS /* Print error messages */ switch(error){ case 0: break; case NOTFOUND: /* Failed all attempts */ printk("%s: not found\n", argv[0]); break; default: printk("%s: terminated %x\n",argv[0], error); break; } }}/* * Getin() Get user input */getin(str)char *str;{ int num; num = 0; while(1){ read(fin, str, 1); num++; if((*str == '\n') || (*str == ';')) break; str++; } *str = 0; return num;}/* * Opens all files for shell */openfiles(){ if ((fin = open("/dev/console", 2)) == -1){ if ((fin = open(":console", 2)) == -1) panic("No console"); } if (fin) panic("Std input non-zero"); fout = dup(fin); /* Stdout and stderr */ ferr = dup(fout); chfiles = 0;}/* * Parse() Parse command line into arguments return number. */parse(cptr, argv)char *cptr;char *argv[];{ int argc; char fquote; /* scan line, breaking into args */ fquote = argc = 0; while (1){ /* miss leading spaces */ while (*cptr && *cptr == ' ') cptr++; if (*cptr){ /* Check if quotes start of argument */ if(*cptr == '"'){ fquote = 1; cptr++; } /* arg there */ argv[argc++] = cptr; /* scan to end of word */ while (*cptr && ((*cptr != ' ') || fquote) && (*cptr != '"')) cptr++; /* null terminate arg */ if ((*cptr == ' ') || (*cptr == '"')){ *cptr++ = '\0'; fquote = 0; } } else break; if(argc >= (NARGS - 1)) break; } argv[argc] = 0; return argc;}/* * Execute() Execute program, first checks internal shell * commands then looks in places as defined in the * enviroment varible PATH. * If not found will exectute internal kernal command if * found. * Will execute shell files if found. * Returns NOTFOUND if not found, or exit status * of process if found. */execute(name, argc, argv, env, eflag)char *name;int argc, eflag;char *argv[], *env[];{ struct Comm *coms; char path[ENVLEN], *ps, *pe; char execname[ARGLEN]; int error; /* Creates new proccess useing xeq (does fork and execl in one) */ error = 0; /* Failed - try in PATH varible places */ /* Get path string */ retenv(env, "PATH", path); ps = path; /* Check internal shell commands */ coms = shcom; while (coms->c_name && strcmp(coms->c_name, name) != 0) coms++; /* Execute if found */ if(coms->c_name){ return (*coms->c_routine)(argc, argv, env); } /* Else check the paths as defined in the PATH enviroment */ while(1){ /* If end of path string break */ if(!(*ps)) break; /* Find the end of the path entry */ pe = ps; while(*pe && (*pe != ':')) pe++; if(*pe) *pe++ = 0; /* Copy this entry into the execname place and execute normally */ strcpy(execname, ps); /* If ps has a path in it add a slash */ if(execname[0]) strcat(execname, "/"); strcat(execname, name); if((error = shexec(execname, argv, env, eflag)) != NOTFOUND) return error; /* Check if could be shell file */ if((error = shellfile(execname, argc, argv, env, eflag)) != NOTFOUND) return error; /* Next entry */ ps = pe; } /* failed there too - try built-in kernal commands */ coms = kercom; while (coms->c_name && strcmp(coms->c_name, name) != 0) coms++; /* try and execute */ if (coms->c_name){ return (*coms->c_routine)(argc, argv, env); } return NOTFOUND;}/* * Shellfile() Try and run shell file. * Returns -1 if not found or not executable, * Exit status of terminated program invoked. */shellfile(name, argc, argv, env, eflag)char *name;int argc, eflag;char *argv[], *env[];{ char *sargv[NARGS]; int file, sargc, err, error, backgnd; char str[LINELEN]; /* Check if file executable */ if(access(name, 1)) return NOTFOUND; /* Open file and execute */ if((file = open(name, 0)) != -1){ while(1){ if((err = getline(file, str)) == 1){ sargc = parse(str, sargv); /* Checks if process is to run background */ backgnd = eflag & ENOERROR; if(sargv[argc-1][0] == '&'){ backgnd |= EBACKGRD; sargv[--argc] = 0; } /* Try and execute program */ error = execute(sargv[0],sargc,sargv,env,backgnd); /* If errors are to be checked do check */ if(!(eflag & ENOERROR)){ switch(error){ case 0: /* No error */ break; case NOTFOUND: /* Failed to execute */ printk("%s: not found\n", sargv[0]); return error; default: /* Process returned with error */ printk("%s: terminated %x\n", sargv[0], error); return error; } } } else{ if(err == -1) return NOTFOUND; else break; } } close(file); } else return NOTFOUND; return 0;}/* * Getline() Getline from a file terminated with newline. * Returns 1 if found, 0 if end of file -1 if error. * Ignores zero length lines and line begining with * a #. */getline(file, line)int file;char *line;{ int count, n; char *str; /* Scans file for input line */ count = 0; while(!count){ str = line; *str = 0; while(n = read(file, str, 1)){ if((*str == '\n') || (*str == ';')){ *str = 0; break; } if((*str < ' ') || (*str > 'z')) return -1; if(!count && (*str == '#')){ while((n = read(file, str, 1)) && *str != '\n'); break; } str++; if(++count >= LINELEN) return -1; } if(!n) return 0; } return 1;}/* * Chredir() Check if any file redirections if found opens * relevent files, and flags filech to indicate * I/O files have been changed, removes * the args from argv and returns the new value of argc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -