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

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

Improve sys_exec.

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