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

Last change on this file since 442 was 442, checked in by alain, 4 years ago

Introduce idbg application.

File size: 19.5 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 != 4 )
241        {
242                    printf("  usage: display vmm cxy pid\n");
243                    return;
244            }
245
246            cxy = atoi(argv[2]);
247            pid = atoi(argv[3]);
248
249        if( display_vmm( cxy , pid ) )
250        {
251            printf("  error: no process %x in cluster %x\n", pid , cxy );
252        }
253    }
254    else if( strcmp( argv[1] , "sched" ) == 0 )
255    {
256        if( argc != 4 )
257        {
258                    printf("  usage: display sched cxy lid\n");
259                    return;
260            }
261
262            cxy = atoi(argv[2]);
263            lid = atoi(argv[3]);
264
265        if( display_sched( cxy , lid ) )
266        {
267            printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
268        }
269    }
270    else if( strcmp( argv[1] , "process" ) == 0 )
271    {
272        if( argc != 3 )
273        {
274                    printf("  usage: display process cxy\n");
275                    return;
276            }
277
278            cxy = atoi(argv[2]);
279
280        if( display_cluster_processes( cxy ) )
281        {
282            printf("  error: illegal argument cxy = %x\n", cxy );
283        }
284    }
285    else if( strcmp( argv[1] , "txt" ) == 0 )
286    {
287        if( argc != 3 )
288        {
289                    printf("  usage: display txt txt_id\n");
290                    return;
291            }
292
293            txt_id = atoi(argv[2]);
294
295        if( display_txt_processes( txt_id ) )
296        {
297            printf("  error: illegal argument txt_id = %x\n", txt_id );
298        }
299    }
300    else if( strcmp( argv[1] , "vfs" ) == 0 )
301    {
302        if( argc != 2 )
303        {
304                    printf("  usage: display vfs\n");
305                    return;
306            }
307
308        display_vfs();
309    }
310    else if( strcmp( argv[1] , "chdev" ) == 0 )
311    {
312        if( argc != 2 )
313        {
314                    printf("  usage: display chdev\n");
315                    return;
316            }
317
318        display_chdev();
319    }
320    else
321    {
322        printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n");
323    }
324} // end cmd_display()
325
326/////////////////////////////////////////
327static void cmd_fg(int argc, char **argv)
328{
329        unsigned int pid;
330
331        if (argc != 2) 
332    {
333                printf("  usage: %s pid\n", argv[0]);
334                return;
335        }
336
337    pid = atoi( argv[1] );   
338
339    if( pid == 0 )
340    {
341                printf("  error: PID cannot be 0\n" );
342        }
343
344    if( fg( pid ) )
345    {
346                printf("  error: cannot find process %x\n", pid );
347        }
348}  // end cmd_fg()
349
350//////////////////////////////////////////////
351static void cmd_help( int argc , char **argv )
352{
353        unsigned int i;
354
355        if (argc != 1) 
356    {
357                printf("  usage: %s\n", argv[0]);
358                return;
359        }
360
361        printf("available commands:\n");
362        for (i = 0 ; cmd[i].name ; i++) 
363    {
364                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
365        }
366}   // end cmd_help()
367
368//////////////////////////////////////////////
369static void cmd_kill( int argc , char **argv )
370{
371        unsigned int pid;
372
373        if (argc != 2) 
374    {
375                printf("  usage: %s pid\n", argv[0]);
376                return;
377        }
378
379        pid = atoi( argv[1] );
380
381    if( pid == 0 )
382    {
383                printf("  error: kernel process 0 cannot be killed\n" );
384        }
385
386        if( kill( pid , SIGKILL ) )
387    {
388                printf("  error: process %x cannot be killed\n", pid );
389        }
390}   // end cmd_kill()
391
392//////////////////////////////////////////////
393static void cmd_load( int argc , char **argv )
394{
395        int                  ret_fork;           // return value from fork
396        int                  ret_exec;           // return value from exec
397    unsigned int         ksh_pid;            // KSH process PID
398        char               * pathname;           // path to .elf file
399    unsigned int         background;         // background execution if non zero
400    int                  status;             // new process exit status
401
402        if( (argc < 2) || (argc > 3) ) 
403    {
404                printf("  usage: %s pathname [&]\n", argv[0] );
405                return;
406        }
407
408        pathname = argv[1];
409
410    if( argc == 3 ) background = (argv[2][0] == '&');
411    else            background = 0;
412
413    // get KSH process PID
414    ksh_pid = getpid();
415
416    // KSH process fork CHILD process
417        ret_fork = fork();
418
419    if ( ret_fork < 0 )          // it is a failure reported to KSH
420    {
421        printf("  error: ksh process unable to fork\n");
422        return;
423    }
424    else if (ret_fork == 0)      // it is the CHILD process
425    {
426        // CHILD process exec NEW process
427        ret_exec = exec( pathname , NULL , NULL );
428
429        // this is only executed in case of exec failure
430        if( ret_exec )
431        {
432            printf("  error: child process unable to exec <%s>\n", pathname );
433            exit( 0 );
434        }   
435        } 
436    else                        // it is the parent KSH : ret_fork is the new process PID
437    {
438        // give back terminal ownership to KSH if new process created in background /
439        // wait new process completion before returning to command interpreter otherwise
440        if( background )   fg( ksh_pid );
441        else               wait( &status );
442
443        // return to command interpreter
444        return;
445    }
446}   // end cmd_load
447
448/////////////////////////////////////////////
449static void cmd_log( int argc , char **argv )
450{
451        unsigned int i;
452
453        printf("--- registered commands ---\n");
454        for (i = 0; i < LOG_DEPTH; i++) 
455    {
456                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
457        }
458}
459
460////////////////////////////////////////////
461static void cmd_ls( int argc , char **argv )
462{
463        char  * path;
464
465//  struct dirent * file;
466//  DIR *dir;
467
468        if (argc == 1)
469    {
470                path = ".";
471        }
472    else if (argc == 2) 
473    {
474                path = argv[1];
475        } 
476    else 
477    {
478                printf("  usage: ls [path]\n");
479                return;
480        }
481
482    printf("  error: not implemented yet\n");
483/*
484        dir = opendir( path );
485        while ((file = readdir(dir)) != NULL)
486        {
487                printf(" %s\n", file->d_name);
488        }
489        closedir(dir);
490*/
491}
492
493///////////////////////////////////////////////
494static void cmd_mkdir( int argc , char **argv )
495{
496        char * pathname;
497
498        if (argc != 2)
499    {
500                printf("  usage: mkdir pathname\n");
501                return;
502        }
503
504    pathname = argv[1];
505
506    printf("  error: not implemented yet\n");
507/*
508        if ( mkdir( path, 0x700) == -1 )
509    {
510                printf("  error: cannot create directory %s\n", path);
511        }
512*/
513}
514
515////////////////////////////////////////////
516static void cmd_mv( int argc , char **argv )
517{
518
519        if (argc < 3)
520        {
521                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
522                return;
523        }
524
525    printf("  error: not implemented yet\n");
526   
527/*
528        int ret = giet_fat_rename(argv[1], argv[2]);
529        if (ret < 0)
530        {
531                printf("  error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret );
532        }
533*/
534
535}
536
537/////////////////////////////////////////////
538static void cmd_pwd( int argc , char **argv )
539{
540        char buf[1024];
541
542        if (argc != 1)
543    {
544                printf("  usage: pwd\n");
545                return;
546        }
547
548        if ( getcwd( buf , 1024 ) ) 
549    {
550                printf("  error: unable to get current directory\n");
551        }
552    else 
553    {
554                printf("%s\n", buf);
555        }
556}
557
558////////////////////////////////////////////
559static void cmd_rm( int argc , char **argv )
560{
561        char * pathname;
562
563        if (argc != 2)
564    {
565                printf("  usage: rm pathname\n");
566                return;
567        }
568
569        pathname = argv[1];
570
571    printf("  error: not implemented yet\n");
572/*
573        if (remove(path) == -1)
574    {
575                printf("  error: cannot remove %s\n", path);
576        }
577*/
578
579}
580
581///////////////////////////////////////////////
582static void cmd_rmdir( int argc , char **argv )
583{
584        cmd_rm(argc, argv);
585}
586
587///////////////////////////////////////////////
588static void cmd_trace( int argc , char **argv )
589{
590    unsigned int cxy;
591    unsigned int lid;
592
593        if (argc != 3)
594    {
595                printf("  usage: trace cxy lid \n");
596                return;
597        }
598
599    cxy = atoi(argv[1]);
600    lid = atoi(argv[2]);
601
602    if( trace( 1 , cxy , lid ) )
603    {
604        printf("  error: core[%x,%d] not found\n", cxy, lid );
605    }
606}
607
608///////////////////////////////////////////////
609static void cmd_untrace( int argc , char **argv )
610{
611    unsigned int cxy;
612    unsigned int lid;
613
614        if (argc != 3)
615    {
616                printf("  usage: untrace cxy lid \n");
617                return;
618        }
619
620    cxy = atoi(argv[1]);
621    lid = atoi(argv[2]);
622
623    if( trace( 0 , cxy , lid ) )
624    {
625        printf("  error: core[%x,%d] not found\n", cxy, lid );
626    }
627}
628
629//////////////////////////////////////////////////////////////////
630// Array of commands
631//////////////////////////////////////////////////////////////////
632
633ksh_cmd_t cmd[] =
634{
635        { "cat",     "display file content",                            cmd_cat     },
636        { "cd",      "change current directory",                        cmd_cd      },
637        { "cp",      "replicate a file in file system",                 cmd_cp      },
638    { "fg",      "put a process in foreground",                     cmd_fg      },
639    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
640        { "load",    "load an user application",                        cmd_load    },
641        { "help",    "list available commands",                         cmd_help    },
642        { "kill",    "kill an application (all threads)",               cmd_kill    },
643        { "log",     "list registered commands",                        cmd_log     },
644        { "ls",      "list directory entries",                          cmd_ls      },
645        { "mkdir",   "create a new directory",                          cmd_mkdir   },
646        { "mv",      "move a file in file system",                      cmd_mv      },
647        { "pwd",     "print current working directory",                 cmd_pwd     },
648        { "rm",      "remove a file from file system",                  cmd_rm      },
649        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
650        { "trace",   "activate trace for a given core",                 cmd_trace   },
651        { "untrace", "desactivate trace for a given core",              cmd_untrace },
652        { NULL,      NULL,                                                                              NULL        }
653};
654
655////////////////////////////////////////////////////////////////////////////////////
656// This function analyses one command (with arguments), execute it, and return.
657////////////////////////////////////////////////////////////////////////////////////
658static void parse(char *buf)
659{
660        int argc = 0;
661        char *argv[MAX_ARGS];
662        int i;
663        int len = strlen(buf);
664
665        // build argc/argv
666        for (i = 0; i < len; i++) 
667    {
668                if (buf[i] == ' ') 
669        {
670                        buf[i] = '\0';
671                }
672        else if (i == 0 || buf[i - 1] == '\0') 
673        {
674                        if (argc < MAX_ARGS) 
675            {
676                                argv[argc] = &buf[i];
677                                argc++;
678                        }
679                }
680        }
681
682        if (argc > 0)
683    {
684                int found = 0;
685
686                argv[argc] = NULL;
687
688                // try to match typed command
689                for (i = 0; cmd[i].name; i++)
690        {
691                        if (strcmp(argv[0], cmd[i].name) == 0)
692            {
693                                cmd[i].fn(argc, argv);
694                                found = 1;
695                                break;
696                        }
697                }
698
699                if (!found)
700        {
701                        printf("  undefined command <%s>\n", argv[0]);
702                }
703        }
704}
705
706///////////////////////////////////
707int main( int argc , char *argv[] )
708{
709        char         c;                                           // read character
710        char         buf[CMD_MAX_SIZE];           // buffer for one command
711        unsigned int count = 0;                           // pointer in buf
712        unsigned int i;                                           // index for loops
713
714        enum fsm_states
715    {
716                NORMAL,
717                ESCAPE,
718                BRAKET,
719        };
720
721    // log buffer initialisation
722        memset( &log_entries , 0, sizeof(log_entries));
723        ptw   = 0;
724        ptr   = 0;
725
726        printf( "\n\n~~~ shell ~~~\n\n" );
727
728        // command buffer initialisation
729        memset( buf, 0x20 , sizeof(buf) );
730        count = 0;
731
732        // display first prompt
733        printf("# ");
734
735        // This lexical analyser writes one command line in the buf buffer.
736        // It is implemented as a 3 states FSM to handle the following sequences:
737        // - ESC [ A : up arrow
738        // - ESC [ B : down arrow
739        // - ESC [ C : right arrow
740        // - ESC [ D : left arrow
741        // The three states have the following semantic:
742        // - NORMAL : no (ESC) character has been found
743        // - ESCAPE : the character (ESC) has been found
744        // - BRAKET : the wo characters (ESC,[) have been found
745
746        unsigned int state = NORMAL;
747
748// @@@
749// parse("load /bin/user/hello.elf");
750// @@@
751
752        while (1)
753        {
754                c = (char)getchar();
755
756        if( c == 0 ) continue;
757
758                switch (state)
759                {
760                        case NORMAL:
761                        {
762                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
763                                {
764                                        if (count > 0) {
765                                                printf("\b \b");
766                                                count--;
767                                        }
768                                }
769                                else if (c == '\n')      // new line => call parser to execute command
770                                {
771                                        if (count > 0)
772                                        {
773                                                // complete command
774                                                buf[count] = '\0';
775
776                                                // register command in log arrays
777                                                strcpy(log_entries[ptw].buf, buf);
778                                                log_entries[ptw].count = count;
779                                                ptw = (ptw + 1) % LOG_DEPTH;
780                                                ptr = ptw;
781
782                                                // execute command
783                                                printf("\n");
784                                                parse((char *)&buf);
785
786                                                // reinitialise buffer and display prompt
787                                                for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
788                                                count = 0;
789                                                printf("# ");
790                                        }
791                    else
792                    {
793                        printf("\n# ");
794                    }
795                                }
796                                else if (c == '\t')     // tabulation => do nothing
797                                {
798                                }
799                                else if (c == (char)0x1B)       // ESC => start an escape sequence
800                                {
801                                        state = ESCAPE;
802                                }
803                                else if (c == 0x03)     // ^C  => cancel current command
804                                {
805                                        for (i = 0; i < count; i++) printf("\b \b");
806                                        for (i = 0; i < sizeof(buf); i++) buf[i] = 0x20;
807                                        count = 0;
808                                }
809                                else                                     // register character in command buffer
810                                {
811                                        if (count < sizeof(buf) - 1)
812                                        {
813                                                putchar( c );
814                                                buf[count] = c;
815                                                count++;
816                                        }
817                                }
818                                break;
819                        }
820                        case ESCAPE:
821                        {
822                                if (c == '[')           //  valid sequence => continue
823                                {
824                                        state = BRAKET;
825                                }
826                                else                               // invalid sequence => do nothing
827                                {
828                                        state = NORMAL;
829                                }
830                                break;
831                        }
832                        case BRAKET:
833                        {
834                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
835                                {
836                                        if (count > 0)
837                                        {
838                                                printf("\b");
839                                                count--;
840                                        }
841
842                                        // get next user char
843                                        state = NORMAL;
844                                }
845                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
846                                {
847                                        if (count < sizeof(buf) - 1)
848                                        {
849                                                printf("%c", buf[count]);
850                                                count++;
851                                        }
852
853                                        // get next user char
854                                        state = NORMAL;
855                                }
856                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
857                                {
858                                        // cancel current command
859                                        for (i = 0; i < count; i++) printf("\b \b");
860                                        count = 0;
861
862                                        // copy log command into buf
863                                        ptr = (ptr - 1) % LOG_DEPTH;
864                                        strcpy(buf, log_entries[ptr].buf);
865                                        count = log_entries[ptr].count;
866
867                                        // display log command
868                                        printf("%s", buf);
869
870                                        // get next user char
871                                        state = NORMAL;
872                                }
873                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
874                                {
875                                        // cancel current command
876                                        for (i = 0 ; i < count; i++) printf("\b \b");
877                                        count = 0;
878
879                                        // copy log command into buf
880                                        ptr = (ptr + 1) % LOG_DEPTH;
881                                        strcpy(buf, log_entries[ptr].buf);
882                                        count = log_entries[ptr].count;
883
884                                        // display log command
885                                        printf("%s", buf);
886
887                                        // get next user char
888                                        state = NORMAL;
889                                }
890                                else                               // other character => do nothing
891                                {
892                                        // get next user char
893                                        state = NORMAL;
894                                }
895                                break;
896                        }
897                }
898        }
899}  // end main()
900
Note: See TracBrowser for help on using the repository browser.