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

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

Fix several bugs in the fork() syscall.

File size: 15.2 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 <nostdio.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.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_help( int argc , char **argv )
232{
233        unsigned int i;
234
235        if (argc != 1) 
236    {
237                printf("usage: %s\n", argv[0]);
238                return;
239        }
240
241        printf("available commands:\n");
242        for (i = 0 ; cmd[i].name ; i++) 
243    {
244                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
245        }
246}   // end cmd_help()
247
248//////////////////////////////////////////////
249static void cmd_kill( int argc , char **argv )
250{
251        unsigned int pid;
252
253        if (argc != 2) 
254    {
255                printf("usage: %s pid\n", argv[0]);
256                return;
257        }
258
259        pid = atoi(argv[1]);
260
261        if( kill( pid , 9 ) )   // TODO replace 9 by SIGKILL
262    {
263                printf("error: unable to kill process %x\n", pid );
264        }
265}   // end cmd_kill()
266
267//////////////////////////////////////////////
268static void cmd_load( int argc , char **argv )
269{
270        unsigned int         pid;
271    unsigned int         error;
272        char               * pathname;
273
274        if (argc != 2) 
275    {
276                printf("usage: %s pathname \n", argv[0] );
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        printf("CHILD\n");
288        exit(0);
289
290        // exec system call
291        // error = exec( pathname , NULL , NULL );
292
293        // if( error )
294        // {
295        //    printf("error: new process unable to exec <%s>\n", pathname );
296        //    exit();
297        // }
298        } 
299    else if ( pid < 0 )  // it is a failure reported to parent
300    {
301        printf("error: unable to fork\n");
302    }
303    else                 // it is a success reported to parent
304    {
305        printf("PARENT\n");
306        exit(0);
307    }
308
309}   // end cmd_load
310
311/////////////////////////////////////////////
312static void cmd_log( int argc , char **argv )
313{
314        unsigned int i;
315
316        printf("--- registered commands ---\n");
317        for (i = 0; i < LOG_DEPTH; i++) 
318    {
319                printf(" - %zu\t: %s\n", i, &log_entries[i].buf);
320        }
321}
322
323////////////////////////////////////////////
324static void cmd_ls( int argc , char **argv )
325{
326        char  * path;
327
328//  struct dirent * file;
329//  DIR *dir;
330
331        if (argc == 1)
332    {
333                path = ".";
334        }
335    else if (argc == 2) 
336    {
337                path = argv[1];
338        } 
339    else 
340    {
341                printf("usage: ls [path]\n");
342                return;
343        }
344
345    printf("error: not implemented yet\n");
346/*
347        dir = opendir( path );
348        while ((file = readdir(dir)) != NULL)
349        {
350                printf(" %s\n", file->d_name);
351        }
352        closedir(dir);
353*/
354}
355
356///////////////////////////////////////////////
357static void cmd_mkdir( int argc , char **argv )
358{
359        char * pathname;
360
361        if (argc != 2)
362    {
363                printf("usage: mkdir pathname\n");
364                return;
365        }
366
367    pathname = argv[1];
368
369    printf("error: not implemented yet\n");
370/*
371        if ( mkdir( path, 0x700) == -1 )
372    {
373                printf("error: cannot create directory %s\n", path);
374        }
375*/
376}
377
378////////////////////////////////////////////
379static void cmd_mv( int argc , char **argv )
380{
381
382        if (argc < 3)
383        {
384                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
385                return;
386        }
387
388    printf("error: not implemented yet\n");
389   
390/*
391        int ret = giet_fat_rename(argv[1], argv[2]);
392        if (ret < 0)
393        {
394                printf("error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret );
395        }
396*/
397
398}
399
400/////////////////////////////////////////////
401static void cmd_pwd( int argc , char **argv )
402{
403        char buf[1024];
404
405        if (argc != 1)
406    {
407                printf("usage: pwd\n");
408                return;
409        }
410
411        if ( getcwd( buf , 1024 ) ) 
412    {
413                printf("error: unable to get current directory\n");
414        }
415    else 
416    {
417                printf("%s\n", buf);
418        }
419}
420
421////////////////////////////////////////////
422static void cmd_rm( int argc , char **argv )
423{
424        char * pathname;
425
426        if (argc != 2)
427    {
428                printf("usage: rm pathname\n");
429                return;
430        }
431
432        pathname = argv[1];
433
434    printf("error: not implemented yet\n");
435/*
436        if (remove(path) == -1)
437    {
438                printf("error: cannot remove %s\n", path);
439        }
440*/
441
442}
443
444///////////////////////////////////////////////
445static void cmd_rmdir( int argc , char **argv )
446{
447        cmd_rm(argc, argv);
448}
449
450///////////////////////////////////////////////
451static void cmd_sched( int argc , char **argv )
452{
453    unsigned int cxy;
454    unsigned int lid;
455
456        if (argc != 3)
457    {
458                printf("usage: sched cxy lid\n");
459                return;
460        }
461
462        cxy = atoi(argv[1]);
463        lid = atoi(argv[2]);
464
465    if( get_sched( cxy , lid ) )
466    {
467        printf("error: illegal arguments\n");
468    }
469}
470
471//////////////////////////////////////////////////////////////////
472// Array of commands
473//////////////////////////////////////////////////////////////////
474
475ksh_cmd_t cmd[] =
476{
477        { "cat",    "display file content",                cmd_cat   },
478        { "cd",     "change current directory",            cmd_cd    },
479        { "cp",     "replicate a file in file system",     cmd_cp    },
480        { "load",   "load an user application",            cmd_load  },
481        { "help",   "list available commands",             cmd_help  },
482        { "kill",   "kill an application (all threads)",   cmd_kill  },
483        { "log",    "list registered commands",            cmd_log   },
484        { "ls",     "list directory entries",              cmd_ls    },
485        { "mkdir",  "create a new directory",              cmd_mkdir },
486        { "mv",     "move a file in file system",          cmd_mv    },
487        { "pwd",    "print current working directory",     cmd_pwd   },
488        { "rm",     "remove a file from file system",      cmd_rm    },
489        { "rmdir",  "remove a directory from file system", cmd_rmdir },
490    { "sched",  "display scheduler state",             cmd_sched },
491        { NULL,     NULL,                                                                  NULL      }
492};
493
494////////////////////////////////////////////////////////////////////////////////////
495// This function analyses one command (with arguments), execute it, and return.
496////////////////////////////////////////////////////////////////////////////////////
497static void parse(char *buf)
498{
499        int argc = 0;
500        char *argv[MAX_ARGS];
501        int i;
502        int len = strlen(buf);
503
504        // build argc/argv
505        for (i = 0; i < len; i++) 
506    {
507                if (buf[i] == ' ') 
508        {
509                        buf[i] = '\0';
510                }
511        else if (i == 0 || buf[i - 1] == '\0') 
512        {
513                        if (argc < MAX_ARGS) 
514            {
515                                argv[argc] = &buf[i];
516                                argc++;
517                        }
518                }
519        }
520
521        if (argc > 0)
522    {
523                int found = 0;
524
525                argv[argc] = NULL;
526
527                // try to match typed command
528                for (i = 0; cmd[i].name; i++)
529        {
530                        if (strcmp(argv[0], cmd[i].name) == 0)
531            {
532                                cmd[i].fn(argc, argv);
533                                found = 1;
534                                break;
535                        }
536                }
537
538                if (!found)
539        {
540                        printf("\n  undefined command %s\n", argv[0]);
541                }
542        }
543}
544
545///////////////////////////////////
546int main( int argc , char *argv[] )
547{
548        char         c;                                           // read character
549        char         buf[CMD_MAX_SIZE];           // buffer for one command
550        unsigned int count = 0;                           // pointer in buf
551        unsigned int i;                                           // index for loops
552
553        enum fsm_states
554    {
555                NORMAL,
556                ESCAPE,
557                BRAKET,
558        };
559
560    // log buffer initialisation
561        memset( &log_entries , 0, sizeof(log_entries));
562        ptw   = 0;
563        ptr   = 0;
564
565        printf( "~~~ shell ~~~\n\n" );
566
567        // command buffer initialisation
568        memset( buf, 0x20 , sizeof(buf) );
569        count = 0;
570
571        // display first prompt
572        printf("# ");
573
574        // This lexical analyser writes one command line in the buf buffer.
575        // It is implemented as a 3 states FSM to handle the following sequences:
576        // - ESC [ A : up arrow
577        // - ESC [ B : down arrow
578        // - ESC [ C : right arrow
579        // - ESC [ D : left arrow
580        // The three states have the following semantic:
581        // - NORMAL : no (ESC) character has been found
582        // - ESCAPE : the character (ESC) has been found
583        // - BRAKET : the wo characters (ESC,[) have been found
584        unsigned int state = NORMAL;
585
586// @@@
587parse("load /bin/user/sort.elf");
588// @@@
589
590
591   
592        while (1)
593        {
594                c = (char)getchar();
595
596        if( c == 0 ) continue;
597
598                switch (state)
599                {
600                        case NORMAL:
601                        {
602                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
603                                {
604                                        if (count > 0) {
605                                                printf("\b \b");
606                                                count--;
607                                        }
608                                }
609                                else if (c == '\n')      // new line => call parser to execute command
610                                {
611                                        if (count > 0)
612                                        {
613                                                // complete command
614                                                buf[count] = '\0';
615
616                                                // register command in log arrays
617                                                strcpy(log_entries[ptw].buf, buf);
618                                                log_entries[ptw].count = count;
619                                                ptw = (ptw + 1) % LOG_DEPTH;
620                                                ptr = ptw;
621
622                                                // execute command
623                                                printf("\n");
624                                                parse((char *)&buf);
625
626                                                // reinitialise buffer and display prompt
627                                                for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
628                                                count = 0;
629                                                printf("# ");
630                                        }
631                                }
632                                else if (c == '\t')     // tabulation => do nothing
633                                {
634                                }
635                                else if (c == 0x1B)     // ESC => start an escape sequence
636                                {
637                                        state = ESCAPE;
638                                }
639                                else if (c == 0x03)     // ^C  => cancel current command
640                                {
641                                        for (i = 0; i < count; i++) printf("\b \b");
642                                        for (i = 0; i < sizeof(buf); i++) buf[i] = 0x20;
643                                        count = 0;
644                                }
645                                else                                     // register character in command buffer
646                                {
647                                        if (count < sizeof(buf) - 1)
648                                        {
649                                                printf("%c", c);
650                                                buf[count] = c;
651                                                count++;
652                                        }
653                                }
654                                break;
655                        }
656                        case ESCAPE:
657                        {
658                                if (c == '[')           //  valid sequence => continue
659                                {
660                                        state = BRAKET;
661                                }
662                                else                               // invalid sequence => do nothing
663                                {
664                                        state = NORMAL;
665                                }
666                                break;
667                        }
668                        case BRAKET:
669                        {
670                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
671                                {
672                                        if (count > 0)
673                                        {
674                                                printf("\b");
675                                                count--;
676                                        }
677
678                                        // get next user char
679                                        state = NORMAL;
680                                }
681                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
682                                {
683                                        if (count < sizeof(buf) - 1)
684                                        {
685                                                printf("%c", buf[count]);
686                                                count++;
687                                        }
688
689                                        // get next user char
690                                        state = NORMAL;
691                                }
692                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
693                                {
694                                        // cancel current command
695                                        for (i = 0; i < count; i++) printf("\b \b");
696                                        count = 0;
697
698                                        // copy log command into buf
699                                        ptr = (ptr - 1) % LOG_DEPTH;
700                                        strcpy(buf, log_entries[ptr].buf);
701                                        count = log_entries[ptr].count;
702
703                                        // display log command
704                                        printf("%s", buf);
705
706                                        // get next user char
707                                        state = NORMAL;
708                                }
709                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
710                                {
711                                        // cancel current command
712                                        for (i = 0 ; i < count; i++) printf("\b \b");
713                                        count = 0;
714
715                                        // copy log command into buf
716                                        ptr = (ptr + 1) % LOG_DEPTH;
717                                        strcpy(buf, log_entries[ptr].buf);
718                                        count = log_entries[ptr].count;
719
720                                        // display log command
721                                        printf("%s", buf);
722
723                                        // get next user char
724                                        state = NORMAL;
725                                }
726                                else                               // other character => do nothing
727                                {
728                                        // get next user char
729                                        state = NORMAL;
730                                }
731                                break;
732                        }
733                }
734        }
735}
736
Note: See TracBrowser for help on using the repository browser.