============================================================================================ Á¦ ¸ñ : Making Your Own Linux Shell ÀÛ¼ºÀÏÀÚ : 2002. 10. 12 ¼öÁ¤ÀÏÀÚ : 2002. 12. 01 ¹®¼­¹öÁ¯ : ver 0.0.1 ¶óÀ̼¾½º : GPL ¹è°æÁö½Ä : C Language, ÆÄÀÌÇÁ, ¸®´ÙÀÌ·º¼Ç, ÆÄ½Ì ============================================================================================ ======================================================= * Áغñ¹° - i386ÀÌ»ó - ¸®´ª½º ¸Ó½Å - binutils, gcc, vi * test ȯ°æ - os : debian linux (2.4.18) - processor : pentium IV 1.7Ghz - ram : 512MB - VMWare 3.0(À©µµ¿ì ¸Ó½ÅÀ§¿¡ vmware ¸¦ ¿Ã¸®°í ±×À§¿¡ Linux) * ÂüÁ¶¹®Çå : ADVANCED UNIX PROGRAMMING (Marc J. Rochkind - prentice hall) Advanced Programming in the Unix Environment (W.Richard Stevens - Addison wesley) GNU C REFERENCE GUIDE ú·ãý Unix Programming (È«¸ª°úÇÐÃâÆÇ»ç) ½©Àº ±×³É »ç¿ëÇϱâÀ§ÇÑ ¿ëµµ·Î¸¸ ½è¾úÁö °áÄÚ ¸¸µé¾îº»ÀûÀÌ ¾ø¾ú±â ¶§¹®¿¡ È£±â½É¿¡ ½ÃÀÛÇؼ­ ¸®´ª½ºÀÇ ¿©·¯°¡Áö °³³äµéÀ» ¸¹ÀÌ ¾Ë°ÔµÈ°Å °°½À´Ï´Ù. ±×·¡¼­ ¹®¼­°¡ Á¶±Ý ÀÌ»óÇÏ´õ¶óµµ ÀÌ»óÇÑ ³»¿ëÀº ¹Ù·Î ¸ÞÀÏ·Î ¾Ã¾îÁÖ¼¼¿ä. Á¦°¡ °ËÁõ ÈÄ ¹Ù·Î °íÃļ­ ¾÷µ¥ÀÌÆ® ÇÏ°Ú½À´Ï´Ù. ======================================================= 1. Linux Shell ¸¸µé±â 1-1) Shell ¿¡´Â ¹«¾ùÀÌ ÇÊ¿äÇÒ±î ? ¿ì¼± Login shell °³³äÀº ¾ÆÁ÷Àº Ãß°¡ÇÏÁö ¾ÊÀ» »ý°¢À̸ç, ¸¸µé±â ½ÃÀÛÇÒ ½©Àº ¾ÆÁÖ °£´ÜÇÑ °³³äÀ» ÀÍÈ÷±â À§ÇÑ ½©ÀÌ µÉ°ÍÀÌ´Ù. ½©¿¡´Â ¹«¾ùÀÌ ÇÊ¿äÇÒÁö ¿ì¼± »ý°¢À» Çغ¸´Ï, - ½© ÇÁ·ÒÇÁÆ® Ãâ·Â ( debian:~root#) - »ç¿ëÀÚ ÀÔ·Â (find / | grep myshell > find.txt) - ÀÔ·Â ¶óÀÎ ÆÄ½Ì (find, |, grep, myshell, >, find.txt) - redirection and pipe ±×¸®°í creat file (redirection, creat file : ls > file.txt pipe : ls | more) - ¸í·É¾î ½ÇÇà (exec °è¿­ ½Ã½ºÅÛÄÝ »ç¿ë) - background or foreground ÇÁ·Î¼¼½ºÁ¦¾î (mysqld&) 1-2) ±×¿Ü¿¡ ¾î¶²°ÍµéÀÌ ÇÊ¿äÇÒ±î ? - Å͹̳ΠÁ¦¾î ¹Þ¾Æ¿À±â - ÆÄÀÏ¸í ¶Ç´Â µð·ºÅ丮À̸§ ÀÚµ¿¿Ï¼º ±â´É (tab) - »ç¿ëÀÚ ÀÔ·Â history ... µîµî 2. Shell ÀÇ ºÎºÐ °³³äÁ¤¸® ¹× ¼Ò½ºÄÚµå ÀÛ¼ºÇϱâ 2-1) ½© ÇÁ·ÒÇÁÆ® Ãâ·Â °³³ä ¿©·¯°¡Áö ½©¸¶´Ù ´Ù¸£°ÚÁö¸¸ ½©À̸§(bash), hostname(osx86), path(root), ±×¸®°í ±ÇÇÑÁö½ÃÀÚ(# or $) Á¤µµ°¡ µé¾î°¡°Ô µÈ´Ù. ½©À̸§À̳ª hostname Àº °ÅÀÇ °íÁ¤ÀûÀÌ°ÚÁö¸¸ path ´Â ¼ö½Ã·Î ¹Ù²î°Ô µÇ°í, ±ÇÇÑ Áö½ÃÀÚµµ ½Å°æ½á¾ß µÉÅ×Áö¸¸ ÇÁ·ÒÇÁÆ® Ãâ·Â¹®µµ ÇÔ¼ö·Î ±¸ÇöÇصθé ÆíÇÒ°ÍÀÌ´Ù. 2-2) ½© ÇÁ·ÒÇÁÆ® Ãâ·Â ¼Ò½º °£´ÜÈ÷ ½©À̸§Á¤µµ¸¸ ½Å°æ½á¼­ Çغ¸ÀÚ. (½©À̸§ : µð·ºÅ丮) ====================================================================== !source : print_prompt.c #include #define MAX_PATH 100 #define LF 10 int print_prompt() { char *buffer = (char *)malloc(MAX_PATH); char *value = (char *)getcwd (buffer, MAX_PATH); if (value != 0) fprintf(stdout,"jsh:%s>",buffer); free (buffer); return 0; } int main() { char c; while((c=getchar())!=EOF) if(c==LF) print_prompt(); return 0; } ====================================================================== ÀÌ·¸°Ô ÀÛ¾÷ÇϽðí, ÀÌÁ¦ ÄÄÆÄÀÏÇÏ°í ½ÇÇàÈ­ÀÏ·Î ¸¸µé¾î¾ß °ÚÁÒ. #gcc -o jsh jsh.c error ³ª warning ¾ø´Â ±ò²ûÇÑ ÀÔ·ÂâÀÌ µË´Ï´Ù ^^; #./jsh ÀÌ·¸°Ô ½ÇÇàÇØÁֽøé ... jsh:/root> »ç¿ëÀÚ ÀÔ·Â °¡´ÉÇÑ ÇüÅ°¡ µÇÁÒ ... ¼Ò½º¸¦ °£´ÜÈ÷ º¸¸é getcwd ¶ó´Â ÇÔ¼ö°¡ ´Ù ÇÕ´Ï´Ù. -_-;; current working directory ÀÇ ¾àÀÚÀΰ¡ º¾´Ï´Ù. ù¹ø° ÀÎÀÚ¿¡ char ¹öÆÛ¸¦ ÁÖ°í, µÎ¹ø° ÀÎÀÚ¿¡ ¹öÆÛ Å©±â¸¦ ÁÖ¸é ÇöÀç ÀÛ¾÷ µð·ºÅ丮°¡ ¹ÝȯµÇ°Ô µÇÁÒ. º¸Åë ½©¿¡¼­ pwd ¶û ºñ½ÁÇÑ°¡¿ä ? (ÀÌ°Ç present working directory ÀÇ ¾àÀÚÀϱî¿ä -_-;;) GNU C ¶óÀ̺귯¸® ·¹ÆÛ·±½º °¡À̵åÀΰ¡¿¡ º¸¸é getcwd ÇÔ¼ö°¡ char *¸¦ ¹ÝȯÇÑ´Ù°í Çؼ­ -_- °Á ›§´õ´Ï¸¸, warning ÀÌ ¶ß´õ±º¿ä. ±×·¡¼­ char * ·Î ´Ù½Ã Çüº¯È¯ÇØÁÖ°í ½èÀ½´ç... 2-3). »ç¿ëÀÚ ÀԷ°ú ÆÄ½Ì »ç¿ëÀÚ ÀԷ°ú ÆĽÌÀÌ ½©¿¡¼­ Å« ºÎºÐÀ» Â÷ÁöÇÏ°Ô µÇÁÒ ... »ç¿ëÀÚ°¡ ¸¸¾à bash ¿¡¼­ bash > ls °ú °°Àº ¸í·É¸¸ ÀÔ·ÂÇÑ´Ù¸é ¾ó¸¶³ª ÁÁ°Ú½À´Ï±î ? bash > ls | more > test.txt bash > ls -al | more >> test.txt À§¿Í °°ÀÌ ÀÔ·ÂÇÑ´Ù¸é ÀÌ·± °æ¿ì´Â ¾î¶»°Ô ó¸®ÇÒ±î¿ä ... ±×¶§ºÎÅÍ º¹ÀâÇØÁö±â ½ÃÀÛÇÕ´Ï´Ù. ÆÄÀÌÇÁ¿Í ¸®´ÙÀÌ·º¼Ç µîÀÇ Ã³¸®¿Í ÇÔ²² ¹°¸®±â ¶§¹®ÀÌ°ÚÁÒ. 2-4). »ç¿ëÀÚ ÀԷ°ú ÆÄ½Ì ±¸Çö ¿ì¸®°¡ ÇؾߵÉÀÏÀº °¢ ¹®ÀÚµéÀÌ ¿ÔÀ»¶§ ±×¸¦ ºÐ¸®Çس»´Â ÀÏÀÔ´Ï´Ù. ¾Æ·¡ÀÇ Äڵ带 º¸¸é¼­ Çغ¸µµ·Ï ÇÏÁÒ ... ====================================================================== !source : getsymb.c #include typedef enum {S_WORD, S_BAR, S_AMP, S_SEMI, S_GT, S_GTGT, S_LT, S_NL, S_EOF} SYMBOL; typedef enum {NEUTRAL, GTGT, INQUOTE, INWORD} STATUS; SYMBOL getsymb(char *word) { // º¯¼öÁ¤ÀÇ ºÎºÐ STATUS state; int c; char *w; state = NEUTRAL; // »óÅÂÃʱâÈ­ w = word; // word ¿Í pointer ·Î ¹°·Á ÇÔ¼ö°¡ ³¡³ªµµ word ¿¡ °ªÀ» º¸Á¸ÇÒ¼ö ÀÖ°Ô // »ç¿ëÇÏ°Ô µË´Ï´Ù. while ((c = getchar()) != EOF) { switch (state) { // óÀ½¿¡ »óŸ¦ NEUTRAL ·Î ÃʱâÈ­ ÇßÀ¸¹Ç·Î NEUTRAL ·Î case NEUTRAL : switch (c) { // ½©¿¡ ; & | < \n ÀÌ°°Àº ¸í·ÉÀ» ³»¸®¸é ÇÒÀÏÀÌ ¾ø°ÚÁÒ. ÇÔ¼ö ¸®ÅÏÇÕ´Ï´Ù. case ';' : return S_SEMI; case '&' : return S_AMP; case '|' : return S_BAR; case '<' : return S_LT; case '\n': return S_NL; // °ø¹é¹®ÀÚ³ª ÅÇ ÀÏ °æ¿ì´Â ´Ù½Ã ¹®ÀÚ¸¦ ÀÔ·Â ¹Þ½À´Ï´Ù. case ' ' : case '\t': continue; case '>' : // ¸®´ÙÀÌ·º¼Ç(stdout to stdin ÀÏ°æ¿ì) state = GTGT; // >>(GTGT) »óÅ°¡ µÉ¼ö ÀÖÀ¸¹Ç·Î state ¸¦ ¹Ù²Ù°í continue; // ´ÙÀ½ ¹®ÀÚÀÔ·Â case '"' : // " °¡ ÀԷµɰæ¿ì ¹®ÀÚ¿­·Î °£ÁÖÇÏ°í state = INQUOTE; // INQUOTE »óÅ°¡ µÇ°í continue; // ´ÙÀ½¹®ÀÚ ÀÔ·Â default : state = INWORD; // ±×¿Ü ¹®ÀÚ°¡ ÀԷµɰæ¿ì INWORD »óÅ·Π󸮵ǰí, *w++ = c; // ¹®ÀÚ¸¦ w °¡ °¡¸®Å°´Â°÷¿¡ ÀúÀåÇÏ°í w ÁÖ¼Ò¸¦ 1Áõ°¡ continue; // ´ÙÀ½¹®ÀÚ ÀÔ·Â } case GTGT: // ÇϳªÀÇ > °¡ ÀԷµǾî Àִ°æ¿ì GTGT »óÅ°¡µÇ´Âµ¥ if (c == '>') return S_GTGT; // > Çϳª°¡ ´õ Ãß°¡µÉ°æ¿ì S_GTGT ¸¦ ¸®ÅÏÇÑ´Ù. ungetc(c, stdin); return S_GT; // ¾Æ´Ñ°æ¿ì´Â S_GT ¸®ÅÏ case INQUOTE: switch (c) { case '\\' : // ¹®ÀÚ¿­¿¡¼­ \\ ¹®ÀÚ°¡ ÀԷµǸé *w++ = getchar(); // ¹®ÀÚÀÔ·Â ¹Þ°í, w ÁÖ¼ÒÁõ°¡ continue; // ´Ù½Ã ¹®ÀÚ ÀÔ·Â case '"' : // INQUOTE »óÅ¿¡¼­ " Çϳª°¡ ´õ ÀԷµǸé *w = '\0'; // Á¾·á¹®ÀÚ¸¦ ³Ñ±â°í return S_WORD; // S_WORD ¸¦ ¸®ÅÏ default : *w++ = c; // ±×¿ÜÀÇ ¹®ÀÚ°¡ µé¾î¿Ã°æ¿ì¿¡´Â w ¿¡ ÀúÀåÈÄ ÁÖ¼ÒÁõ°¡ continue; // ¹®ÀÚ ÀÔ·Â } case INWORD: switch (c) { // INWORD »óÅ¿¡¼­ ; & | < > \n ' ' \t ¹®ÀÚÀÏ °æ¿ì¿¡´Â case ';' : case '&' : case '|' : case '<' : case '>' : case '\n': case ' ' : case '\t': ungetc(c, stdin); *w = '\0'; // Á¾·á¹®ÀÚ Ãß°¡ÇÏ°í return S_WORD; // S_WORD ¸®ÅÏ default : *w++ = c; // ´Ù¸¥ ¹®ÀÚÀΰæ¿ì¿¡´Â ¹®ÀÚÀúÀåÇÏ°í w ÁÖ¼ÒÁõ°¡ continue; // ¹®ÀÚ ÀÔ·ÂÀ¸·Î °è¼Ó } } } return S_EOF; } int main() { char word[200]; // getsymb ÇÔ¼ö¿¡¼­ w ·Î Àå³­À» Ä¡¸é °á°ú´Â word ¿¡ ÀúÀåµÈ´Ù. while(1) switch(getsymb(word)) { // °á°ú Ãâ·Â¹® case S_WORD : printf("S_WORD<%s>\n", word); break; case S_BAR : printf("S_BAR\n"); break; case S_AMP : printf("S_AMP\n"); break; case S_SEMI : printf("S_SEMI\n"); break; case S_GT : printf("S_GT\n"); break; case S_GTGT : printf("S_GTGT\n"); break; case S_LT : printf("S_LT\n"); break; case S_LN : printf("S_LN\n"); break; case S_EOF : printf("S_EOF\n"); exit(0); } return 0; } ====================================================================== ÀÏ´Ü ¿ç¶ó ±äµ¥, º°°Í ¾ø½À´Ï´Ù. ÀüºÎ CASE ó¸®ÀÏ»ÓÀÌÁÒ ... ¿ì¼± µÎ¶óÀÎÀ» ¸ÕÀú º¸ÁÒ ... //////////////////////////////////////////////////////////////////////// typedef enum {S_WORD, S_BAR, S_AMP, S_SEMI, S_GT, S_GTGT, S_LT, S_NL, S_EOF} SYMBOL; /* SYMBOL Àº ÀÔ·ÂµÈ ½É¹úÀÇ Á¾·ù ÀÔ´Ï´Ù. ¹®ÀÚÀΰ¡(S_WORD), ÆÄÀÌÇÁ¸¦ À§ÇÑ ¹ÙÀΰ¡, (S_BAR), Á¾·á ½É¹úÀÎ ¼¼¹ÌÄÝ·ÐÀΰ¡(S_SEMI), ¸®´ÙÀÌ·º¼ÇÀ» À§ÇÑ > Àΰ¡(S_GT), ±× ¹Ý´ëÀÎ< Àΰ¡ (S_LT), ¸®´ÙÀÌ·º¼Ç APPEND ¸¦ À§ÇÑ >> Àΰ¡(S_GTGT), ´º¶óÀÎ ¹®ÀÚÀΰ¡(S_NL), ³¡À» ³ªÅ¸³»´Â EOF Àΰ¡(S_EOF) */ typedef enum {NEUTRAL, GTGT, INQUOTE, INWORD} STATUS; /* STATUS ´Â ¹®ÀåÀÇ ¿À·ù°¡ ã±âÀ§ÇÑ »óÅ ÄÚµåµé ÀÔ´Ï´Ù. NEUTRAL Àº º¸ÅëÀÇ °æ¿ìÀÌÁÒ. GTGT ´Â > °¡ ÀÔ·ÂµÈ ÀÌÈĸ¦ À§ÇÑ »óÅÂÄÚµå ÀÔ´Ï´Ù. INQUOTE ´Â ÄõÅÍ(") ¾È¿¡ µé¾î¿Í ÀÖÀ»°æ¿ì ¹®ÀÚ¿­ ÀÔ·Â »óÅ ÄÚµåÀÔ´Ï´Ù. INWORD ´Â À̾îÁö´Â ¹®ÀÚµéÀ» À§ÇÑ »óÅ ÄÚµåÀÔ´Ï´Ù. */ //////////////////////////////////////////////////////////////////////// ³ª¸ÓÁö´Â ¼Ò½ºÄڵ峻¿¡ ÁÖ¼®Ã³¸®¸¦ Çß½À´Ï´Ù. INQUOTE »óųª INWORD »óÅ´ °è¼ÓµÈ ¹®ÀÚÀÔ·ÂÀ» ¹Þ°ÔµÇÁÒ GTGT »óÅ´ óÀ½¿¡ > Çϳª°¡ ÀԷµǾúÀ»°æ¿ì GTGT »óÅ°¡µÇ°í, À̾ Çϳª°¡ ´õ ÀԷµɰæ¿ì S_GTGT ¸¦ RETURN ÇÏ°í, ¾Æ´Ï¶ó¸é S_GT ¸¦ ¸®ÅÏÇÏ°Ô µË´Ï´Ù. ±×¸®°í MAIN ¿¡¼­ Ãâ·ÂÀ» ÇÏ°Ô µÇÁÒ ÄÄÆÄÀÏÇÏ°í ½ÇÇàÀ» Çغ¼±î¿ä ... #compile gcc -o getsymb getsymb.c #execution ./getsymb ÀÌÁ¦ ÀÔ·ÂÀ» Çغ¼±î¿ä ... ;) ============================ ls -al | more > test.txt S_WORD S_WORD <-al> S_BAR S_WORD S_GT S_WORD T_NL ============================ ÀÌÁ¦ ´Ù¸¥°É Çغ¼±î¿ä ... ============================ ls >> test.txt S_WORD S_GTGT S_WORD T_NL ============================ ============================ cat < test.txt S_WORD S_LT S_WORD T_NL ============================ Àß Â©¸®ÁÒ -_- À½³É ÀÌ°Ç ÀÌÁ¤µµ·Î ÇÏÁÒ... 2-5). ¸®´ÙÀÌ·º¼Ç°ú ÆÄÀÌÇÁ ¶óÀÎ ¸®´ª½º¿¡´Â pipe ¶óÀÎÀ̶ó´Â °³³äÀÌ Á¸ÀçÇÕ´Ï´Ù. ÇÁ·Î¼¼½º°£¿¡ ½ºÆ®¸²À» ¿­¾îÁÖ¾î ¼­·Î Åë½ÅÇÒ¼ö ÀÖ°Ô Çϴ°ÍÀÌ´õ±º¿ä. (Àúµµ ÀÌ°É ¸ô¶ó¼­ ÇÑÂüÀ» Çì¸ä´Ù´Â -_-;;; óÀ½ º¸´Ùº¸´Ï -_-;;) °á±¹ pipe ´Â ÇÁ·Î¼¼½º°£ Åë½ÅÀ» ÇϱâÀ§ÇÑ ½ºÆ®¸²À̾ú°í, redirection Àº ÇÁ·Î¼¼½º¿¡¼­ file ·ÎÀÇ µ¥ÀÌÅÍ Ãâ·Â ¶Ç´Â file ¿¡¼­ ÇÁ·Î¼¼½º·ÎÀÇ µ¥ÀÌÅÍ Ãâ·Â À̾ú½À´Ï´Ù. µû¶ó¼­ pipe °°Àº °æ¿ì ls | more °ú °°Àº °æ¿ìÀÌ°í, redirection Àº ls > test.txt ¿Í °°Àº °æ¿ìÁÒ ... BAR ·Î ÆÄÀÏ¿¡ ¾²¸é ¾ÈµÇ´õ±º¿ä ^^; ls | test.txt »ßÀÍ -_-;; ¾ÈµË´Ï´Ù... ¿ì¼± °£´ÜÈ÷ ls ¸í·É°ú more ¸í·É»çÀÌ¿¡ ÆÄÀÌÇÁ¸¦ »ý¼ºÇØ ls ÀÇ Ãâ·ÂÀ» more ÀÇ ÀÔ·ÂÀ¸·Î ³Ñ°ÜÁÖ´Â ÀÛ¾÷À» Çغ¾½Ã´Ù. ================================================================ !source : pipetest.c #include #include int main() { int pfd[2]; if(pipe(pfd)==-1) perror("pipe"); switch(fork()) { case -1 : perror("fork"); case 0 : if(close(1)==-1) perror("close"); if(dup(pfd[1]) != 0) perror("dup"); if(close(pfd[0]) == -1 || close(pfd[1]) == -1) perror("close2"); execlp("ls", "ls", NULL); perror("execlp"); } switch(fork()) { case -1 : perror ("fork"); case 0 : if(close(0) == -1) perror("close3"); if(dup(pfd[0]) != 0) perror("dup2"); if(close(pfd[0]) == -1 || close(pfd[1]) == -1) perror("close4"); execlp("more", "more", NULL); perror("execlp"); } if(close(pfd[0]) == -1 || close(pfd[1]) == -1) perror("close5"); while(wait(NULL) != -1); return 0; } ================================================================ ÆÄÀÌÇÁ´Â ------------- | ¡å processA processB ¡ã | ------------- ¿Í °°ÀÌ Åë½ÅÀÌ °¡´ÉÇÕ´Ï´Ù. ¿ì¸® ¼Ò½º¿¡¼­ º¸½Ã¸é, int pfd[2]; // ÆÄÀÌÇÁ¸¦ À§ÇÑ ÆÄÀÏ µð½ºÅ©¸³Å͸¦ µÎ°³ ¼±¾ð if(pipe(pfd)==-1) perror("pipe"); // ÆÄÀÌÇÁ ÀÛµ¿ ÀÌ °æ¿ì pfd[2] Áß¿¡¼­ pfd[1] ¿¡ ÀÔ·ÂÀ» ÇϰԵǸé pipe ¿¡ µ¥ÀÌÅ͸¦ ³Ö´Â Àǹ̰¡ µÇ¸ç, pfd[0]¿¡¼­´Â pfd[1]°ú ¿¬°áÀÌ µÇ¾î pfd[1]¿¡¼­ºÎÅÍ µ¥ÀÌÅ͸¦ Àоî¿À°Ô µÇÁÒ. pfd[1] -------> pfd[0] ¿Í °°ÀÌ µÇ°ÚÁÒ. ±×¸®°í ³ª¼­ fork ·Î ÇÁ·Î¼¼½º¸¦ Çϳª »ý¼ºÇÏ°ÚÁÒ. fork ¸¦ Çѹø È£ÃâÇÏ°Ô µÇ¸é µÎ¹øÀÇ return (Çϳª´Â child ¿¡ 0 À» parent¿¡ childÀÇ process id) À» ÇÏ°Ô µË´Ï´Ù. ¿©Æ° fork ´Â µû·Î ¼³¸íÇÒ °èȹÀÌ ¾ø±¸¿ä ... ¹®¼­ ¹öÁ¯ ¾÷ ÇÒ¶§ ÇÒÁöµµ ¸ð¸£°Ú±º¿ä. case 0 (child process) ÀÎ °æ¿ì /////////////////////////////////////////////////////////////////////////// case 0 : if(close(1)==-1) perror("close"); if(dup(pfd[1]) != 0) perror("dup"); if(close(pfd[0]) == -1 || close(pfd[1]) == -1) perror("close2"); execlp("ls", "ls", NULL); perror("execlp"); /////////////////////////////////////////////////////////////////////////// close(1) ¿¡¼­ 1ÀÇ Àǹ̴ ¹ºÁö ¾Æ½ÃÁÒ ... ;) STDIN_FILENO ¿Í STDOUT_FILENO °¡ unistd.h ¿¡ Á¤ÀÇ µÇ¾î ÀÖ½À´Ï´Ù. =================================================== !file : include/unistd.h .... /* Standard file descriptors. */ #define STDIN_FILENO 0 /* Ç¥ÁØÀÔ·Â */ #define STDOUT_FILENO 1 /* Ç¥ÁØÃâ·Â */ #define STDERR_FILENO 2 /* Ç¥ÁØ ERROR Ãâ·Â */ .... =================================================== ¹ºÁö ¾Æ½Ã°ÚÁÒ. µû¶ó¼­ ù¹ø° child ÀÇ Ç¥ÁØ Ãâ·ÂÀ» ´Ý¾Æ ¹ö¸®°Ú´Ù´Â°Ì´Ï´Ù. if(dup(pfd[1]) != 0) perror("dup"); ±×¸®°í dup °¡ ³ª¿ÀÁÒ ... dup ´Â return °ªÀ¸·Î pfd[1] ¿Í °°Àº È­ÀÏÀ» °¡¸®Å°´Â »õ·Î¿î file descriptor ¸¦ ¹ÝȯÇÏ°Ô µÇ°í, pfd[0]¿Í 1À» ´Ý°ÔµÇÁÒ. ls ¿¡°Ô pfd[0]´Â Àǹ̰¡ ¾ø½À´Ï´Ù. more ÀÌ pfd[0]·Î Ãâ·ÂÇÏ°Ô µÉÅ״ϱî¿ä ... execlp("ls", "ls", NULL); ±×¸®°í ³ª¼­ execlp ¸í·ÉÀ» ÅëÇØ ls ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù. ÀÌÁ¦´Â µÎ¹ø° child ¸¦ »ý¼ºÇÕ´Ï´Ù. /////////////////////////////////////////////////////////////////////////// case 0 : if(close(0) == -1) perror("close3"); if(dup(pfd[0]) != 0) perror("dup2"); if(close(pfd[0]) == -1 || close(pfd[1]) == -1) perror("close4"); execlp("more", "more", NULL); perror("execlp"); /////////////////////////////////////////////////////////////////////////// close(0) Àº Ç¥ÁØ ÀÔ·ÂÀ» ´Ý°Ú´Ù´Â ¼Ò¸³´Ï´Ù... ´Ù¸¥ Àâ°ÍµéÀÌ ³¢¸é ¾ÈµÇ´Ï±î¿ä ... ¿ÀÁ÷ µÎ¹ø° child ´Â pfd[0]°¡ °¡¸®Å°´Â ÆÄÀÏ°úÀÇ Åë½Å¸¸ ÇÏ¸é µË´Ï´Ù. ÀÌÇØ°¡½ÃÁÒ ... À̹ø¿¡´Â Ç¥ÁØÀԷ°ú °ü·ÃµÈ ÀÛ¾÷À» ÇØÁÖ°í, execlp("more", "more", NULL); ¸¶Âù°¡Áö·Î more ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù. ÀÌÁ¦ ls ¿Í more °£¿¡ Åë½ÅÀ» Çغ¼±î¿ä ... #compile gcc -o pipetest pipetest.c #execution ./pipetest a b c d e f g h <--more--> ½ÇÇàÇϱâÀü¿¡ ÆÄÀÏÀÌ ¸¹¾Æ¾ß µË´Ï´Ù. -_-;; ls | more ÀÇ ¸í·ÉÀ» ½ÇÇàÇÑ°Íó·³ µÇ°ÔµÇÁÒ ... ¿Ö ±×·¯³Ä¸é ls -write-> pfd[1] --> pfd[0] <-read- more ¿Í °°ÀÌ µÇ±â ¶§¹®ÀÌÁÒ ... ÀÌÁ¦ ¿ì¸®°¡ ¾Õ¿¡¼­ ÀÛ¼ºÇÑ token °ú ÀÌ·¯ÇÑ pipe °³³äÀ» Àß ¼¯¾îÁÖ¸é µË´Ï´Ù. ¿©Æ° ÆÄÀÌÇÁ¿¡ ´ëÇØ ÀÚ¼¼È÷ º¸½Ã°í ½ÍÀººÐÀº fs/pipe.c ¸¦ ÂüÁ¶Çϼ¼¿ä 3. Minish À» ¸ðµ¨·Î Shell ¸¸µé¾îº¸±â Áö±Ý±îÁö ÀÌÇØÇÑ °³³ä¸¸À¸·Îµµ ±âº»½©À» ÃæºÐÈ÷ ±¸ÇöÇÒ¼ö°¡ ÀÖ½À´Ï´Ù. ¸¶Áö¸·À¸·Î ÇÑ°¡Áö°¡ ³²¾Ò±º¿ä. »ç¿ëÀÚ ÀÔ·ÂÀ¸·Î »ý¼ºµÈ ÅäÅ«À» À߶󳻾ú°í, pipe °³³äÀ» ÀÌ¿ëÇØ ÇÁ·Î¼¼½º°£ Åë½ÅÇÏ´Â ¹ýµµ ÀÍÇû½À´Ï´Ù. ¾î¶»°Ô ¿¬°áÇؼ­ ¾²´ÂÁö¿¡ ´ëÇÑ ³»¿ëÀÌ ¾ø¾úÁÒ. 3-1). minish ¼Ò½º ÄÚµåÀÇ ±¸¼º ¾Æ·¡ ÄÚµå´Â minish À̶ó´Â ¾ÆÁÖ ÀÛÀº Å×½ºÆ®¿ë shell source ÄÚµå ÀÔ´Ï´Ù. Âü°íÇϽöó°í ³Ö¾î³ù½À´Ï´Ù. (Unix Programming À̾ú´ø°¡ ÇÏ´Â È«¸ªÃâÆÇ»ç Ã¥ÂüÁ¶) Main : minish.c Sub : execcmd.c exsimcmd.c getsymb.c shenv.c shutil.c fdredir.c Header : minish.h * ¿ì¼± minish ¿¡¼­ »ç¿ëÇÒ º¯¼ö¿Í Àü󸮱¸¹®ÀÇ Á¤ÀÇ ============================================================================ !source : minish.h #define ERROR (-1) #define MAXFNAME 10 #define MAXARG 10 #define MAXWORD 20 #define MAXFD 20 #define MAXVAR 50 #define MAXNAME 20 #ifndef MAXSIG #define MAXSIG 19 #endif #define TRUE 1 #define FALSE 0 #define BADFD (-2) #define lowbyte(w) ((w) & 0377) #define highbyte(w) lowbyte((w) >> 8) typedef int BOOLEAN; typedef enum {S_WORD, S_BAR, S_AMP, S_SEMI, S_GT, S_GTGT, S_LT, S_NL, S_EOF} SYMBOL; SYMBOL execcmd(); int exsimcmd(); void fdredir(); char *envget(); int envinit(); BOOLEAN envupdate(); void envprint(); void envexport(); void envass(); void envset(); void sigigno(); void sigrest(); void fatal(); void syserr(); void prnstate(); ============================================================================ * main ¿ªÇÒÀ» ÇÏ´Â ÇÁ·Î±×·¥ ============================================================================ !source : minish.c #include #include "minish.h" main() { char *prompt; int pid, fd; SYMBOL term; sigigno(); if (!envinit()) fatal("cannot initialize environment."); if ((prompt = envget("PS2")) == NULL) prompt = "> "; printf("%s", prompt); while (TRUE) { term = execcmd(&pid, FALSE, NULL); if (term != S_AMP && pid != 0) waitfor(pid); if (term == S_NL) printf("%s", prompt); for (fd=3; fd #include "minish.h" typedef enum {NEUTRAL, GTGT, INQUOTE, INWORD} STATUS; SYMBOL getsymb(word) char *word; { STATUS state; int c; char *w; state = NEUTRAL; w = word; while ((c = getchar()) != EOF) { switch (state) { case NEUTRAL : switch (c) { case ';' : return S_SEMI; case '&' : return S_AMP; case '|' : return S_BAR; case '<' : return S_LT; case '\n': return S_NL; case ' ' : case '\t': continue; case '>' : state = GTGT; continue; case '"' : state = INQUOTE; continue; default : state = INWORD; *w++ = c; continue; } case GTGT: if (c == '>') return S_GTGT; ungetc(c, stdin); return S_GT; case INQUOTE: switch (c) { case '\\' : *w++ = getchar(); continue; case '"' : *w = '\0'; return S_WORD; default : *w++ = c; continue; } case INWORD: switch (c ) { case ';' : case '&' : case '|' : case '<' : case '>' : case '\n': case ' ' : case '\t': ungetc(c, stdin); *w = '\0'; return S_WORD; default : *w++ = c; continue; } } } return S_EOF; } ============================================================================ * ºÐ¸®µÈ ÅäÅ«À» ÀÌ¿ëÇÑ ¸í·É¾î ½ÇÇà ============================================================================ !source : execcmd.c #include #include #include #include "minish.h" SYMBOL execcmd(int *waitpid, BOOLEAN makepipe, int *pipefdp) BOOLEAN makepipe; { SYMBOL symbol, term; int argc, sourcefd, destfd; int pid, pipefd[2]; char *argv[MAXARG+1], sourcefile[MAXFNAME]; char destfile[MAXFNAME]; char word[MAXWORD]; BOOLEAN append; argc = 0; sourcefd = 0; destfd = 1; while (TRUE) { switch (symbol = getsymb(word)) { case S_WORD : if (argc == MAXARG) { fprintf(stderr, "Too many args.\n"); break; } argv[argc] = (char *) malloc(strlen(word)+1); if (argv[argc] == NULL) { fprintf(stderr, "Out of arg memory.\n"); break; } strcpy(argv[argc], word); argc++; continue; case S_LT : if (makepipe) { fprintf(stderr, "Extra <.\n"); break; } if (getsymb(sourcefile) != S_WORD) { fprintf(stderr, "Illegal <.\n"); break; } sourcefd = BADFD; continue; case S_GT : case S_GTGT : if (destfd != 1) { fprintf(stderr, "Extra > or >>.\n"); break; } if (getsymb(destfile) != S_WORD) { fprintf(stderr, "Illegal > or >>.\n"); break; } destfd = BADFD; append = (symbol == S_GTGT); continue; case S_BAR : case S_AMP : case S_SEMI : case S_NL : argv[argc] = NULL; if (symbol == S_BAR) { if (destfd != 1) { fprintf(stderr, "> or >> conflicts with |.\n"); break; } term = execcmd(waitpid, TRUE, &destfd); } else term = symbol; if (makepipe) { if (pipe(pipefd) == ERROR) syserr("pipe"); *pipefdp = pipefd[1]; sourcefd = pipefd[0]; } pid = exsimcmd(argc, argv, sourcefd, sourcefile, destfd, destfile,append, term == S_AMP); if (symbol != S_BAR) *waitpid = pid; if (argc == 0 && (symbol != S_NL || sourcefd > 1)) fprintf(stderr, "Missing command.\n"); while (--argc >= 0) free(argv[argc]); return term; case S_EOF : exit(0); } } } ============================================================================ * ½É¹ú Ä¿¸ÇµåÀÇ ½ÇÇà ============================================================================ !source : exsimcmd.c #include #include #include "minish.h" int exsimcmd(ac, av, sourcefd, sourcefile, destfd, destfile, append, backgrnd) int ac; char *av[]; int sourcefd; char *sourcefile; int destfd; char *destfile; BOOLEAN append; BOOLEAN backgrnd; { int pid; if (ac == 0 || shellcmd(ac, av, sourcefd, destfd)) return 0; pid = fork(); switch (pid) { case ERROR : fprintf(stderr, "Cannot create new process.\n"); return 0; case 0 : if (!backgrnd) sigrest(); if (!envupdate()) fatal("Cannot update environment.\n"); fdredir(sourcefd, sourcefile, destfd, destfile, append, backgrnd); execvp(av[0], av); fprintf(stderr, "Cannot execute %s\n", av[0]); exit(0); default : if (sourcefd > 0 && close(sourcefd) == ERROR) syserr("close sourcefd"); if (destfd > 1 && close(destfd) == ERROR) syserr("close destfd"); if (backgrnd) printf("%d\n", pid); return pid; } } ============================================================================ * file descriptor ¸®´ÙÀÌ·º¼Ç ============================================================================ !source : fdredir.c #include #include #include #include #include "minish.h" void fdredir(sourcefd, sourcefile, destfd, destfile, append, backgrnd) int sourcefd; char *sourcefile; int destfd; char *destfile; BOOLEAN append; BOOLEAN backgrnd; { int flags, fd; if (sourcefd == 0 && backgrnd) { strcpy(sourcefile, "/dev/null"); sourcefd = BADFD; } if (sourcefd != 0) { if (close(0) == ERROR) syserr("close"); if (sourcefd > 0) { if (dup(sourcefd) != 0) fatal("dup"); } else if (open(sourcefile, O_RDONLY, 0) == ERROR) { fprintf(stderr, "Cannot open %s\n", sourcefile); exit(0); } } if (destfd != 1) { if (close(1) == ERROR) syserr("close"); if (destfd > 1) { if (dup(destfd) != 1) fatal("dup"); }else { flags = O_WRONLY | O_CREAT; if (!append) flags |= O_TRUNC; if (open(destfile, flags, 0666) == ERROR) { fprintf(stderr, "Cannot create %s\n", destfile); exit(0); } if (append) if (lseek(1, 0L, 2) == ERROR) syserr("lseek"); } } for (fd =3; fd < MAXFD; fd++) close(fd); return; } ============================================================================ * ȯ°æº¯¼ö ¼³Á¤¹× ÇÁ·Î±×·¥ ³» ±âÃÊÇÔ¼ö ±¸Çö ============================================================================ !source : envsh.c #include #include #include #include #include "minish.h" extern char **environ; static struct slot { char *name; char *value; BOOLEAN export; } envsym[MAXVAR]; static struct slot *slfind(name) char *name; { int i; struct slot *v; v = NULL; for (i = 0; i < MAXVAR; i++) if (envsym[i].name == NULL) { if (v == NULL) v = &envsym[i]; } else if (strcmp(envsym[i].name, name) == 0) { v = &envsym[i]; break; } return v; } static BOOLEAN assign(p, s) char **p; char *s; { int size; size = strlen(s) + 1; if (*p == NULL) { if ((*p = (char *) malloc(size)) == NULL) return FALSE; } else if ((*p = (char *) realloc(*p, size)) == NULL) return FALSE; strcpy(*p, s); return TRUE; } BOOLEAN set(name, value) char *name; char *value; { struct slot *v; BOOLEAN b; if ((v = slfind(name)) == NULL) return FALSE; b = assign(&v->name, name) && assign(&v->value, value); return b; } BOOLEAN export(name) char *name; { struct slot *v; if ((v = slfind(name)) == NULL) return FALSE; if (v->name == NULL) if (!assign(&v->name, name) || !assign(&v->value, "")) return FALSE; v->export = TRUE; return TRUE; } char *envget(name) char *name; { struct slot *v; if ((v = slfind(name)) == NULL || v-> name == NULL) return NULL; return v->value; } BOOLEAN envinit() { int i, leng; char name[MAXNAME]; for (i = 0; environ[i] != NULL; i++) { leng = strcspn(environ[i], "="); strncpy(name, environ[i], leng); name[leng] = '\0'; if (!set(name, &environ[i][leng+1]) || !export(name)) return FALSE; } return TRUE; } void envass(ac, av) int ac; char *av[]; { char *name, *value; if (ac != 1) printf("Extra args.\n"); else { name = strtok(av[0], "="); value = strtok(NULL, "\1"); /* alles uebrige */ if (!set(name, value)) fprintf(stderr, "Cannot set.\n"); } } void envexport(ac, av) int ac; char *av[]; { int i; if (ac == 1) { envset(ac, av); return; } for (i = 1; i < ac; i++) if (!export(av[i])) { fprintf(stderr, "Cannot export %s\n", av[i]); return; } } void envset(ac, av) int ac; char *av[]; { if (ac != 1) printf("Extra args.\n"); else envprint(); return; } void envprint() { int i; for (i = 0; i < MAXVAR; i++) if (envsym[i].name != NULL) printf("%3s %s=%s\n", envsym[i].export ? "[E]" : "", envsym[i].name, envsym[i].value); return; } BOOLEAN envupdate() { int i, envi, nvlen; struct slot *w; static BOOLEAN updated = FALSE; if (!updated) if ((environ = (char **) malloc((MAXVAR+1) * sizeof(char *))) == NULL) return FALSE; envi = 0; for (i = 0; i < MAXVAR; i++) { w = &envsym[i]; if (w->name == NULL || !w->export) continue; nvlen = strlen(w->name) + strlen(w->value) + 2; if (!updated) { if ((environ[envi] = (char *) malloc(nvlen)) == NULL) return FALSE; } else if ((environ[envi] = (char *) realloc(environ[envi], nvlen)) == NULL) return FALSE; sprintf(environ[envi], "%s=%s", w->name, w->value); envi++; } environ[envi] = NULL; updated = TRUE; return TRUE; } ============================================================================ * ½© À¯Æ¿ ============================================================================ !source : shutil.c #include #include #include #include #include #include "minish.h" #ifndef BADSIG #define BADSIG (void (*)) (-1) #endif #ifndef BSD #ifndef OS2 extern sys_nerr; extern char *sys_errlist[]; #endif #endif void fatal(message) char *message; { fprintf(stderr, "Error: %s\n", message); exit(1); } void syserr(message) char *message; { fprintf(stderr, "Error: %s (%d", message, errno); if (errno > 0 && errno < sys_nerr) fprintf(stderr, "; %s)\n", sys_errlist[errno]); else fprintf(stderr, ")\n"); exit(1); } static void (* oldint)(); static void (* oldquit)(); void sigigno() { static BOOLEAN first = TRUE; if (first) { first = FALSE; oldint = signal(SIGINT, SIG_IGN); oldquit = signal(SIGQUIT, SIG_IGN); if (oldint == BADSIG || oldquit == BADSIG) syserr("signal"); } else if (signal(SIGINT, SIG_IGN) == BADSIG || signal(SIGQUIT, SIG_IGN) == BADSIG) syserr("signal"); } void sigrest() { if (signal(SIGINT, oldint) == BADSIG || signal(SIGQUIT, oldquit) == BADSIG) syserr("signal"); } void waitfor(pid) int pid; { int wpid, status; while ((wpid = wait(&status)) != pid && wpid != ERROR) prnstate(wpid, status); if (wpid == pid) prnstate(0, status); } #ifndef OS2 void prnstate(pid, status) int pid; int status; { int k; if (status != 0 && pid != 0) printf("Process %d: ", pid); if (lowbyte(status) == 0) { if ((k = highbyte(status)) != 0) printf("Exit code %d\n", k); } else { if ((k = status & 0177) <= MAXSIG) printf("%s", sys_siglist[k]); else printf("Signal #%d", k); if ((status & 0200) == 0200) printf(" - core dumped"); printf("\n"); } return; } #endif #ifdef OS2 void prnstate(pid, status) int pid; int status; { int k; static char *sigmess[] = { "", "Hangup", "Interrupt", "Quit", "Illegal instruction", "Trace trap", "IOT instruction", "EMT instruction", "Floating point exception", "Kill", "Bus error", "Segmentation violation", "Bad arg to system call", "Write on pipe", "Alarm clock", "Terminate signal", "User signal 1", "User signal 2", "Death of child", "Power fail" }; if (status != 0 && pid != 0) printf("Process %d: ", pid); if (lowbyte(status) == 0) { if ((k = highbyte(status)) != 0) printf("Exit code %d\n", k); } else { if ((k = status & 0177) <= MAXSIG) printf("%s", sigmess[k]); else printf("Signal #%d", k); if ((status & 0200) == 0200) printf(" - core dumped"); printf("\n"); } return; } #endif BOOLEAN shellcmd(ac, av, sourcefd, destfd) int ac; char *av[]; int sourcefd; int destfd; { char *path; if (strchr(av[0], '=') != NULL) envass(ac, av); else if (strcmp(av[0], "export") == 0) envexport(ac, av); else if (strcmp(av[0], "set") == 0) envset(ac, av); else if (strcmp(av[0], "cd") == 0) { if (ac > 1) path = av[1]; else if ((path = envget("HOME")) == NULL) path = "."; if (chdir(path) == ERROR) fprintf(stderr, "%s: bad directory.\n", path); }else if (strcmp(av[0], "exit") == 0) { exit(0); } else return FALSE; if (sourcefd != 0 || destfd != 1) fprintf(stderr, "Ilegal redirection or pipeline.\n"); return TRUE; } ============================================================================ # makefile =============================================================== all: minish minish.o: minish.c minish.h gcc -c minish.c shutil.o: shutil.c minish.h gcc -c shutil.c shenv.o: shenv.c minish.h gcc -c shenv.c getsymb.o: getsymb.c minish.h gcc -c getsymb.c execcmd.o: execcmd.c minish.h gcc -c execcmd.c fdredir.o: fdredir.c minish.h gcc -c fdredir.c exsimcmd.o: exsimcmd.c minish.h gcc -c exsimcmd.c minish: minish.o shutil.o getsymb.o execcmd.o fdredir.o \ exsimcmd.o shenv.o gcc -o minish minish.o shutil.o getsymb.o execcmd.o \ fdredir.o exsimcmd.o shenv.o =============================================================== # make make all # execute minish Å×½ºÆ® ÀÛ¾÷À» Çغ¸°í, Á¾·á½Ã exit ¸¦ ÀÔ·ÂÇØÁÖ¼¼¿ä. ±×·³ ¿ø·¡ »ç¿ëÇÏ´ø ½©·Î µ¹¾Æ°©´Ï´Ù. postscript. ³Ê¹« ¹ÌÈíÇÑ°Í °°½À´Ï´Ù¸¸ ... ½º½º·Î ã¾Æ¼­ Çغ¸´Â°Íµµ ...