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

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

Fix a bug in rpc_vmm_get_pte_client() function (bad RPC index).

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