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

Last change on this file since 444 was 444, checked in by satin@…, 4 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

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