#ifdef MSDOS /* { */ #include "grep_msd.h" #endif /* } */ static char sccsID[] = "@(#) Shell.c V1.0 Author Julian Stacey\n" ; #undef DEBUG /* OURNIX(MSDOS) Command Interpreter enhancements needed: many, including: .coms to .exe does not understand quotes etc. unbuffered io for prompt needed */ /* Features: allows commands with or without parameters, allows parameters to have one or more white space chars blocks signals changes directory Does not suffer the directory change problems of nested msdos interpretes. Can type cd . Can run from scripts Bugs: blows when run from a shell file. */ #include #include #include #include #include #define UTMP "/etc/utmp" #define CTL_D 4 /* control char that exits this interpreter */ #define EXITT "exit" /* command that exits this interpreter */ #define CHDIR "cd" /* change directory inbuilt command */ #define SET "set" /* display environment */ #define EX_EXT ".exe" /* executable extension */ #define EX_LEN 12 /* maximum length of an msdos name (excluding null) typical abcdefgh.ijk\0 */ #define PATH_LN 50 /* maximum allowable path length */ #define MSDOS #ifdef MSDOS /* directory restoral needed after each exec */ #endif #ifdef UNIX /* directory restoral not needed after each exec */ #endif struct passwd { char *pw_name; char *pw_passwd; char *pw_dir; char *pw_shell; char *pw_shargs; /* shell args */ }; typedef char flag; #define strequ !strcmp #include "lib/getpwnam.c" int ARGC ; char **ARGV ; char **ENVP; main(argc,argv,envp) int argc ; char **argv ; char **envp ; { flag opened = 0 ; ARGC = argc ; ARGV = argv ; ENVP = envp ; printf(Sccsid); signal(SIGINT,SIG_IGN); #define DEBUG if ( dup2(0,17) || dup2(1,18) || dup2(2,19) ) printf("sh: program error dup failed\n"); printf("sh argc is %d argv 1st element is %s\n",argc, *argv); while (argc-- > 1) { if ( **++argv == '-' ) switch(*++*argv) { case 'I': printf("got Initial flag\n"); break; default: printf("bad sh option\n"); break; } else { if (!opened) { close(0); /* step past a delimeter typically \- */ if (**argv == '\\') (*argv)++ ; open(*argv++,O_RDONLY); opened = 1; } } /* remove input file name from command string */ *(ARGV+1) = *ARGV; ARGV++; } doit(); } char *getline() { static char line_buf[200] ; int c ; char *p ; for (p = line_buf ; ((c = getchar()) != EOF) ; *p++ = (char)c ) { c = (char)c & 0x7f ; if (c == '\n') break; } *p = '\0'; if (c == EOF) return((char *)0); else return(line_buf); } doit() { char *pb; /* pointer to beginning of command */ char *pe; /* pointer to end of command */ char **pp ; /* environmment pointer */ char executable[PATH_LN + EX_LEN + 1]; /* command to be executed */ char *ptr[20] ; /* array of pointers */ int ret; /* return value */ #ifdef MSDOS #define CWD_LN PATH_LN char cwd[CWD_LN]; /* current working directory */ #endif FILE *utmp ; struct passwd *who_s ; char who_o[20] ; /* person name */ flag sh_result ; /* will be used as per unix $RESULT one day */ char putter[100] ; /* cludge for putenv */ ptr[0] = executable ; /* first element of argv will allways be name of executable command */ while(1) { /* output prompt */ #ifdef MSDOS getcwd(cwd,CWD_LN+2); printf("%s %%\n",cwd); #endif #ifdef UNIX /* no need to state directory as pwd does this */ printf("%%\n"); #endif if ((pb = getline()) == (char *)0 ) break ; #ifdef DEBUG printf("Command line is: %s.\n",pb); #endif /* append a second null for later use between end of line & end of command name */ pe = pb ; while (*pe++ != '\0') ; *pe = '\0'; /* find executable name */ while isspace(*pb++) ; pe = --pb ; while (!isspace(*pe) && (*pe != '\0')) pe++ ; *pe++ = '\0' ; while (isspace(*pe++)) ; pe-- ; /* pe now points to first char of 1st possible param (or \0 if end of line) */ strncpy(executable,pb,PATH_LN + EX_LEN); executable[PATH_LN + EX_LEN] = '\0' ; /* remove spaces between subsequent strings */ for( pp = ptr + 1, ptr[1] = "\0" ; (*pe != '\0'); /* mark end of array */ *pp = "\0" ) { while (isspace(*pe++)) ; /* store address of argument */ if (*--pe != '\0') { *pp++ = pe ; #ifdef DEBUG printf("next param start is %s\n",pe); #endif } else break ; while (!isspace(*pe) && (*pe != '\0')) pe++ ; *pe++ = '\0' ; } #ifdef DEBUG printf("Parameters including executable are:\n"); for ( pp=ptr ; **pp != '\0' ; pp++ ) printf("Parm is |%s|\n",*pp); if (executable[0] == '\0') continue ; /* empty line */ if ((executable[0] == CTL_D) || strequ(executable,EXITT)) { #ifdef DEBUG printf("Shell exiting.\n"); #endif exit(0) ; } /* test for inbuilt cd command */ if (strequ(CHDIR,executable) ) { if (*ptr[1] == '\0') { /* no directory named to change to, so change to login directory */ utmp = fopen(UTMP,"r"); fscanf(utmp,"%s",who_o); fclose(utmp); who_s = getpwnam(who_o); endpwent() ; ptr[1] = who_s->pw_dir; } if (chdir(ptr[1])) { printf("Failed to chdir to %s\n",ptr[1]); sh_result = 1 ; } continue ; } /* test for inbuilt set command */ /* export this */ if (strequ(SET,executable,strlen(SET)) ) { if (*(ptr[1]) != '\0') { #ifdef DEBUG printf("setting new env var %s\n",ptr[1]); #endif strcpy(putter,ptr[1]);strcat(putter,"\n"); putenv(putter); continue ; } /* else let code fall through so that a process called set does the display, (so output can be redirected if necessary) */ } /* prepare to call spawn */ strcat(executable,EX_EXT); #ifdef DEBUG printf("Executable file name is: %s.\n",executable); #endif pp = ptr ; #ifdef DEBUG while (**pp != '\0') printf("spawn env var is %s\n",*pp++); #endif #ifdef DEBUG printf("env path is %s\n",getenv("PATH")); #endif /* convert for spawn protocol */ pp = ptr ; while (**pp++ != '\0') ; *--pp = (char *)0 ; #ifdef MSDOS getcwd(cwd,CWD_LN+2); #endif #ifdef DEBUG printf("Calling command now\n"); #endif ret = spawnlp(P_WAIT,executable,executable,*(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7), *(ptr+8), *(ptr+9), *(ptr+10), *(ptr+11), *(ptr+12), *(ptr+13), *(ptr+14), *(ptr+15), *(ptr+16), *(ptr+17), *(ptr+18), *(ptr+19), *(ptr+20), (char *)0); #ifdef MSDOS /* unix doesnt need this */ chdir(cwd); #endif if (ret) printf("Command not found or failed.\n"); } }