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

Last change on this file since 434 was 434, checked in by alain, 7 years ago

blap

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