source: trunk/user/ksh/ksh.c @ 435

Last change on this file since 435 was 435, checked in by alain, 6 years ago

Fix a bad bug in scheduler...

File size: 17.7 KB
RevLine 
[407]1///////////////////////////////////////////////////////////////////////////////
2// File   :  ksh.c
3// Date   :  October 2017
4// Author :  Alain Greiner
5///////////////////////////////////////////////////////////////////////////////
6// This single thread application implement a simple shell for ALMOS-MKH.
7///////////////////////////////////////////////////////////////////////////////
[230]8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
[416]12#include <shared_syscalls.h>
[230]13
[407]14#define CMD_MAX_SIZE   (256)    // max number of characters in one command
15#define LOG_DEPTH      (256)    // max number of registered commands
16#define MAX_ARGS           (32)     // max number of arguments in a command
17#define FIFO_SIZE      (1024)   // FIFO depth for recursive ls
[230]18
[407]19////////////////////////////////////////////////////////////////////////////////
20//         Structures
21////////////////////////////////////////////////////////////////////////////////
[230]22
[407]23// one entry in the registered commands array
24typedef struct log_entry_s
25{
26        char          buf[CMD_MAX_SIZE];
27        unsigned int  count;
28}
29log_entry_t;
[230]30
[407]31// one entry in the supported command types array
32typedef struct ksh_cmd_s
33{
34        char * name;
35        char * desc;
36        void   (*fn)( int , char ** );
37}
38ksh_cmd_t;
39
40
[230]41////////////////////////////////////////////////////////////////////////////////
42//         Global Variables
43////////////////////////////////////////////////////////////////////////////////
44
[407]45ksh_cmd_t       cmd[];                    // array of supported commands
[230]46
[407]47log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
[230]48
[407]49unsigned int    ptw;                      // write pointer in log_entries[]
50unsigned int    ptr;                      // read pointer in log_entries[]
[230]51
52////////////////////////////////////////////////////////////////////////////////
53//         Shell  Commands
54////////////////////////////////////////////////////////////////////////////////
55
[407]56/////////////////////////////////////////////
57static void cmd_cat( int argc , char **argv )
[230]58{
[407]59        char         * path;
[230]60
[407]61        if (argc != 2) 
62    {
[409]63                printf("  usage: cat pathname\n");
[230]64                return;
65        }
[407]66
[230]67        path = argv[1];
68
[409]69    printf("  error: not implemented yet\n");
[407]70
71/*
72        // open the file
73        fd = open( path , O_RDONLY , 0 );
74        if (fd < 0)
75    {
[409]76                printf("  error: cannot open %s\n", path);
[230]77                goto exit;
78        }
79
[407]80        // get file size
81        if (stat(path, &st) == -1)
82    {
[409]83                printf("  error: cannot stat %s\n", path);
[230]84                goto exit;
85        }
86        if (S_ISDIR(st.st_mode)) {
[409]87                printf("  error: %s is a directory\n", path);
[230]88                goto exit;
89        }
90        size = st.st_size;
91
[407]92        // mmap the file
[230]93        buf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
94        if (buf == NULL || buf == (char *)-1) {
[409]95                printf("  error: cannot map %s\n", path);
[230]96                goto exit;
97        }
98
[407]99        // set terminating '0' XXX
[230]100        buf[size-1] = 0;
101
[407]102        // display the file content
[230]103        printf("%s", buf);
104
105exit:
[407]106        if (buf != NULL) munmap(buf, size);
107        if (fd >= 0) close(fd);
108*/
[230]109
[407]110}   // end cmd_cat()
111
112////////////////////////////////////////////
113static void cmd_cd( int argc , char **argv )
114{
115        char * path;
116
117        if (argc != 2)
118    {
[409]119                printf("  usage: cd pathname\n");
[407]120                return;
121        }
122
123        path = argv[1];
124
[409]125    printf("  error: not implemented yet\n");
[407]126/*
127        path = argv[1];
128
129        if (chdir(path) == -1)
130    {
[409]131                printf("  error: cannot cd to %s\n", path);
[407]132        }
133*/
134
135}   // end cmd_cd()
136
137/////////////////////////////////////////
[230]138static void cmd_cp(int argc, char **argv)
139{
[407]140//      int src_fd = -1, dst_fd = -1;
141//      char *srcpath, *dstpath;
142//      struct stat st;
143//      size_t size, i;
144//      char buf[1024];
[230]145
[407]146        if (argc != 3) 
147    {
[409]148                printf("  usage: cp src_pathname dst_pathname\n");
[230]149                return;
150        }
151
[409]152    printf("  error: not implemented yet\n");
[407]153
154/*
[230]155        srcpath = argv[1];
156        dstpath = argv[2];
157
[407]158        // open the src file
[230]159        src_fd = open(srcpath, O_RDONLY, 0);
160        if (src_fd < 0) {
[409]161                printf("  error: cannot open %s / err = %d\n", srcpath, errno);
[230]162                goto exit;
163        }
164
[407]165        // get file size
[230]166        if (stat(srcpath, &st) == -1) {
[409]167                printf("  error: cannot stat %s\n", srcpath);
[230]168                goto exit;
169        }
170        if (S_ISDIR(st.st_mode)) {
[409]171                printf("  error: %s is a directory\n", srcpath);
[230]172                goto exit;
173        }
174        size = st.st_size;
175
[407]176        // open the dst file
[230]177        dst_fd = open(dstpath, O_CREAT|O_TRUNC|O_RDWR, 0);
178        if (dst_fd < 0) {
[409]179                printf("  error: cannot open %s / err = %d\n", dstpath, errno);
[230]180                goto exit;
181        }
182        if (stat(dstpath, &st) == -1) {
[409]183                printf("  error: cannot stat %s\n", dstpath);
[230]184                goto exit;
185        }
186        if (S_ISDIR(st.st_mode)) {
[409]187                printf("  error: %s is a directory\n", dstpath);
[230]188                goto exit;
189        }
190
191        i = 0;
192        while (i < size)
193        {
194                size_t rlen = (size - i < 1024 ? size - i : 1024);
195                size_t wlen;
196                ssize_t ret;
197
[407]198                // read the source
[230]199                ret = read(src_fd, buf, rlen);
200                if (ret == -1) {
[409]201                        printf("  error: cannot read from file %s\n", srcpath);
[230]202                        goto exit;
203                }
204                rlen = (size_t)ret;
205
[407]206                // write to the destination
[230]207                ret = write(dst_fd, buf, rlen);
208                if (ret == -1) {
[409]209                        printf("  error: cannot write to file %s\n", dstpath);
[230]210                        goto exit;
211                }
212                wlen = (size_t)ret;
213
[407]214                // check
[230]215                if (wlen != rlen) {
[409]216                        printf("  error: cannot write on device\n");
[230]217                        goto exit;
218                }
219
220                i += rlen;
221        }
222
223exit:
[407]224        if (src_fd >= 0) close(src_fd);
225        if (dst_fd >= 0) close(dst_fd);
226*/
[230]227
[407]228}   // end cmd_cp()
229
[427]230/////////////////////////////////////////
231static void cmd_fg(int argc, char **argv)
232{
233        unsigned int pid;
234
235        if (argc != 2) 
236    {
237                printf("  usage: %s pid\n", argv[0]);
238                return;
239        }
240
241    pid = atoi( argv[1] );   
242
243    if( pid == 0 )
244    {
245                printf("  error: ilegal pid format\n" );
246        }
247
248    if( fg( pid ) )
249    {
250                printf("  error: cannot find process %x\n", pid );
251        }
252}
253
[407]254//////////////////////////////////////////////
255static void cmd_help( int argc , char **argv )
[230]256{
[407]257        unsigned int i;
[230]258
[407]259        if (argc != 1) 
260    {
[409]261                printf("  usage: %s\n", argv[0]);
[230]262                return;
263        }
264
265        printf("available commands:\n");
[407]266        for (i = 0 ; cmd[i].name ; i++) 
267    {
[230]268                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
269        }
[407]270}   // end cmd_help()
[230]271
[407]272//////////////////////////////////////////////
273static void cmd_kill( int argc , char **argv )
[230]274{
[407]275        unsigned int pid;
[230]276
[407]277        if (argc != 2) 
278    {
[409]279                printf("  usage: %s pid\n", argv[0]);
[230]280                return;
281        }
282
[427]283        pid = atoi( argv[1] );
[230]284
[427]285    if( pid == 0 )
286    {
287                printf("  error: ilegal pid format\n" );
288        }
289
[416]290        if( kill( pid , SIGKILL ) )
[407]291    {
[409]292                printf("  error: unable to kill process %x\n", pid );
[230]293        }
[407]294}   // end cmd_kill()
[230]295
[407]296//////////////////////////////////////////////
297static void cmd_load( int argc , char **argv )
[230]298{
[434]299        int                  ret;
300    unsigned int         ksh_pid;
[408]301        char               * pathname;
[427]302    unsigned int         background;
[407]303
[427]304        if( (argc < 2) || (argc > 3) ) 
[407]305    {
[434]306                printf("  usage: %s pathname [&]\n", argv[0] );
[407]307                return;
308        }
309
310        pathname = argv[1];
311
[427]312    if( argc == 3 ) background = (argv[2][0] == '&');
[434]313    else            background = 0;
[427]314
[434]315    // get KSH process PID
316    ksh_pid = getpid();
[407]317
[434]318    // KSH process fork CHILD process
319        ret = fork();
320
321    if ( ret < 0 )      // it is a failure reported to parent
[407]322    {
[434]323        printf("  error: ksh process unable to fork\n");
324    }
325    else if (ret == 0)  // it is the CHILD process
326    {
327        // give back to KSH process the terminal ownership
328        if( background ) fg( ksh_pid );
329
330        // CHILD process exec NEW process
331        ret = exec( pathname , NULL , NULL );
332
333        if( ret )
[409]334        {
335            printf("  error: new process unable to exec <%s>\n", pathname );
336            exit(0);
337        }
[407]338        } 
339}   // end cmd_load
340
341/////////////////////////////////////////////
342static void cmd_log( int argc , char **argv )
343{
344        unsigned int i;
345
[230]346        printf("--- registered commands ---\n");
[407]347        for (i = 0; i < LOG_DEPTH; i++) 
348    {
[230]349                printf(" - %zu\t: %s\n", i, &log_entries[i].buf);
350        }
351}
352
[407]353////////////////////////////////////////////
354static void cmd_ls( int argc , char **argv )
[230]355{
[407]356        char  * path;
[230]357
[407]358//  struct dirent * file;
359//  DIR *dir;
360
361        if (argc == 1)
362    {
[230]363                path = ".";
[407]364        }
365    else if (argc == 2) 
366    {
[230]367                path = argv[1];
[407]368        } 
369    else 
370    {
[409]371                printf("  usage: ls [path]\n");
[230]372                return;
373        }
374
[409]375    printf("  error: not implemented yet\n");
[407]376/*
377        dir = opendir( path );
[230]378        while ((file = readdir(dir)) != NULL)
379        {
380                printf(" %s\n", file->d_name);
381        }
382        closedir(dir);
[407]383*/
[230]384}
385
[407]386///////////////////////////////////////////////
387static void cmd_mkdir( int argc , char **argv )
[230]388{
[407]389        char * pathname;
[230]390
[407]391        if (argc != 2)
392    {
[409]393                printf("  usage: mkdir pathname\n");
[230]394                return;
395        }
396
[407]397    pathname = argv[1];
[230]398
[409]399    printf("  error: not implemented yet\n");
[407]400/*
401        if ( mkdir( path, 0x700) == -1 )
402    {
[409]403                printf("  error: cannot create directory %s\n", path);
[230]404        }
[407]405*/
[230]406}
407
[407]408////////////////////////////////////////////
409static void cmd_mv( int argc , char **argv )
[230]410{
[407]411
[230]412        if (argc < 3)
413        {
414                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
415                return;
416        }
417
[409]418    printf("  error: not implemented yet\n");
[407]419   
420/*
[230]421        int ret = giet_fat_rename(argv[1], argv[2]);
422        if (ret < 0)
423        {
[409]424                printf("  error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret );
[230]425        }
[407]426*/
427
[230]428}
429
[407]430/////////////////////////////////////////////
431static void cmd_pwd( int argc , char **argv )
[230]432{
[407]433        char buf[1024];
[230]434
[407]435        if (argc != 1)
436    {
[409]437                printf("  usage: pwd\n");
[407]438                return;
439        }
440
441        if ( getcwd( buf , 1024 ) ) 
442    {
[409]443                printf("  error: unable to get current directory\n");
[407]444        }
445    else 
446    {
447                printf("%s\n", buf);
448        }
449}
450
451////////////////////////////////////////////
452static void cmd_rm( int argc , char **argv )
453{
454        char * pathname;
455
456        if (argc != 2)
457    {
[409]458                printf("  usage: rm pathname\n");
[230]459                return;
460        }
461
[407]462        pathname = argv[1];
[230]463
[409]464    printf("  error: not implemented yet\n");
[407]465/*
466        if (remove(path) == -1)
467    {
[409]468                printf("  error: cannot remove %s\n", path);
[230]469        }
[407]470*/
471
[230]472}
473
[407]474///////////////////////////////////////////////
475static void cmd_rmdir( int argc , char **argv )
[230]476{
477        cmd_rm(argc, argv);
478}
479
[427]480/////////////////////////////////////////////////
481static void cmd_display( int argc , char **argv )
[230]482{
[427]483    unsigned int  cxy;
484    unsigned int  lid;
485    unsigned int  pid;
[435]486    unsigned int  txt_id;
[230]487
[427]488    if( strcmp( argv[1] , "vmm" ) == 0 )
[407]489    {
[427]490        if( argc != 3 )
491        {
492                    printf("  usage: display vmm pid\n");
493                    return;
494            }
[230]495
[427]496            pid = atoi(argv[2]);
[230]497
[427]498        if( display_vmm( pid ) )
499        {
500            printf("  error: illegal arguments pid = %x\n", pid );
501        }
502    }
503    else if( strcmp( argv[1] , "sched" ) == 0 )
[407]504    {
[427]505        if( argc != 4 )
506        {
507                    printf("  usage: display sched cxy lid\n");
508                    return;
509            }
510
511            cxy = atoi(argv[2]);
512            lid = atoi(argv[3]);
513
514        if( display_sched( cxy , lid ) )
515        {
516            printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
517        }
[407]518    }
[427]519    else if( strcmp( argv[1] , "process" ) == 0 )
520    {
521        if( argc != 3 )
522        {
523                    printf("  usage: display process cxy\n");
524                    return;
525            }
526
527            cxy = atoi(argv[2]);
528
[435]529        if( display_cluster_processes( cxy ) )
[427]530        {
531            printf("  error: illegal argument cxy = %x\n", cxy );
532        }
533    }
[435]534    else if( strcmp( argv[1] , "txt" ) == 0 )
535    {
536        if( argc != 3 )
537        {
538                    printf("  usage: display txt txt_id\n");
539                    return;
540            }
541
542            txt_id = atoi(argv[2]);
543
544        if( display_txt_processes( txt_id ) )
545        {
546            printf("  error: illegal argument txt_id = %x\n", txt_id );
547        }
548    }
[427]549    else if( strcmp( argv[1] , "vfs" ) == 0 )
550    {
551        if( argc != 2 )
552        {
553                    printf("  usage: display vfs\n");
554                    return;
555            }
556
557        display_vfs();
558    }
559    else if( strcmp( argv[1] , "chdev" ) == 0 )
560    {
561        if( argc != 2 )
562        {
563                    printf("  usage: display chdev\n");
564                    return;
565            }
566
567        display_chdev();
568    }
569    else
570    {
[435]571        printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n");
[427]572    }
[230]573}
574
[407]575//////////////////////////////////////////////////////////////////
576// Array of commands
577//////////////////////////////////////////////////////////////////
[230]578
[407]579ksh_cmd_t cmd[] =
[230]580{
[435]581        { "cat",     "display file content",                            cmd_cat     },
582        { "cd",      "change current directory",                        cmd_cd      },
583        { "cp",      "replicate a file in file system",                 cmd_cp      },
584    { "fg",      "put a process in foreground",                     cmd_fg      },
585    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
586        { "load",    "load an user application",                        cmd_load    },
587        { "help",    "list available commands",                         cmd_help    },
588        { "kill",    "kill an application (all threads)",               cmd_kill    },
589        { "log",     "list registered commands",                        cmd_log     },
590        { "ls",      "list directory entries",                          cmd_ls      },
591        { "mkdir",   "create a new directory",                          cmd_mkdir   },
592        { "mv",      "move a file in file system",                      cmd_mv      },
593        { "pwd",     "print current working directory",                 cmd_pwd     },
594        { "rm",      "remove a file from file system",                  cmd_rm      },
595        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
596        { NULL,      NULL,                                                                              NULL        }
[230]597};
598
[407]599////////////////////////////////////////////////////////////////////////////////////
600// This function analyses one command (with arguments), execute it, and return.
601////////////////////////////////////////////////////////////////////////////////////
[230]602static void parse(char *buf)
603{
604        int argc = 0;
605        char *argv[MAX_ARGS];
606        int i;
607        int len = strlen(buf);
608
609        // build argc/argv
[407]610        for (i = 0; i < len; i++) 
611    {
612                if (buf[i] == ' ') 
613        {
[230]614                        buf[i] = '\0';
[407]615                }
616        else if (i == 0 || buf[i - 1] == '\0') 
617        {
618                        if (argc < MAX_ARGS) 
619            {
[230]620                                argv[argc] = &buf[i];
621                                argc++;
622                        }
623                }
624        }
625
[407]626        if (argc > 0)
627    {
[230]628                int found = 0;
629
630                argv[argc] = NULL;
631
[407]632                // try to match typed command
633                for (i = 0; cmd[i].name; i++)
634        {
635                        if (strcmp(argv[0], cmd[i].name) == 0)
636            {
[230]637                                cmd[i].fn(argc, argv);
638                                found = 1;
639                                break;
640                        }
641                }
642
[407]643                if (!found)
644        {
[434]645                        printf("  undefined command <%s>\n", argv[0]);
[230]646                }
647        }
648}
649
[407]650///////////////////////////////////
651int main( int argc , char *argv[] )
[230]652{
[407]653        char         c;                                           // read character
654        char         buf[CMD_MAX_SIZE];           // buffer for one command
655        unsigned int count = 0;                           // pointer in buf
656        unsigned int i;                                           // index for loops
[230]657
[407]658        enum fsm_states
659    {
[230]660                NORMAL,
661                ESCAPE,
662                BRAKET,
663        };
664
[407]665    // log buffer initialisation
666        memset( &log_entries , 0, sizeof(log_entries));
667        ptw   = 0;
668        ptr   = 0;
[230]669
670        printf( "~~~ shell ~~~\n\n" );
671
672        // command buffer initialisation
[407]673        memset( buf, 0x20 , sizeof(buf) );
[230]674        count = 0;
675
676        // display first prompt
677        printf("# ");
678
679        // This lexical analyser writes one command line in the buf buffer.
680        // It is implemented as a 3 states FSM to handle the following sequences:
681        // - ESC [ A : up arrow
682        // - ESC [ B : down arrow
683        // - ESC [ C : right arrow
684        // - ESC [ D : left arrow
[407]685        // The three states have the following semantic:
[230]686        // - NORMAL : no (ESC) character has been found
687        // - ESCAPE : the character (ESC) has been found
688        // - BRAKET : the wo characters (ESC,[) have been found
689        unsigned int state = NORMAL;
690
[409]691
[407]692// @@@
[416]693// parse("load /bin/user/sort.elf");
[407]694// @@@
[408]695
[407]696   
[230]697        while (1)
698        {
[407]699                c = (char)getchar();
[230]700
[407]701        if( c == 0 ) continue;
702
[230]703                switch (state)
704                {
705                        case NORMAL:
706                        {
707                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
708                                {
709                                        if (count > 0) {
710                                                printf("\b \b");
711                                                count--;
712                                        }
713                                }
714                                else if (c == '\n')      // new line => call parser to execute command
715                                {
716                                        if (count > 0)
717                                        {
718                                                // complete command
719                                                buf[count] = '\0';
720
721                                                // register command in log arrays
722                                                strcpy(log_entries[ptw].buf, buf);
723                                                log_entries[ptw].count = count;
724                                                ptw = (ptw + 1) % LOG_DEPTH;
725                                                ptr = ptw;
726
727                                                // execute command
728                                                printf("\n");
729                                                parse((char *)&buf);
730
731                                                // reinitialise buffer and display prompt
732                                                for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
733                                                count = 0;
734                                                printf("# ");
735                                        }
736                                }
737                                else if (c == '\t')     // tabulation => do nothing
738                                {
739                                }
740                                else if (c == 0x1B)     // ESC => start an escape sequence
741                                {
742                                        state = ESCAPE;
743                                }
744                                else if (c == 0x03)     // ^C  => cancel current command
745                                {
746                                        for (i = 0; i < count; i++) printf("\b \b");
747                                        for (i = 0; i < sizeof(buf); i++) buf[i] = 0x20;
748                                        count = 0;
749                                }
750                                else                                     // register character in command buffer
751                                {
752                                        if (count < sizeof(buf) - 1)
753                                        {
[418]754                                                putchar( c );
[230]755                                                buf[count] = c;
756                                                count++;
757                                        }
758                                }
759                                break;
760                        }
761                        case ESCAPE:
762                        {
763                                if (c == '[')           //  valid sequence => continue
764                                {
765                                        state = BRAKET;
766                                }
767                                else                               // invalid sequence => do nothing
768                                {
769                                        state = NORMAL;
770                                }
771                                break;
772                        }
773                        case BRAKET:
774                        {
775                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
776                                {
777                                        if (count > 0)
778                                        {
779                                                printf("\b");
780                                                count--;
781                                        }
782
783                                        // get next user char
784                                        state = NORMAL;
785                                }
786                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
787                                {
788                                        if (count < sizeof(buf) - 1)
789                                        {
790                                                printf("%c", buf[count]);
791                                                count++;
792                                        }
793
794                                        // get next user char
795                                        state = NORMAL;
796                                }
797                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
798                                {
799                                        // cancel current command
800                                        for (i = 0; i < count; i++) printf("\b \b");
801                                        count = 0;
802
803                                        // copy log command into buf
804                                        ptr = (ptr - 1) % LOG_DEPTH;
805                                        strcpy(buf, log_entries[ptr].buf);
806                                        count = log_entries[ptr].count;
807
808                                        // display log command
809                                        printf("%s", buf);
810
811                                        // get next user char
812                                        state = NORMAL;
813                                }
814                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
815                                {
816                                        // cancel current command
817                                        for (i = 0 ; i < count; i++) printf("\b \b");
818                                        count = 0;
819
820                                        // copy log command into buf
821                                        ptr = (ptr + 1) % LOG_DEPTH;
822                                        strcpy(buf, log_entries[ptr].buf);
823                                        count = log_entries[ptr].count;
824
825                                        // display log command
826                                        printf("%s", buf);
827
828                                        // get next user char
829                                        state = NORMAL;
830                                }
831                                else                               // other character => do nothing
832                                {
833                                        // get next user char
834                                        state = NORMAL;
835                                }
836                                break;
837                        }
838                }
839        }
840}
841
Note: See TracBrowser for help on using the repository browser.