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

Last change on this file since 473 was 473, checked in by alain, 3 years ago

Fix several GCC warning related to the -Wextra compilation option.

File size: 27.1 KB
RevLine 
[469]1/////////////////////////////////////////////////////////////////////////////////////////
[407]2// File   :  ksh.c
3// Date   :  October 2017
4// Author :  Alain Greiner
[469]5/////////////////////////////////////////////////////////////////////////////////////////
[457]6// This application implements a minimal shell for ALMOS-MKH.
7//
8// This user KSH process contains two POSIX threads:
[446]9// - the "main" thread contains the infinite loop implementing
[469]10//   the children processes termination monitoring, using the wait syscall.
11// - the "interactive" thread contains the infinite loop implementing the command
12//   interpreter attached to the TXT terminal, and handling one KSH command
13//   per iteration.
[457]14//
[469]15// The children processes are created by the <load> command, and are
[457]16// attached to the same TXT terminal as the KSH process itself.
[469]17// A child process can be lauched in foreground or in background:
18// . when the child process is running in foreground, the KSH process loses
19//   the TXT terminal ownership, that is transfered to the child process.
20// . when the child process is running in background: the KSH process keeps
21//   the TXT terminal ownership.
22//
23// A semaphore is used to synchronize the two KSH threads. At each iteration,
24// the interactive thread check the semaphore (with a sem_wait). It blocks
25// and deschedules, if the KSH process loosed the TXT ownership (after a load,
26// or for any other cause. It unblocks with the following policy:
27// . if the command is "not a load", the semaphore is incremented by the
28//   cmd_***() function when the command is completed, to allow the KSH interactive()
29//   function to get the next command in the while loop.   
30// . if the command is a "load without &", the TXT is given to the NEW process by the
31//   execve() syscall, and is released to the KSH process when NEW process terminates.
32//   The KSH process is notified and the KSH main() function increments the semahore
33//   to allow the KSH interactive() function to handle commands.
34// . if the command is a "load with &", the cmd_load() function returns the TXT
35//   to the KSH process and increment the semaphore, when the parent KSH process
36//   returns from the fork() syscall.
37/////////////////////////////////////////////////////////////////////////////////////////
[230]38
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
[444]42#include <sys/wait.h>
43#include <signal.h>
44#include <unistd.h>
[445]45#include <almosmkh.h>
[457]46#include <semaphore.h>
[230]47
[407]48#define CMD_MAX_SIZE   (256)    // max number of characters in one command
[436]49#define LOG_DEPTH      (32)     // max number of registered commands
[407]50#define MAX_ARGS           (32)     // max number of arguments in a command
51#define FIFO_SIZE      (1024)   // FIFO depth for recursive ls
[230]52
[469]53#define KSH_DEBUG           0
54#define CMD_LOAD_DEBUG      0
[457]55
[469]56//////////////////////////////////////////////////////////////////////////////////////////
[407]57//         Structures
[469]58//////////////////////////////////////////////////////////////////////////////////////////
[230]59
[407]60// one entry in the registered commands array
61typedef struct log_entry_s
62{
63        char          buf[CMD_MAX_SIZE];
64        unsigned int  count;
65}
66log_entry_t;
[230]67
[407]68// one entry in the supported command types array
69typedef struct ksh_cmd_s
70{
71        char * name;
72        char * desc;
73        void   (*fn)( int , char ** );
74}
75ksh_cmd_t;
76
77
[469]78//////////////////////////////////////////////////////////////////////////////////////////
[230]79//         Global Variables
[469]80//////////////////////////////////////////////////////////////////////////////////////////
[230]81
[407]82ksh_cmd_t       cmd[];                    // array of supported commands
[230]83
[407]84log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
[230]85
[407]86unsigned int    ptw;                      // write pointer in log_entries[]
87unsigned int    ptr;                      // read pointer in log_entries[]
[230]88
[457]89pthread_attr_t  attr;                     // interactive thread attributes
[446]90
[457]91sem_t           semaphore;                // block interactive thread when zero
92
[469]93//////////////////////////////////////////////////////////////////////////////////////////
[230]94//         Shell  Commands
[469]95//////////////////////////////////////////////////////////////////////////////////////////
[230]96
[407]97/////////////////////////////////////////////
98static void cmd_cat( int argc , char **argv )
[230]99{
[407]100        char         * path;
[230]101
[407]102        if (argc != 2) 
103    {
[409]104                printf("  usage: cat pathname\n");
[230]105                return;
106        }
[407]107
[230]108        path = argv[1];
109
[473]110    printf("  error: not implemented yet\n", argc, argv );
[407]111
112/*
113        // open the file
114        fd = open( path , O_RDONLY , 0 );
115        if (fd < 0)
116    {
[409]117                printf("  error: cannot open %s\n", path);
[230]118                goto exit;
119        }
120
[407]121        // get file size
122        if (stat(path, &st) == -1)
123    {
[409]124                printf("  error: cannot stat %s\n", path);
[230]125                goto exit;
126        }
127        if (S_ISDIR(st.st_mode)) {
[409]128                printf("  error: %s is a directory\n", path);
[230]129                goto exit;
130        }
131        size = st.st_size;
132
[407]133        // mmap the file
[230]134        buf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
135        if (buf == NULL || buf == (char *)-1) {
[409]136                printf("  error: cannot map %s\n", path);
[230]137                goto exit;
138        }
139
[446]140        // set terminating '0'
[230]141        buf[size-1] = 0;
142
[407]143        // display the file content
[230]144        printf("%s", buf);
145
146exit:
[407]147        if (buf != NULL) munmap(buf, size);
148        if (fd >= 0) close(fd);
149*/
[230]150
[457]151    // release semaphore to get next command
152    sem_post( &semaphore );
153
[407]154}   // end cmd_cat()
155
156////////////////////////////////////////////
157static void cmd_cd( int argc , char **argv )
158{
159        char * path;
160
161        if (argc != 2)
162    {
[409]163                printf("  usage: cd pathname\n");
[407]164                return;
165        }
166
167        path = argv[1];
168
[473]169    printf("  error: not implemented yet\n", argc, argv );
[407]170
[457]171    // release semaphore to get next command
172    sem_post( &semaphore );
[407]173
174}   // end cmd_cd()
175
176/////////////////////////////////////////
[230]177static void cmd_cp(int argc, char **argv)
178{
[407]179//      int src_fd = -1, dst_fd = -1;
180//      char *srcpath, *dstpath;
181//      struct stat st;
182//      size_t size, i;
183//      char buf[1024];
[230]184
[407]185        if (argc != 3) 
186    {
[409]187                printf("  usage: cp src_pathname dst_pathname\n");
[230]188                return;
189        }
190
[473]191    printf("  error: not implemented yet\n", argc, argv );
[407]192
193/*
[230]194        srcpath = argv[1];
195        dstpath = argv[2];
196
[407]197        // open the src file
[230]198        src_fd = open(srcpath, O_RDONLY, 0);
199        if (src_fd < 0) {
[409]200                printf("  error: cannot open %s / err = %d\n", srcpath, errno);
[230]201                goto exit;
202        }
203
[407]204        // get file size
[230]205        if (stat(srcpath, &st) == -1) {
[409]206                printf("  error: cannot stat %s\n", srcpath);
[230]207                goto exit;
208        }
209        if (S_ISDIR(st.st_mode)) {
[409]210                printf("  error: %s is a directory\n", srcpath);
[230]211                goto exit;
212        }
213        size = st.st_size;
214
[407]215        // open the dst file
[230]216        dst_fd = open(dstpath, O_CREAT|O_TRUNC|O_RDWR, 0);
217        if (dst_fd < 0) {
[409]218                printf("  error: cannot open %s / err = %d\n", dstpath, errno);
[230]219                goto exit;
220        }
221        if (stat(dstpath, &st) == -1) {
[409]222                printf("  error: cannot stat %s\n", dstpath);
[230]223                goto exit;
224        }
225        if (S_ISDIR(st.st_mode)) {
[409]226                printf("  error: %s is a directory\n", dstpath);
[230]227                goto exit;
228        }
229
230        i = 0;
231        while (i < size)
232        {
233                size_t rlen = (size - i < 1024 ? size - i : 1024);
234                size_t wlen;
235                ssize_t ret;
236
[407]237                // read the source
[230]238                ret = read(src_fd, buf, rlen);
239                if (ret == -1) {
[409]240                        printf("  error: cannot read from file %s\n", srcpath);
[230]241                        goto exit;
242                }
243                rlen = (size_t)ret;
244
[407]245                // write to the destination
[230]246                ret = write(dst_fd, buf, rlen);
247                if (ret == -1) {
[409]248                        printf("  error: cannot write to file %s\n", dstpath);
[230]249                        goto exit;
250                }
251                wlen = (size_t)ret;
252
[407]253                // check
[230]254                if (wlen != rlen) {
[409]255                        printf("  error: cannot write on device\n");
[230]256                        goto exit;
257                }
258
259                i += rlen;
260        }
261
262exit:
[407]263        if (src_fd >= 0) close(src_fd);
264        if (dst_fd >= 0) close(dst_fd);
265*/
[230]266
[457]267    // release semaphore to get next command
268    sem_post( &semaphore );
269
[407]270}   // end cmd_cp()
271
[436]272/////////////////////////////////////////////////
273static void cmd_display( int argc , char **argv )
274{
275    unsigned int  cxy;
276    unsigned int  lid;
277    unsigned int  pid;
278    unsigned int  txt_id;
279
280    if( strcmp( argv[1] , "vmm" ) == 0 )
281    {
[442]282        if( argc != 4 )
[436]283        {
[442]284                    printf("  usage: display vmm cxy pid\n");
[436]285                    return;
286            }
287
[442]288            cxy = atoi(argv[2]);
289            pid = atoi(argv[3]);
[436]290
[442]291        if( display_vmm( cxy , pid ) )
[436]292        {
[442]293            printf("  error: no process %x in cluster %x\n", pid , cxy );
[436]294        }
295    }
296    else if( strcmp( argv[1] , "sched" ) == 0 )
297    {
298        if( argc != 4 )
299        {
300                    printf("  usage: display sched cxy lid\n");
301                    return;
302            }
303
304            cxy = atoi(argv[2]);
305            lid = atoi(argv[3]);
306
307        if( display_sched( cxy , lid ) )
308        {
309            printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
310        }
311    }
312    else if( strcmp( argv[1] , "process" ) == 0 )
313    {
314        if( argc != 3 )
315        {
316                    printf("  usage: display process cxy\n");
317                    return;
318            }
319
320            cxy = atoi(argv[2]);
321
322        if( display_cluster_processes( cxy ) )
323        {
324            printf("  error: illegal argument cxy = %x\n", cxy );
325        }
326    }
327    else if( strcmp( argv[1] , "txt" ) == 0 )
328    {
329        if( argc != 3 )
330        {
331                    printf("  usage: display txt txt_id\n");
332                    return;
333            }
334
335            txt_id = atoi(argv[2]);
336
337        if( display_txt_processes( txt_id ) )
338        {
[458]339            printf("  error: illegal argument txt_id = %d\n", txt_id );
[436]340        }
341    }
342    else if( strcmp( argv[1] , "vfs" ) == 0 )
343    {
344        if( argc != 2 )
345        {
346                    printf("  usage: display vfs\n");
347                    return;
348            }
349
350        display_vfs();
351    }
352    else if( strcmp( argv[1] , "chdev" ) == 0 )
353    {
354        if( argc != 2 )
355        {
356                    printf("  usage: display chdev\n");
357                    return;
358            }
359
360        display_chdev();
361    }
[445]362    else if( strcmp( argv[1] , "dqdt" ) == 0 )
363    {
364        if( argc != 2 )
365        {
366                    printf("  usage: display dqdt\n");
367                    return;
368            }
369
370        display_dqdt();
371    }
[436]372    else
373    {
374        printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n");
375    }
[457]376
377    // release semaphore to get next command
378    sem_post( &semaphore );
379
[436]380} // end cmd_display()
381
[427]382/////////////////////////////////////////
383static void cmd_fg(int argc, char **argv)
384{
385        unsigned int pid;
386
387        if (argc != 2) 
388    {
389                printf("  usage: %s pid\n", argv[0]);
390                return;
391        }
392
393    pid = atoi( argv[1] );   
394
395    if( pid == 0 )
396    {
[442]397                printf("  error: PID cannot be 0\n" );
[427]398        }
399
400    if( fg( pid ) )
401    {
402                printf("  error: cannot find process %x\n", pid );
403        }
[457]404
405    // release semaphore to get next command
406    sem_post( &semaphore );
407
[436]408}  // end cmd_fg()
[427]409
[407]410//////////////////////////////////////////////
411static void cmd_help( int argc , char **argv )
[230]412{
[407]413        unsigned int i;
[230]414
[407]415        if (argc != 1) 
416    {
[409]417                printf("  usage: %s\n", argv[0]);
[230]418                return;
419        }
420
421        printf("available commands:\n");
[407]422        for (i = 0 ; cmd[i].name ; i++) 
423    {
[230]424                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
425        }
[457]426
427    // release semaphore to get next command
428    sem_post( &semaphore );
429
[407]430}   // end cmd_help()
[230]431
[407]432//////////////////////////////////////////////
433static void cmd_kill( int argc , char **argv )
[230]434{
[407]435        unsigned int pid;
[230]436
[407]437        if (argc != 2) 
438    {
[409]439                printf("  usage: %s pid\n", argv[0]);
[230]440                return;
441        }
442
[427]443        pid = atoi( argv[1] );
[230]444
[427]445    if( pid == 0 )
446    {
[440]447                printf("  error: kernel process 0 cannot be killed\n" );
[427]448        }
449
[416]450        if( kill( pid , SIGKILL ) )
[407]451    {
[440]452                printf("  error: process %x cannot be killed\n", pid );
[230]453        }
[457]454
455    // release semaphore to get next command
456    sem_post( &semaphore );
457
[407]458}   // end cmd_kill()
[230]459
[407]460//////////////////////////////////////////////
461static void cmd_load( int argc , char **argv )
[230]462{
[436]463        int                  ret_fork;           // return value from fork
464        int                  ret_exec;           // return value from exec
465    unsigned int         ksh_pid;            // KSH process PID
466        char               * pathname;           // path to .elf file
467    unsigned int         background;         // background execution if non zero
[407]468
[427]469        if( (argc < 2) || (argc > 3) ) 
[407]470    {
[469]471                printf("  usage: %s pathname [&] / argc = %d\n", argv[0], argc );  // @@@
[407]472                return;
473        }
474
475        pathname = argv[1];
476
[427]477    if( argc == 3 ) background = (argv[2][0] == '&');
[434]478    else            background = 0;
[427]479
[434]480    // get KSH process PID
481    ksh_pid = getpid();
[407]482
[469]483#if CMD_LOAD_DEBUG
484long long unsigned cycle;
485get_cycle( &cycle );
486printf("\n@@@ %s : KSH PID %x before fork / path %s / background %d / cycle %d\n",
487__FUNCTION__, ksh_pid, argv[1], background, (int)cycle );
[457]488#endif
489
[434]490    // KSH process fork CHILD process
[436]491        ret_fork = fork();
[434]492
[457]493    if ( ret_fork < 0 )     // it is a failure reported to KSH
[407]494    {
[434]495        printf("  error: ksh process unable to fork\n");
[440]496        return;
[434]497    }
[457]498    else if (ret_fork == 0) // it is the CHILD process
[434]499    {
[469]500
501#if CMD_LOAD_DEBUG
502get_cycle( &cycle );
503printf("\n@@@ %s : CHILD_PID %x after fork, before exec / cycle %d\n",
504__FUNCTION__ , getpid(), (int)cycle );
505#endif
506
[434]507        // CHILD process exec NEW process
[444]508        ret_exec = execve( pathname , NULL , NULL );
[434]509
[469]510#if CMD_LOAD_DEBUG
511get_cycle( &cycle );
512printf("\n@@@ %s : CHILD_PID %x after exec / ret_exec %d / cycle %d\n",
513__FUNCTION__ , getpid(), ret_exec, (int)cycle );
514#endif
515
[441]516        // this is only executed in case of exec failure
[436]517        if( ret_exec )
[409]518        {
[441]519            printf("  error: child process unable to exec <%s>\n", pathname );
520            exit( 0 );
[436]521        }   
522        } 
[457]523    else                    // it is the KSH process : ret_fork is the new process PID
[436]524    {
525
[469]526#if CMD_LOAD_DEBUG
527get_cycle( &cycle );
528printf("\n@@@ %s : KSH_PID %x after fork / ret_fork %x / cycle %d\n",
529__FUNCTION__, getpid(), ret_fork, (int)cycle );
[457]530#endif
531
[469]532        if( background )    // child in background =>  KSH must keep TXT ownership
[457]533        {
534            // execve() tranfered TXT ownership to child => give it back to KSH
535            fg( ksh_pid );
536
537            // release semaphore to get next command
538            sem_post( &semaphore );
539        }
[436]540    }
[407]541}   // end cmd_load
542
543/////////////////////////////////////////////
544static void cmd_log( int argc , char **argv )
545{
546        unsigned int i;
547
[473]548        if (argc != 1)
549    {
550                printf("  usage: %s\n", argv[0], argc ); 
551                return;
552        }
553
[230]554        printf("--- registered commands ---\n");
[407]555        for (i = 0; i < LOG_DEPTH; i++) 
556    {
[436]557                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
[230]558        }
559
[457]560    // release semaphore to get next command
561    sem_post( &semaphore );
562
563} // end cmd_log()
564
565
[407]566////////////////////////////////////////////
567static void cmd_ls( int argc , char **argv )
[230]568{
[407]569        char  * path;
[230]570
[407]571//  struct dirent * file;
572//  DIR *dir;
573
574        if (argc == 1)
575    {
[230]576                path = ".";
[407]577        }
578    else if (argc == 2) 
579    {
[230]580                path = argv[1];
[407]581        } 
582    else 
583    {
[409]584                printf("  usage: ls [path]\n");
[230]585                return;
586        }
587
[409]588    printf("  error: not implemented yet\n");
[407]589/*
590        dir = opendir( path );
[230]591        while ((file = readdir(dir)) != NULL)
592        {
593                printf(" %s\n", file->d_name);
594        }
595        closedir(dir);
[407]596*/
[230]597
[457]598    // release semaphore to get next command
599    sem_post( &semaphore );
600
601} // end cmd_ls()
602
[407]603///////////////////////////////////////////////
604static void cmd_mkdir( int argc , char **argv )
[230]605{
[407]606        char * pathname;
[230]607
[407]608        if (argc != 2)
609    {
[409]610                printf("  usage: mkdir pathname\n");
[230]611                return;
612        }
613
[407]614    pathname = argv[1];
[230]615
[409]616    printf("  error: not implemented yet\n");
[230]617
[457]618    // release semaphore to get next command
619    sem_post( &semaphore );
620
621} // end cmd_mkdir()
622
[407]623////////////////////////////////////////////
624static void cmd_mv( int argc , char **argv )
[230]625{
[407]626
[230]627        if (argc < 3)
628        {
629                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
630                return;
631        }
632
[409]633    printf("  error: not implemented yet\n");
[407]634   
[457]635    // release semaphore to get next command
636    sem_post( &semaphore );
[407]637
[457]638}  // end cmd_mv
[230]639
[407]640/////////////////////////////////////////////
641static void cmd_pwd( int argc , char **argv )
[230]642{
[407]643        char buf[1024];
[230]644
[407]645        if (argc != 1)
646    {
[473]647                printf("  usage: %s\n", argv[0]);
[407]648                return;
649        }
650
651        if ( getcwd( buf , 1024 ) ) 
652    {
[409]653                printf("  error: unable to get current directory\n");
[407]654        }
655    else 
656    {
657                printf("%s\n", buf);
658        }
659
[457]660    // release semaphore to get next command
661    sem_post( &semaphore );
662
663}  // end cmd_pwd()
664
[407]665////////////////////////////////////////////
666static void cmd_rm( int argc , char **argv )
667{
668        char * pathname;
669
670        if (argc != 2)
671    {
[473]672                printf("  usage: %s pathname\n", argv[0]);
[230]673                return;
674        }
675
[407]676        pathname = argv[1];
[230]677
[409]678    printf("  error: not implemented yet\n");
[407]679
[457]680    // release semaphore to get next command
681    sem_post( &semaphore );
[230]682
[457]683}  // end_cmd_rm()
684
[407]685///////////////////////////////////////////////
686static void cmd_rmdir( int argc , char **argv )
[230]687{
[457]688    // same as cmd_rm()
[230]689        cmd_rm(argc, argv);
690}
691
[442]692///////////////////////////////////////////////
693static void cmd_trace( int argc , char **argv )
694{
695    unsigned int cxy;
696    unsigned int lid;
697
698        if (argc != 3)
699    {
700                printf("  usage: trace cxy lid \n");
701                return;
702        }
703
704    cxy = atoi(argv[1]);
705    lid = atoi(argv[2]);
706
707    if( trace( 1 , cxy , lid ) )
708    {
709        printf("  error: core[%x,%d] not found\n", cxy, lid );
710    }
711
[457]712    // release semaphore to get next command
713    sem_post( &semaphore );
714
715}  // end cmd_trace
716
[442]717///////////////////////////////////////////////
718static void cmd_untrace( int argc , char **argv )
719{
720    unsigned int cxy;
721    unsigned int lid;
722
723        if (argc != 3)
724    {
725                printf("  usage: untrace cxy lid \n");
726                return;
727        }
728
729    cxy = atoi(argv[1]);
730    lid = atoi(argv[2]);
731
732    if( trace( 0 , cxy , lid ) )
733    {
734        printf("  error: core[%x,%d] not found\n", cxy, lid );
735    }
736
[457]737    // release semaphore to get next command
738    sem_post( &semaphore );
739
740}  // end cmd_untrace()
741
742///////////////////////////////////////////////////////////////////////////////////
[407]743// Array of commands
[457]744///////////////////////////////////////////////////////////////////////////////////
[230]745
[407]746ksh_cmd_t cmd[] =
[230]747{
[435]748        { "cat",     "display file content",                            cmd_cat     },
749        { "cd",      "change current directory",                        cmd_cd      },
750        { "cp",      "replicate a file in file system",                 cmd_cp      },
751    { "fg",      "put a process in foreground",                     cmd_fg      },
752    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
753        { "load",    "load an user application",                        cmd_load    },
754        { "help",    "list available commands",                         cmd_help    },
[457]755        { "kill",    "kill a process (all threads)",                    cmd_kill    },
[435]756        { "log",     "list registered commands",                        cmd_log     },
757        { "ls",      "list directory entries",                          cmd_ls      },
758        { "mkdir",   "create a new directory",                          cmd_mkdir   },
759        { "mv",      "move a file in file system",                      cmd_mv      },
760        { "pwd",     "print current working directory",                 cmd_pwd     },
761        { "rm",      "remove a file from file system",                  cmd_rm      },
762        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[442]763        { "trace",   "activate trace for a given core",                 cmd_trace   },
764        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]765        { NULL,      NULL,                                                                              NULL        }
[230]766};
767
[407]768////////////////////////////////////////////////////////////////////////////////////
[457]769// This function analyses one command (with arguments), executes it, and returns.
[407]770////////////////////////////////////////////////////////////////////////////////////
[469]771static void __attribute__ ((noinline)) parse( char * buf )
[230]772{
773        int argc = 0;
774        char *argv[MAX_ARGS];
775        int i;
776        int len = strlen(buf);
777
778        // build argc/argv
[407]779        for (i = 0; i < len; i++) 
780    {
781                if (buf[i] == ' ') 
782        {
[230]783                        buf[i] = '\0';
[407]784                }
785        else if (i == 0 || buf[i - 1] == '\0') 
786        {
787                        if (argc < MAX_ARGS) 
788            {
[230]789                                argv[argc] = &buf[i];
790                                argc++;
791                        }
792                }
793        }
794
[469]795    // analyse command type
[407]796        if (argc > 0)
797    {
[230]798                int found = 0;
799
800                argv[argc] = NULL;
801
[407]802                // try to match typed command
[469]803                for (i = 0 ; cmd[i].name ; i++)
[407]804        {
805                        if (strcmp(argv[0], cmd[i].name) == 0)
806            {
[230]807                                cmd[i].fn(argc, argv);
808                                found = 1;
809                                break;
810                        }
811                }
812
[457]813                if (!found)  // undefined command
[407]814        {
[457]815                        printf("  error : undefined command <%s>\n", argv[0]);
816
817            // release semaphore to get next command
818            sem_post( &semaphore );
[230]819                }
820        }
[446]821}  // end parse()
[230]822
[446]823/////////////////////////
824static void interactive()
[230]825{
[469]826        char           c;                                               // read character
827        char           buf[CMD_MAX_SIZE];               // buffer for one command
828    unsigned int   end_command;             // last character found in a command
829        unsigned int   count;                   // pointer in command buffer
830        unsigned int   i;                                               // index for loops
831        unsigned int   state;                   // escape sequence state
[230]832
[469]833/* This can be used to remove interactive mode
[457]834
[469]835for( i=1 ; 1 ; i += 2)
836{
837    if( sem_wait( &semaphore ) )
838    {
839        printf("\n[ksh error] cannot found semafore\n" );
840        exit( 1 );
841    }
842    else
843    {
844        printf("\n[ksh] %d for sort\n", i );
845    }
846    strcpy( buf , "load /bin/user/sort.elf" );
847    parse( buf );
848
849    if( sem_wait( &semaphore ) )
850    {
851        printf("\n[ksh error] cannot found semafore\n" );
852        exit( 1 );
853    }
854    else
855    {
856        printf("\n[ksh] %d for fft\n", i+1 );
857    }
858    strcpy( buf , "load /bin/user/fft.elf" );
859    parse( buf );
860}
861
862*/
863
[407]864        enum fsm_states
865    {
[457]866                NORMAL = 0,
867                ESCAPE = 1,
868                BRAKET = 2,
[230]869        };
870
[457]871        // This lexical analyser writes one command line in the command buffer.
872        // It is implemented as a 3 states FSM to handle the following escape sequences:
[230]873        // - ESC [ A : up arrow
874        // - ESC [ B : down arrow
875        // - ESC [ C : right arrow
876        // - ESC [ D : left arrow
[407]877        // The three states have the following semantic:
[230]878        // - NORMAL : no (ESC) character has been found
879        // - ESCAPE : the character (ESC) has been found
880        // - BRAKET : the wo characters (ESC,[) have been found
[436]881
[457]882    // external loop on the commands
883    // the in teractive thread should not exit this loop
[230]884        while (1)
885        {
[457]886            // initialize command buffer
887            memset( buf, 0x20 , sizeof(buf) );   // TODO useful ?
888            count = 0;
889            state = NORMAL;
[230]890
[469]891        // decrement semaphore, and block if the KSH process is not the TXT owner
892        if ( sem_wait( &semaphore ) )
893        {
894            printf("\n[ksh error] cannot found semafore\n" );
895            exit( 1 );
896        }
[407]897
[457]898        // display prompt on a new line
899        printf("\n[ksh] ");
900 
901        end_command = 0;
902
903        // internal loop on characters in one command
904        while( end_command == 0 )
905        {
906            // get one character from TXT_RX
907                c = (char)getchar();
908
909            if( c == 0 ) continue;
910
911                    if( state == NORMAL )  // we are not in an escape sequence
912                    {
[230]913                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
914                                {
[457]915                                    if (count > 0)
916                    {
917                                        printf("\b \b");
918                                        count--;
919                                    }
[230]920                                }
[457]921                                else if (c == '\n')                  // new line => end of command
[230]922                                {
[457]923                                    if (count > 0)               // analyse & execute command
924                                    {
925                                            // complete command with NUL character
926                                            buf[count] = 0;
927                        count++;
[230]928
[457]929                                        // register command in log arrays
930                                            strcpy(log_entries[ptw].buf, buf);
931                                            log_entries[ptw].count = count;
932                                            ptw = (ptw + 1) % LOG_DEPTH;
933                                            ptr = ptw;
[230]934
[457]935                        // echo character
936                        putchar( c );
[230]937
[457]938                                            // call parser to analyse and execute command
939                                            parse( buf );
940                                    }
941                    else                         // no command registered
[441]942                    {
[457]943                        // release semaphore to get next command
944                        sem_post( &semaphore );
[441]945                    }
[457]946
947                    // exit internal loop on characters
948                    end_command = 1;
949                }
950                            else if (c == '\t')             // tabulation => do nothing
951                                {
952                            }
953                            else if (c == (char)0x1B)       // ESC => start an escape sequence
954                            {
955                    state = ESCAPE;
956                            }
957                            else                                               // normal character
[230]958                                {
[457]959                                    if (count < sizeof(buf) - 1)
960                                    {
961                        // register character in command buffer
962                                            buf[count] = c;
963                                            count++;
964
965                        // echo character
966                        putchar( c );
[230]967                                        }
968                                }
969                        }
[457]970                        else if( state == ESCAPE ) 
[230]971                        {
972                                if (c == '[')           //  valid sequence => continue
973                                {
974                                        state = BRAKET;
975                                }
976                                else                               // invalid sequence => do nothing
977                                {
978                                        state = NORMAL;
979                                }
980                        }
[457]981                        else if( state == BRAKET )
[230]982                        {
983                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
984                                {
985                                        if (count > 0)
986                                        {
987                                                printf("\b");
988                                                count--;
989                                        }
990
991                                        // get next user char
992                                        state = NORMAL;
993                                }
994                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
995                                {
996                                        if (count < sizeof(buf) - 1)
997                                        {
998                                                printf("%c", buf[count]);
999                                                count++;
1000                                        }
1001
1002                                        // get next user char
1003                                        state = NORMAL;
1004                                }
1005                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1006                                {
1007                                        // cancel current command
1008                                        for (i = 0; i < count; i++) printf("\b \b");
1009                                        count = 0;
1010
1011                                        // copy log command into buf
1012                                        ptr = (ptr - 1) % LOG_DEPTH;
1013                                        strcpy(buf, log_entries[ptr].buf);
[458]1014                                        count = log_entries[ptr].count - 1;
[230]1015
1016                                        // display log command
1017                                        printf("%s", buf);
1018
1019                                        // get next user char
1020                                        state = NORMAL;
1021                                }
1022                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1023                                {
1024                                        // cancel current command
1025                                        for (i = 0 ; i < count; i++) printf("\b \b");
1026                                        count = 0;
1027
1028                                        // copy log command into buf
1029                                        ptr = (ptr + 1) % LOG_DEPTH;
1030                                        strcpy(buf, log_entries[ptr].buf);
1031                                        count = log_entries[ptr].count;
1032
1033                                        // display log command
1034                                        printf("%s", buf);
1035
1036                                        // get next user char
1037                                        state = NORMAL;
1038                                }
1039                                else                               // other character => do nothing
1040                                {
1041                                        // get next user char
1042                                        state = NORMAL;
1043                                }
1044                        }
[457]1045                }  // end internal while loop on characters
1046        }  // end external while loop on commands
[446]1047}  // end interactive()
1048
[473]1049//////////
1050int main()
[446]1051{
1052    unsigned int cxy;             // owner cluster identifier for this KSH process
1053    unsigned int lid;             // core identifier for this KSH main thread
1054    int          status;          // child process termination status
[457]1055    int          child_pid;       // child process identifier
[469]1056    int          parent_pid;      // parent process identifier (i.e. this process)
1057    pthread_t    trdid;           // interactive thread identifier (unused)
[457]1058    unsigned int is_owner;        // non-zero if KSH process is TXT owner
[446]1059
1060    // initialize log buffer
1061        memset( &log_entries , 0, sizeof(log_entries));
1062        ptw   = 0;
1063        ptr   = 0;
1064
[457]1065    // get KSH process pid and core
1066    parent_pid = getpid();
[459]1067    get_core( &cxy , &lid );
[457]1068
1069    // initializes the semaphore used to unblock the interactive thread
[469]1070    if ( sem_init( &semaphore , 0 , 1 ) )
1071    {
1072        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1073        exit( 1 ); 
1074    }
[457]1075
[446]1076    // initialize interactive thread attributes
1077    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1078    attr.cxy        = cxy;
1079
1080    // lauch the interactive thread
1081    pthread_create( &trdid,
1082                    &attr,
1083                    &interactive,   // entry function
1084                    NULL ); 
1085   
1086    // enter infinite loop monitoring children processes termination
1087    while( 1 )
1088    {
[457]1089        // wait children termination
1090        child_pid = wait( &status );
[446]1091
[457]1092#if KSH_DEBUG
1093if( WIFEXITED  (status) ) printf("\n[KSH] child process %x exited\n" , child_pid );
1094if( WIFSIGNALED(status) ) printf("\n[KSH] child process %x killed\n" , child_pid );
1095if( WIFSTOPPED (status) ) printf("\n[KSH] child process %x stopped\n", child_pid );
[446]1096#endif
1097
[457]1098        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1099        is_fg( parent_pid , &is_owner );
1100        if( is_owner ) sem_post( &semaphore );
1101
[446]1102    }
[436]1103}  // end main()
[230]1104
[446]1105
Note: See TracBrowser for help on using the repository browser.