sábado, 4 de setembro de 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); }

Um comentário:

  1. Boa tarde meu caro,

    Poderia me ajudar?? Quando mandei rodar, nao foi encontrado a biblioteca que voce denominou de mini-shell.h.

    Voce teria como disponibilizar??

    Grato.

    ResponderExcluir