microshell.c
00001 #include <sys/types.h>
00002 #include <sys/wait.h>
00003 #include <errno.h>
00004 #include <fcntl.h>
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <unistd.h>
00009
00010 #define LINESIZE 200
00011 #define MAXARGNUM 15
00012
00013 static inline int carspecial(char c) {
00014 if (c == ' ' || c == ';' || c == '&' || c == 0 || c == '\n' || c == '>')
00015 return 1;
00016 return 0;
00017 }
00018
00019 static int separateurpresent(char *ligne, int *mustwait, int *fdout) {
00020 switch (ligne[0]) {
00021 case '&':
00022 *mustwait = 0;
00023
00024 case ';':
00025 ligne[0] = '\0';
00026 return 1;
00027 case '>':
00028 ligne[0] = '\0';
00029 int i = 1;
00030 while (ligne[i] == ' ') {i++;}
00031 char* fichier = ligne + i;
00032 while (!carspecial(ligne[i])) {i++;}
00033 if (ligne[i] != 0) ligne[i++] = 0;
00034 *fdout = open(fichier, O_WRONLY | O_CREAT | O_TRUNC, 0644);
00035 if (*fdout < 0) fprintf(stderr, "%s\n", strerror(errno));
00036 return i;
00037 }
00038 return 0;
00039 }
00040
00041 static int comprendrecommande(char **argv, char *ligne, int offset, int *mustwait,
00042 int *fdout)
00043 {
00044 int j = 1;
00045 int i = offset;
00046 while (ligne[i] == ' ' || ligne[i] == ';' || ligne[i] == '&') i++;
00047 if (ligne[i] == 0) return -1;
00048 argv[0] = ligne + i;
00049 while (ligne[i] && ligne[i] != '\n'
00050 && ligne[i] != ';' && ligne[i] != '&' && ligne[i] != '>') {
00051 if (ligne[i] == ' ') {
00052 ligne[i] = '\0';
00053 if (!carspecial(ligne[i+1])) {
00054 argv[j++] = ligne + i + 1;
00055 if (j == MAXARGNUM) return -10;
00056 }
00057 }
00058 i++;
00059 }
00060 argv[j] = NULL;
00061 int ret = separateurpresent(ligne + i, mustwait, fdout);
00062 if (ret) return i + ret;
00063 return 0;
00064 }
00065
00066 static int executer(char* ligne) {
00067 char *argv[MAXARGNUM + 1];
00068 int offset = 0;
00069 do {
00070 int ret;
00071 int mustwait = 1;
00072 int fdout = -2;
00073 offset = comprendrecommande(argv, ligne, offset,
00074 &mustwait, &fdout);
00075 if (offset == -1) break;
00076 if (offset == -2) continue;
00077 if (offset < -2) {
00078 fprintf(stderr, "Erreur de compréhension"
00079 " (trop d'arguments?) !");
00080 return -1;
00081 }
00082
00083 ret = fork();
00084 if (ret < 0) {
00085 fprintf(stderr, "Impossible de forker !");
00086 exit(EXIT_FAILURE);
00087 }
00088 if (ret == 0) {
00089 if (fdout > 0)
00090 dup2(fdout, STDOUT_FILENO);
00091 close(fdout);
00092 execvp(argv[0],argv);
00093 fprintf(stderr, "%s\n", strerror(errno));
00094 exit(EXIT_FAILURE);
00095 }
00096 if (fdout > 0)
00097 close(fdout);
00098 if (mustwait)
00099 waitpid(ret, NULL, 0);
00100 else
00101 mustwait = 1;
00102 while (waitpid(-1, NULL, WNOHANG) > 0);
00103 } while (offset > 0);
00104 return 0;
00105 }
00106
00107 static int lire(char* ligne) {
00108 int ret = read(STDIN_FILENO, ligne, LINESIZE);
00109 switch (ret) {
00110 case 0:
00111 exit(EXIT_SUCCESS);
00112 case LINESIZE:
00113 fprintf(stderr, "ligne trop longue: ignorée\n");
00114 while (read(STDIN_FILENO, ligne, LINESIZE) >= LINESIZE);
00115 return -1;
00116 default:
00117 ligne[ret - 1] = 0;
00118 break;
00119 }
00120 return 0;
00121 }
00122
00123 static void afficheprompt(void) {
00124 printf(":");
00125 fflush(stdout);
00126 }
00127
00128 int main()
00129 {
00130 while(1) {
00131 char ligne[LINESIZE];
00132 afficheprompt();
00133 if (lire(ligne)) continue;
00134 if (executer(ligne)) continue;
00135 }
00136 return EXIT_FAILURE;
00137 }