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

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

This version modifies the exec syscall and fixes a large number of small bugs.
The version number has been updated (0.1)

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