/*- * main.c * Minishell C source * Shows how to use "obtain_order" input interface function. * * Copyright (c) 1993-2002-2019, Francisco Rosales * Todos los derechos reservados. * * Publicado bajo Licencia de Proyecto Educativo Práctico * * * Queda prohibida la difusión total o parcial por cualquier * medio del material entregado al alumno para la realización * de este proyecto o de cualquier material derivado de este, * incluyendo la solución particular que desarrolle el alumno. * * DO NOT MODIFY ANYTHING OVER THIS LINE * THIS FILE IS TO BE MODIFIED */ #include /* NULL */ #include /* setbuf, printf */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int obtain_order(); /* See parser.y for description */ extern char *environ[]; // ---------------------------------------------------------------------------- Funciones ------------ // Mandatos int mandato_simple(char **argv){ execvp(argv[0], argv); perror("Error al ejecutar el comando: "); return 1; } int mi_cd(char **argv){ char *directorio; if(argv[1]){ directorio=argv[1]; if(argv[2]){ fprintf(stderr,"cd: too many arguments\n"); return 1; } } else directorio=(getenv("HOME")); if(chdir(directorio)==0){ char cwd[1024]; getcwd(cwd,sizeof(cwd)); fprintf(stdout,"%s\n",cwd); return 0; } fprintf(stdout,"%s\n",directorio); perror("Error cd: "); return 1; } int mi_umask(char **argv){ char *mascara; char *endptr; if((mascara=(argv[1]))){ if(argv[2]){ fprintf(stderr, "umask: too many arguments\n"); return(1); } } else mascara = "0"; mode_t nueva_mascara = strtol(mascara,&endptr,8); if(endptr[0]||nueva_mascara==LONG_MIN||nueva_mascara==LONG_MAX){ fprintf(stderr,"umask: error en la mascara\n"); return 1; } umask(nueva_mascara); fprintf(stdout,"%o\n",nueva_mascara); return(0); } int mi_time(char **argv){ struct tms buf; int estado; char **argv_1; int tics_s; tics_s = sysconf(_SC_CLK_TCK); double usuario=0, sistema=0; if(argv[1]){ //si se le ha pasado mandato argv_1=&argv[1]; switch(fork()){ case -1: perror("Error al llamar a fork: "); return 1; //HIJO case 0: mandato_simple(argv_1); exit(1); default: if (wait(&estado) == -1){ perror("time: error wait: "); return 1; } else if (!WIFEXITED(estado)){ fprintf(stderr,"El hijo no ha terminado con exito"); return 1; } else if (times(&buf) == -1){ perror("time: times(): "); return 1; } usuario=((double)buf.tms_cutime)/tics_s; sistema=((double)buf.tms_cstime)/tics_s; } } else { if (times(&buf) == -1){ perror("time: times(): "); return 1; } usuario=((double)buf.tms_utime)/tics_s; sistema=((double)buf.tms_stime)/tics_s; } fprintf(stdout,"%d.%03du %d.%03ds %d.%03dr\n", (int)usuario, (int)(1000*(usuario-(int)usuario)), //usuario (int)sistema, (int)(1000*(sistema-(int)sistema)), //sistema (int)usuario + (int)sistema, (int)(1000*(usuario + sistema - (int)usuario - (int)sistema))); //conjunto return 0; } int mi_read(char **argv){ int argc=0; char *buffer=calloc(100,sizeof(char)); fgets(buffer, 100, stdin); char *token; char *var=NULL; if(!argv[1]){ fprintf(stderr,"Read sin argumentos\n"); return 1; } // no hay variables por cambiar if(argv[2]) // si hay mas de una variable token = strtok(buffer, " \t\n\r"); else token = strtok(buffer, "\n\r"); // si es la ultima variable, se le asignan todos los valores que quedan for(argc=1;argv[argc];argc++){ if (token==NULL) // comprobar que quedan valores break; // Se modifica el valor de la variable de entorno. if ((var = (char *)malloc(strlen(token)+strlen(argv[argc]))+strlen("=")+2) == NULL){ perror("mi_read: malloc:"); return 0; } strcpy(var, argv[argc]); //copia el nombre de la variable strcat(var, "="); //suma el igual strcat(var, token); //suma el token o la palabra if(putenv(var)!=0){ //cambia el valor perror("mi_read: putenv: "); return 1; } //printf("%s\n",getenv(argv[argc])); if(argv[argc+2]) token = strtok(NULL, " \t\n\r"); else token = strtok(NULL, "\n\r"); // si es la ultima variable, se le asignan todos los valores que quedan } return 0; } int metacaracteres(char ***argvv){ int argvc; int argc; char *valor_var = calloc(128,sizeof(char)); char *despues = calloc(100,sizeof(char)); char *antes = calloc(100,sizeof(char)); struct passwd *usuario; int formato; char **argv = NULL; char *var = calloc(100,sizeof(char)); for(argvc = 0; (argv = argvv[argvc]); argvc++){ for(argc = 0; argv[argc]; argc++){ if(argv[argc][0]=='$'){ formato=sscanf(argv[argc],"$%[_a-zA-Z0-9]%[^ \n\t\r]",var,despues); strcpy(antes,""); } else formato=sscanf(argv[argc],"%[^$]$%[_a-zA-Z0-9]%[^ \n\t\r]",antes,var,despues); if(formato==-1){ fprintf(stderr,"Error en la llamada sscanf\n"); return(1); } if(formato>1||(argv[argc][0]=='$'&&formato>0)){ // si no se ha encontrado $, siguiente //printf("%s\n",despues); valor_var=getenv(var); // obtenemos el valor de la variable if(valor_var==NULL){ continue; //no lo cambiamos si no lo encuentra } argv[argc]=realloc(argv[argc],strlen(valor_var)+strlen(despues)+strlen(antes)+2); if(argv[argc]==NULL){ perror("metacaracteres: realloc: "); return 1; } strcat(antes,valor_var); strcat(antes,despues); strcpy(argv[argc],antes); memset(antes,0,100); memset(despues,0,100); } if(argv[argc][0]=='~'){ if(!argv[argc][1]){ valor_var=getenv("HOME"); } else{ formato=sscanf(&argv[argc][1],"%[_a-zA-Z0-9]",var); if(formato==-1){ fprintf(stderr,"Error en la llamada sscanf2\n"); return(1); } if(formato==0) continue; usuario=getpwnam(var); valor_var=usuario->pw_dir; } if(valor_var==NULL){ strcpy(argv[argc],"\0"); continue; } argv[argc]=realloc(argv[argc],strlen(valor_var)); strcpy(argv[argc],valor_var); } } } return 0; } int tiene_barra(char *string){ int i; for(i=0;string[i];i++) if(string[i]=='/') return 1; return 0; } int tiene_cuestion(char *string){ int i; for(i=0;string[i];i++) if(string[i]=='?') return 1; return 0; } // ----------------------------------------------------------------------------- Main ----------------------------- int main(void) { char ***argvv = NULL; int argvc; char **argv = NULL; int argc; char *filev[3] = { NULL, NULL, NULL }; int bg; int ret; pid_t pid = 1; setbuf(stdout, NULL); /* Unbuffered */ setbuf(stdin, NULL); int original_stdin, original_stdout, original_stderr, ultimo_stdout=6; int bgpid; int fd [2]; int salida_viejo=7, entrada_nuevo; //Salida del viejo pipe y entrada del nuevo pipe // Configurar manejador de señales signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); //Guardado estandares originales que se cierran si un exec es ejecutado con exito original_stdin=fcntl(0, F_DUPFD_CLOEXEC,0); original_stdout=fcntl(1, F_DUPFD_CLOEXEC,0); original_stderr=fcntl(2, F_DUPFD_CLOEXEC,0); // Declaracion de las variables especiales // mypid pid_t mypid = getpid(); char *string_pid=calloc(32,sizeof(char)); sprintf(string_pid, "%d", mypid); //printf(string_pid); char *var = calloc(64,sizeof(char)); strcpy(var,"mypid="); strcat(var,string_pid); putenv(var); // prompt putenv("prompt=msh> "); // -------------------------------------------------------------------minichel + prompt----------------- while (1) { // Nueva linea fprintf(stderr, "%s", "msh> "); /* Prompt */ ret = obtain_order(&argvv, filev, &bg); if (ret == 0) break; /* EOF */ if (ret == -1) continue; /* Syntax error */ argvc = ret - 1; /* Line */ if (argvc == 0) continue; /* Empty line */ // Sustitucion de $ o ~ if(metacaracteres(argvv)==1) // si surge un error al cambiar los metacaracteres, no se ejecuta continue; // Cambio entrada, salida y salida de error estandar: // Entrada estandar if (filev[0]){ close(0); if(open(filev[0], O_RDONLY)<0){ perror("Error al arbir el fichero de entrada: "); dup2(original_stdin,0); continue; //nueva linea } } // Salida estandar. (guardamos el stdout para futuro) if (filev[1]){ close(1); creat(filev[1], 0666); } // Salida de error estandar if (filev[2]){ close(2); creat(filev[2], 0666); } dup2(0,salida_viejo); // la primera entrada es la entrada estandar if((ultimo_stdout=fcntl(1, F_DUPFD_CLOEXEC))==-1){ perror("error:"); continue; } // guardado de la salida actual for(argvc = 0; argvv[argvc]; argvc++){ for(argc = 0; argvv[argvc][argc]; argc++){ if(!tiene_barra(argvv[argvc][argc])&&tiene_cuestion(argvv[argvc][argc])){ char **lista_nombres; int size; glob_t globo; if(glob(argvv[argvc][argc],GLOB_ERR,NULL, &globo)==0){ lista_nombres=globo.gl_pathv; size=globo.gl_pathc; if(size>0){ int size_argv; for(size_argv=0;argvv[argvc][size_argv];size_argv++); argvv[argvc] = realloc(argvv[argvc], sizeof(char*)*(size_argv + size)); memmove(&argvv[argvc][argc+size], &argvv[argvc][argc+1], sizeof(char*)*(size_argv-argc)); memmove(&argvv[argvc][argc], lista_nombres, sizeof(char*)*(size)); } } } } } // Bucle para argumentos for (argvc = 0; (argv = argvv[argvc]); argvc++){ // Creacion pipe nuevo mientras no sean ultimo hijo if(argvc0) close(fd[0]); //opcion background if(!bg){ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); } //mandatos internos if(!strcmp(argv[0],"cd")) exit(mi_cd(argv)); if(!strcmp(argv[0],"umask")) exit(mi_umask(argv)); if(!strcmp(argv[0],"time")) exit(mi_time(argv)); if(!strcmp(argv[0],"read")) exit(mi_read(argv)); //mandatos simples mandato_simple(argv); exit(0); } //actualizacion punteros if(argvc