Saturday, September 4, 2010

Uma implementação em C de um Mini-Shell

Sistemas Operacionais é bem legal, né? Esse é um Mini-Shell com comandos de mudança e listagem de diretórios (cd e ls) e também de mudança de permissões de arquivos (chmod).

 #include <stdio.h> /* fgets, printf */#include <string.h> /* strlen, strcmp, strtok */#include <stdlib.h> /* exit, NULL, EXIT_FAILURE, EXIT_SUCCESS, free */#include <sys/time.h> /* gettimeofday, struct timeval */#include <sys/resource.h> /* getrusage, struct rusage, RUSAGE_SELF */#include <sys/types.h> /* pid_t */#include <unistd.h> /* fork, chdir, getcwd */#include <sys/wait.h> /* waitpid */#include <dirent.h> /* scandir, struct dirent, alphasort */#include <sys/stat.h> /* chmod */#include "mini-shell.h" /* MAXLINE, MAXARGS, printInformations, cd, fim isPrimitiveCommand, executePrimitiveCommand */int main() { char path[PATH_MAX]; char buffer[MAXLINE]; char *command; char * arguments[MAXARGS]; int i, primitiveCommand; double start, finish; struct timeval timeval; struct rusage rusageParent, rusageChildren; printf("\n Mini-Shell - EP1 - SO (2006)\n\n"); while (1) { getcwd(path, PATH_MAX); /* Lendo nova entrada */ for(i = 0; i < MAXARGS; i++) arguments[i] = NULL; printf("%s > ", path); fgets(buffer, MAXLINE, stdin); /* Comecando a cronometrar o tempo de processamento */ if(gettimeofday(&timeval, NULL) != 0) perror("gettimeofday error"); start = (double)timeval.tv_sec + ((double)timeval.tv_usec * 1e-6); /* Lendo comando */ if (strlen(buffer) > 0) buffer[strlen(buffer) - 1] = '\0'; command = strtok(buffer, " "); if (command != NULL) { /* Lendo argumentos */ arguments[0] = command; /* Convention (man exec) */ i = 1; while(i < MAXARGS && (arguments[i++] = strtok(NULL, " ")) != NULL); /* Verificando comandos primitivos do mini-shell */ if((primitiveCommand = isPrimitiveCommand(command))) executePrimitiveCommand(command, arguments); else executeCommand(command, arguments); /* Terminando de cronometrar o tempo de processamento */ if(gettimeofday(&timeval, NULL) != 0) perror("gettimeofday error"); finish = (double)timeval.tv_sec + ((double)timeval.tv_usec * 1e-6); printf("\nInformacoes\n"); printf("- Tempo de Processamento: %.3f s\n", finish - start); printf("\nPai:\n"); if(getrusage(RUSAGE_SELF, &rusageParent) != 0) perror("getrusage error"); else printRUsageInformation(rusageParent); if(!primitiveCommand) { printf("\nFilho(s):\n"); if(getrusage(RUSAGE_CHILDREN, &rusageChildren) != 0) perror("getrusage error"); else printRUsageInformation(rusageChildren); } printf("\n"); } } exit(EXIT_SUCCESS);}void executeCommand(const char *command, char *const arguments[]) { pid_t pid; int status; /* fork */ if ((pid = fork()) < 0) perror("fork error"); if(pid == 0) { /* Child */ execvp(command, arguments); /* Executando comando */ perror("couldn't execute"); exit(EXIT_FAILURE); } if((pid = wait(&status)) < 0) /* Parent */ perror("waitpid error");}int isPrimitiveCommand(const char *command) { if(strcmp(command, "fim") == 0) return 1; if(strcmp(command, "cd") == 0) return 1; if(strcmp(command, "ls2") == 0) return 1; if(strcmp(command, "chmod2") == 0) return 1; return 0;}void executePrimitiveCommand(const char *command, char *const arguments[]) { if(strcmp(command, "fim") == 0) fim(); else if(strcmp(command, "cd") == 0) cd(arguments[1]); else if(strcmp(command, "ls2") == 0) ls2(arguments); else if(strcmp(command, "chmod2") == 0) chmod_call(arguments);}void fim() { printf("\n"); exit(EXIT_SUCCESS);}void cd(const char *path) { if(chdir(path) != 0) perror("chdir error");}void ls2(char *const arguments[]) { struct dirent **namelist; int n; n = scandir(".", &namelist, 0, alphasort); if(n < 0) perror("scandir"); else { while(n--) { printf("%s\n", namelist[n]->d_name); free(namelist[n]); } free(namelist); }}void chmod_call(char *const arguments[]) { /*owner, group, others */ int all = 0, owner = 0, group = 0, others = 0; if(arguments[1] == NULL || arguments[2] == NULL) { perror("chmod: poucos argumentos"); return; } all = atoi(arguments[1]); owner = all / 100; group = (all % 100) / 10; others = all % 10; if(myChmod(arguments[2], owner, group, others) != 0) perror("myChmod error");}/* 7 XWR 1 X 2 W 4 R S_IRWXU Read, write, execute/search by owner. S_IRUSR Read permission, owner. S_IWUSR Write permission, owner. S_IXUSR Execute/search permission, owner. S_IRWXG Read, write, execute/search by group. S_IRGRP Read permission, group. S_IWGRP Write permission, group. S_IXGRP Execute/search permission, group. S_IRWXO Read, write, execute/search by others. S_IROTH Read permission, others. S_IWOTH Write permission, others. S_IXOTH Execute/search, others.*/int myChmod(const char* path, int owner, int group, int others) { mode_t o = 0, g = 0, t = 0; if(owner / 4) { o = S_IRUSR; owner -= 4; } if(owner / 2) { o = o|S_IWUSR; owner -= 2; } if(owner / 1) { o = o|S_IXUSR; } if(group / 4) { g = S_IRGRP; group -= 4; } if(group / 2) { g = g|S_IWGRP; group -= 2; } if(group / 1) { g = g|S_IXGRP; } if(others / 4) { t = S_IROTH; others -= 4; } if(others / 2) { t = t|S_IWOTH; others -= 2; } if(others / 1) { t = t|S_IXOTH; } return chmod(path, o|g|t);}void printRUsageInformation(struct rusage rusage) { printf("- Tempo de Usuario: %ld ms\n", (rusage.ru_utime.tv_sec * 1000) + (rusage.ru_utime.tv_usec / 1000)); printf("- Tempo de Sistema: %ld ms\n", (rusage.ru_stime.tv_sec * 1000) + (rusage.ru_stime.tv_usec / 1000)); printf("- Numero de Page Faults: %ld\n", rusage.ru_minflt); printf("- Numero de Page Reclaims: %ld\n", rusage.ru_majflt); printf("- Numero de Sinais Recebidos: %ld\n", rusage.ru_nsignals); printf("- Mudancas de Contexto Voluntarias: %ld\n", rusage.ru_nvcsw); printf("- Mudancas de Contexto Involuntarias: %ld\n", rusage.ru_nivcsw);}

No comments:

Post a Comment