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

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

Introduce user libraries

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