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

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

Introduce three new applications:

  • windows : to test the FBF windows kernel manager
  • udp_chat : chat application based on UDP sockets.
  • tcp_chat : chat application based on TCP sockets (including packet loss recovery).
File size: 43.2 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//
[636]8// This user process contains two POSIX threads:
[446]9// - the "main" thread contains the infinite loop implementing
[574]10//   the children processes termination monitoring, using the wait() syscall.
[469]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
[624]16// attached to the same TXT terminal as the parent KSH process.
[626]17// A child process can be launched in foreground or in background:
[624]18// . when the child process is launched in foreground, the KSH process loses
[469]19//   the TXT terminal ownership, that is transfered to the child process.
[624]20// . when the child process is launched in background, the KSH process keeps
[469]21//   the TXT terminal ownership.
22//
[619]23// We use a semaphore to synchronize the two KSH threads. After each command
24// completion, the interactive thread check the TXT ownership (with a sem_wait),
25// and blocks, if the KSH process loosed the TXT ownership (after a load,
26// or for any other cause). It is unblocked with the following policy:
[469]27// . if the command is "not a load", the semaphore is incremented by the
[619]28//   cmd_***() function when the command is completed, to get the next command
29//   in the while loop.   
[469]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>
[611]45#include <dirent.h>
[445]46#include <almosmkh.h>
[457]47#include <semaphore.h>
[588]48#include <hal_macros.h>
[596]49#include <sys/stat.h>
50#include <sys/mman.h>
51#include <fcntl.h>
[659]52#include <shared_syscalls.h>
[230]53
[682]54#define BUF_MAX_SIZE       (4096)   // max number of bytes for k <-> u data transfer
[659]55#define CMD_MAX_SIZE       (256)    // max number of characters in one command
56#define LOG_DEPTH          (32)     // max number of registered commands
57#define MAX_ARGS               (32)     // max number of arguments in a command
58#define PATH_MAX_SIZE      (256)    // max number of characters in a pathname
[230]59
[611]60#define DEBUG_MAIN          0
[625]61#define DEBUG_EXECUTE       0
[624]62#define DEBUG_CMD_CAT       0
[611]63#define DEBUG_CMD_CP        0
[652]64#define DEBUG_CMD_LOAD      0
[611]65#define DEBUG_CMD_LS        0
[619]66#define DEBUG_CMD_PS        0
[457]67
[469]68//////////////////////////////////////////////////////////////////////////////////////////
[407]69//         Structures
[469]70//////////////////////////////////////////////////////////////////////////////////////////
[230]71
[407]72// one entry in the registered commands array
73typedef struct log_entry_s
74{
75        char          buf[CMD_MAX_SIZE];
76        unsigned int  count;
77}
78log_entry_t;
[230]79
[407]80// one entry in the supported command types array
81typedef struct ksh_cmd_s
82{
83        char * name;
84        char * desc;
85        void   (*fn)( int , char ** );
86}
87ksh_cmd_t;
88
89
[469]90//////////////////////////////////////////////////////////////////////////////////////////
[230]91//         Global Variables
[469]92//////////////////////////////////////////////////////////////////////////////////////////
[230]93
[625]94ksh_cmd_t       command[];                  // array of supported commands
[230]95
[625]96log_entry_t     log_entries[LOG_DEPTH];     // array of registered commands
[230]97
[625]98unsigned int    ptw;                        // write pointer in log_entries[]
99unsigned int    ptr;                        // read pointer in log_entries[]
[230]100
[625]101pthread_attr_t  attr;                       // interactive thread attributes
[446]102
[625]103sem_t           semaphore;                  // block interactive thread when zero
[457]104
[625]105pthread_t       trdid;                      // interactive thread identifier
106
[676]107char            cmd[CMD_MAX_SIZE];                  // buffer for one command
108
109char            elf_path[PATH_MAX_SIZE];    // pathname for cmd_load command
110
[625]111char            pathname[PATH_MAX_SIZE];    // pathname for a file
112
[676]113char            pathnew[PATH_MAX_SIZE];     // used by the cmd_rename command
[619]114 
[676]115char            string[256];                // used by snprintf() for debug
[635]116
[469]117//////////////////////////////////////////////////////////////////////////////////////////
[230]118//         Shell  Commands
[469]119//////////////////////////////////////////////////////////////////////////////////////////
[230]120
[407]121/////////////////////////////////////////////
122static void cmd_cat( int argc , char **argv )
[230]123{
[611]124    struct stat    st;
[596]125    int            fd;
126    int            size;
127    char         * buf;
[230]128
[619]129#if DEBUG_CMD_CAT
[676]130printf("\n[ksh] %s enters" , __FUNCTION__);
[619]131#endif
132
[407]133        if (argc != 2) 
134    {
[409]135                printf("  usage: cat pathname\n");
[623]136
137        sem_post( &semaphore );
138            return;
[596]139    }
[407]140
[625]141    strcpy( pathname , argv[1] );
[230]142
[635]143#if DEBUG_CMD_CAT
[676]144printf("\n[ksh] %s : after strcpy" , __FUNCTION__ );
[635]145#endif
146
[596]147    // open the file
[625]148    fd = open( pathname , O_RDONLY , 0 );
[596]149    if (fd < 0) 
150    {
[625]151            printf("  error: cannot open file <%s>\n", pathname );
[623]152
153        sem_post( &semaphore );
154            return;
[596]155    }
[407]156
[611]157#if DEBUG_CMD_CAT
[676]158printf("\n[ksh] %s : file %s open", __FUNCTION__, pathname );
[596]159#endif
160
161    // get file stats
[625]162    if ( stat( pathname , &st ) == -1)
[407]163    {
[625]164            printf("  error: cannot stat <%s>\n", pathname );
[623]165
166            close(fd);
167        sem_post( &semaphore );
168            return;
[596]169    }
[230]170
[596]171        if ( S_ISDIR(st.st_mode) )
[407]172    {
[625]173            printf("  error: <%s> is a directory\n", pathname );
[623]174
175            close(fd);
176        sem_post( &semaphore );
177            return;
[596]178    }
[230]179
[596]180    // get file size
181    size = st.st_size;
[230]182
[611]183#if DEBUG_CMD_CAT
[676]184printf("\n[ksh] %s : size = %d", __FUNCTION__, size );
[596]185#endif
[230]186
[623]187    if( size == 0 )
188    {
[625]189            printf("  error: size = 0 for <%s>\n", pathname );
[623]190
191            close(fd);
192        sem_post( &semaphore );
193            return;
194    }
195
196    // mapping type is MAP_FILE when MAP_ANON and MAP_REMOTE are not specified
[596]197    buf = mmap( NULL , size , PROT_READ|PROT_WRITE , MAP_PRIVATE , fd , 0 );
[230]198
[596]199    if ( buf == NULL )
200    {
[625]201            printf("  error: cannot map file <%s>\n", pathname );
[623]202
203            close(fd);
204        sem_post( &semaphore );
205            return;
[596]206    }
207
[611]208#if DEBUG_CMD_CAT
[676]209printf("\n[ksh] %s : mapped file %d to buffer %x", __FUNCTION__, fd , buf );
[596]210#endif
211
212    // display the file content on TXT terminal
213    write( 1 , buf , size );
214
[641]215    // unmap the file
[623]216    if( munmap( buf , size ) )
217    {
[625]218            printf("  error: cannot unmap file <%s>\n", pathname );
[623]219    }
[596]220
[623]221#if DEBUG_CMD_CAT
[676]222printf("\n[ksh] %s : unmapped file %d from buffer %x", __FUNCTION__, fd , buf );
[623]223#endif
[596]224
[623]225    // close the file
226        if( close( fd ) )
227    {
[625]228            printf("  error: cannot close file <%s>\n", pathname );
[623]229    }
[596]230
[457]231    // release semaphore to get next command
232    sem_post( &semaphore );
233
[407]234}   // end cmd_cat()
235
236////////////////////////////////////////////
237static void cmd_cd( int argc , char **argv )
238{
239        if (argc != 2)
240    {
[409]241                printf("  usage: cd pathname\n");
[407]242        }
[596]243    else
244    {
[625]245            strcpy( pathname , argv[1] );
[407]246
[610]247        // call the relevant syscall
[625]248        if( chdir( pathname ) )
[610]249        {
[625]250            printf("  error: cannot found <%s> directory\n", pathname );
[610]251        }
[596]252    }
[407]253
[457]254    // release semaphore to get next command
255    sem_post( &semaphore );
[407]256
257}   // end cmd_cd()
258
259/////////////////////////////////////////
[230]260static void cmd_cp(int argc, char **argv)
261{
[611]262        int          src_fd;
263    int          dst_fd;
264        int          size;          // source file size
265        int          bytes;         // number of transfered bytes
266        char         buf[4096];
267        struct stat  st;
[230]268
[619]269#if DEBUG_CMD_CP
[676]270printf("\n[ksh] enter %s" , __FUNCTION__);
[619]271#endif
272
[407]273        if (argc != 3) 
274    {
[596]275        src_fd = -1;
276        dst_fd = -1;
[409]277                printf("  usage: cp src_pathname dst_pathname\n");
[611]278        goto cmd_cp_exit;
[230]279        }
280
[596]281    // open the src file
[625]282    strcpy( pathname , argv[1] );
283    src_fd = open( pathname , O_RDONLY , 0 );
[230]284
[596]285    if ( src_fd < 0 ) 
286    {
287        dst_fd = -1;
[625]288            printf("  error: cannot open <%s>\n", argv[1] );
[611]289            goto cmd_cp_exit;
[596]290    }
[230]291
[611]292#if DEBUG_CMD_CP
[676]293printf("\n[ksh] %s : file %s open", __FUNCTION__, argv[1] );
[610]294#endif
295
[596]296    // get file stats
[625]297    if ( stat( pathname , &st ) )
[596]298    {
299        dst_fd = -1;
[625]300            printf("  error: cannot stat <%s>\n", argv[1] );
[611]301            goto cmd_cp_exit;
[596]302    }
303
[611]304#if DEBUG_CMD_CP
[676]305printf("\n[ksh] %s : got stats for %s", __FUNCTION__, argv[1] );
[610]306#endif
307
[596]308        if ( S_ISDIR(st.st_mode) )
309    {
310        dst_fd = -1;
[625]311                printf("  error: <%s> is a directory\n", argv[1] );
[611]312                goto cmd_cp_exit;
[230]313        }
[596]314
315    // get src file size
[230]316        size = st.st_size;
317
[407]318        // open the dst file
[625]319    strcpy( pathname , argv[2] );
320        dst_fd = open( pathname , O_CREAT|O_TRUNC|O_RDWR , 0 );
[596]321
322        if ( dst_fd < 0 ) 
323    {
[625]324                printf("  error: cannot open <%s>\n", argv[2] );
[611]325                goto cmd_cp_exit;
[230]326        }
[596]327
[611]328#if DEBUG_CMD_CP
[676]329printf("\n[ksh] %s : file %s open", __FUNCTION__, argv[2] );
[610]330#endif
331
[625]332        if ( stat( pathname , &st ) )
[596]333    {
[625]334                printf("  error: cannot stat <%s>\n", argv[2] );
[611]335                goto cmd_cp_exit;
[230]336        }
[596]337
[611]338#if DEBUG_CMD_CP
[676]339printf("\n[ksh] %s : got stats for %s", __FUNCTION__, argv[2] );
[610]340#endif
341
[596]342        if ( S_ISDIR(st.st_mode ) ) 
343    {
[625]344                printf("  error: <%s> is a directory\n", argv[2] );
[611]345                goto cmd_cp_exit;
[230]346        }
347
[596]348        bytes = 0;
349
350        while (bytes < size)
[230]351        {
[608]352                int len = ((size - bytes) < 4096) ? (size - bytes) : 4096;
[230]353
[407]354                // read the source
[608]355                if ( read( src_fd , buf , len ) != len )
[596]356        {
[625]357                        printf("  error: cannot read from file <%s>\n", argv[1] );
[611]358                        goto cmd_cp_exit;
[230]359                }
360
[611]361#if DEBUG_CMD_CP
[676]362printf("\n[ksh] %s : read %d bytes from %s", __FUNCTION__, len, argv[1] );
[610]363#endif
364
[407]365                // write to the destination
[608]366                if ( write( dst_fd , buf , len ) != len )
[596]367        {
[625]368                        printf("  error: cannot write to file <%s>\n", argv[2] );
[611]369                        goto cmd_cp_exit;
[230]370                }
371
[611]372#if DEBUG_CMD_CP
[676]373printf("\n[ksh] %s : write %d bytes to %s", __FUNCTION__, len, argv[2] );
[610]374#endif
375
[608]376                bytes += len;
[230]377        }
378
[611]379cmd_cp_exit:
[596]380
[407]381        if (src_fd >= 0) close(src_fd);
382        if (dst_fd >= 0) close(dst_fd);
[230]383
[457]384    // release semaphore to get next command
385    sem_post( &semaphore );
386
[407]387}   // end cmd_cp()
388
[436]389/////////////////////////////////////////////////
390static void cmd_display( int argc , char **argv )
391{
[596]392    if( argc < 2 )
[436]393    {
[640]394        printf("  usage: display  vmm      cxy      pid      mapping\n"
[626]395               "         display  sched    cxy      lid\n"             
[611]396               "         display  process  cxy\n"             
397               "         display  txt      txtid\n"             
398               "         display  vfs\n"             
399               "         display  chdev\n"             
400               "         display  dqdt\n"             
[626]401               "         display  locks    pid      trdid\n"
[623]402               "         display  barrier  pid\n"
[626]403               "         display  mapper   path     page     nbytes\n"
[657]404               "         display  fat      min      nslots\n"
[659]405               "         display  fat      cxy      0\n"
[676]406               "         display  socket   pid      fdid\n" 
407               "         display  fd       pid\n"
408               "         display  fbf      pid\n" );
[596]409    }
410    ////////////////////////////////////
411    else if( strcmp( argv[1] , "vmm" ) == 0 )
412    {
[640]413        if( argc != 5 )
[436]414        {
[640]415                    printf("  usage: display vmm cxy pid mapping\n");
[436]416            }
[596]417        else
418        {
419                unsigned int cxy = atoi(argv[2]);
420                unsigned int pid = atoi(argv[3]);
[640]421                unsigned int map = atoi(argv[4]);
[436]422
[640]423            if( display_vmm( cxy , pid , map ) )
[596]424            {
425                printf("  error: no process %x in cluster %x\n", pid , cxy );
426            }
[436]427        }
428    }
[596]429    ///////////////////////////////////////////
[436]430    else if( strcmp( argv[1] , "sched" ) == 0 )
431    {
432        if( argc != 4 )
433        {
434                    printf("  usage: display sched cxy lid\n");
435            }
[596]436        else
437        {
438                unsigned int cxy = atoi(argv[2]);
439                unsigned int lid = atoi(argv[3]);
[436]440
[596]441            if( display_sched( cxy , lid ) )
442            {
443                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
444            }
[436]445        }
446    }
[596]447    /////////////////////////////////////////////
[436]448    else if( strcmp( argv[1] , "process" ) == 0 )
449    {
450        if( argc != 3 )
451        {
452                    printf("  usage: display process cxy\n");
453            }
[596]454        else
455        {
456                unsigned int cxy = atoi(argv[2]);
[436]457
[596]458            if( display_cluster_processes( cxy , 0 ) )
459            {
460                printf("  error: illegal argument cxy = %x\n", cxy );
461            }
[436]462        }
463    }
[596]464    /////////////////////////////////////////
[436]465    else if( strcmp( argv[1] , "txt" ) == 0 )
466    {
467        if( argc != 3 )
468        {
469                    printf("  usage: display txt txt_id\n");
470            }
[596]471        else
472        {
473                unsigned int txtid = atoi(argv[2]);
[436]474
[596]475            if( display_txt_processes( txtid ) )
476            {
477                printf("  error: illegal argument txtid = %d\n", txtid );
478            }
[436]479        }
480    }
[596]481    /////////////////////////////////////////
[436]482    else if( strcmp( argv[1] , "vfs" ) == 0 )
483    {
484        if( argc != 2 )
485        {
486                    printf("  usage: display vfs\n");
487            }
[596]488        else
489        {
490            display_vfs();
491        }
[436]492    }
[596]493    //////////////////////////////////////////
[436]494    else if( strcmp( argv[1] , "chdev" ) == 0 )
495    {
496        if( argc != 2 )
497        {
498                    printf("  usage: display chdev\n");
499            }
[596]500        else
501        {
502            display_chdev();
503        }
[436]504    }
[596]505    //////////////////////////////////////////
[445]506    else if( strcmp( argv[1] , "dqdt" ) == 0 )
507    {
508        if( argc != 2 )
509        {
510                    printf("  usage: display dqdt\n");
511            }
[596]512        else
513        {
514            display_dqdt();
515        }
516    }
517    ///////////////////////////////////////////
518    else if( strcmp( argv[1] , "locks" ) == 0 )
519    {
520        if( argc != 4 )
521        {
522                    printf("  usage: display locks pid trdid\n");
523            }
524        else
525        {
526                unsigned int pid   = atoi(argv[2]);
527            unsigned int trdid = atoi(argv[3]);
[445]528
[596]529            if( display_busylocks( pid , trdid ) )
530            {
531                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
532            }
533        }
[445]534    }
[623]535    /////////////////////////////////////////////////
536    else if( strcmp( argv[1] , "barrier" ) == 0 )
537    {
538        if( argc != 3 )
539        {
540                    printf("  usage: display barrier pid\n");
541            }
542        else
543        {
544                unsigned int pid   = atoi(argv[2]);
545
546            if( display_barrier( pid ) )
547            {
548                printf("  error: illegal arguments pid = %x\n", pid );
549            }
550        }
551    }
[611]552    ///////////////////////////////////////////
553    else if( strcmp( argv[1] , "mapper" ) == 0 )
554    {
555        if( argc != 5 )
556        {
557                    printf("  usage: display mapper path page_id nbytes\n");
558            }
559        else
560        {
561                unsigned int page_id   = atoi(argv[3]);
562            unsigned int nbytes    = atoi(argv[4]);
563
564            if( display_mapper( argv[2] , page_id, nbytes ) )
565            {
566                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
567            }
568        }
569    }
[676]570    /////////////////////////////////////////
[626]571    else if( strcmp( argv[1] , "fat" ) == 0 )
572    {
573        if( argc != 4 )
574        {
[657]575                    printf("  usage: display fat  min_slot  nb_slots\n");
[626]576            }
577        else
578        {
[657]579                unsigned int min_slot = atoi(argv[2]);
580            unsigned int nb_slots = atoi(argv[3]);
[626]581
[657]582            if( display_fat( min_slot, nb_slots ) )
[626]583            {
[657]584                printf("  error: cannot display fat\n");
[626]585            }
586        }
587    }
[676]588    ////////////////////////////////////////////
[659]589    else if( strcmp( argv[1] , "socket" ) == 0 )
590    {
591        if( argc != 4 )
592        {
593                    printf("  usage: display socket pid fdid\n");
594            }
595        else
596        {
597                unsigned int pid   = atoi(argv[2]);
598            unsigned int fdid = atoi(argv[3]);
599
600            if( display_socket( pid , fdid ) )
601            {
602                printf("  error: cannot found socket[%x,%d]\n", pid, fdid );
603            }
604        }
605    }
[676]606    ////////////////////////////////////////
607    else if( strcmp( argv[1] , "fd" ) == 0 ) 
608    {
609        if( argc != 3 )
610        {
611                    printf("  usage: display fd pid\n");
612            }
613        else
614        {
615            unsigned int pid = atoi(argv[2]);
616           
617            if( display_fd_array( pid ) )
618            {
619                printf("  error: cannot found process %x\n", pid );
620            }
621        }
622    }
623    ////////////////////////////////////////
624    else if( strcmp( argv[1] , "fbf" ) == 0 ) 
625    {
626        if( argc != 3 )
627        {
628                    printf("  usage: display fbf pid\n"
629                   "         display fbf 0 (all processes)");
630            }
631        else
632        {
633            unsigned int pid = atoi(argv[2]);
634           
635            if( display_fbf_windows( pid ) )
636            {
637                printf("  error: cannot found process %x\n", pid );
638            }
639        }
640    }
[659]641    ////
[436]642    else
643    {
[596]644        printf("  error: undefined display request : %s\n", argv[1] ); 
645    }       
[457]646
647    // release semaphore to get next command
648    sem_post( &semaphore );
649
[436]650} // end cmd_display()
651
[427]652/////////////////////////////////////////
653static void cmd_fg(int argc, char **argv)
654{
655        unsigned int pid;
656
657        if (argc != 2) 
658    {
[676]659                printf("  usage: fg pid\n");
[427]660        }
[596]661    else
[427]662    {
[596]663        pid = atoi( argv[1] );   
[427]664
[596]665        if( pid == 0 )
666        { 
667                    printf("  error: PID cannot be 0\n" );
668            }
669        else if( fg( pid ) )
670        {
671                    printf("  error: cannot find process %x\n", pid );
672            }
673    }
[457]674
675    // release semaphore to get next command
676    sem_post( &semaphore );
677
[436]678}  // end cmd_fg()
[427]679
[407]680//////////////////////////////////////////////
681static void cmd_help( int argc , char **argv )
[230]682{
[407]683        unsigned int i;
[230]684
[676]685        if( (argc != 1) || (argv[0] == NULL) ) 
[407]686    {
[676]687                printf("  usage: help\n");
[230]688        }
[596]689    else
[407]690    {
[619]691        printf("available commands:\n");
692            for (i = 0 ; command[i].name ; i++) 
[596]693        {
[619]694                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
[596]695            }
696    }
[457]697
698    // release semaphore to get next command
699    sem_post( &semaphore );
700
[407]701}   // end cmd_help()
[230]702
[676]703/////////////////////////////////////////////////
704static void cmd_history( int argc , char **argv )
705{
706        unsigned int i;
707
708        if( (argc != 1) || (argv[0] == NULL) ) 
709    {
710                printf("  usage: history\n"); 
711        }
712    else
713    {
714            printf("--- registered commands ---\n");
715            for (i = 0; i < LOG_DEPTH; i++) 
716        {
717                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
718            }
719    }
720
721    // release semaphore to get next command
722    sem_post( &semaphore );
723
724} // end cmd_history()
725
[407]726//////////////////////////////////////////////
727static void cmd_kill( int argc , char **argv )
[230]728{
[407]729        unsigned int pid;
[230]730
[407]731        if (argc != 2) 
732    {
[676]733                printf("  usage: kill pid\n", argv[0]);
[230]734        }
[596]735    else
736    {
737            pid = atoi( argv[1] );
[230]738
[596]739        if( pid == 0 )
740        {
741                    printf("  error: kernel process 0 cannot be killed\n" );
742            }
[230]743
[596]744            else if( kill( pid , SIGKILL ) )
745        {
746                    printf("  error: process %x cannot be killed\n", pid );
747            }
748    }
[427]749
[457]750    // release semaphore to get next command
751    sem_post( &semaphore );
752
[407]753}   // end cmd_kill()
[230]754
[407]755//////////////////////////////////////////////
756static void cmd_load( int argc , char **argv )
[230]757{
[436]758        int                  ret_fork;           // return value from fork
759        int                  ret_exec;           // return value from exec
[676]760    unsigned int         cmd_ok;             // command arguments acceptable
[436]761    unsigned int         background;         // background execution if non zero
[676]762    unsigned int         place;              // user placement if non zero
[682]763    char               * arg[5];             // array of pointers on process arguments
764    unsigned int         args_nr;            // number of arguments in this array
[407]765
[682]766    arg[4] = NULL;
[619]767
[676]768    // arguments analysis of argv[] array that contains at most 8 strings:
[682]769    // - the two first arguments ("cmd_load" & "elf_path") are mandatory
[676]770    // - the six next ("-pcxy","arg0","arg1","arg2","arg3","&") are optional
771
772     // analyse the optional arguments
773    if( argc == 2 )                            // no optional arguments
[407]774    {
[676]775        cmd_ok     = 1;
776        background = 0;
777        place      = 0;
[682]778        arg[0]     = NULL;
779        arg[1]     = NULL;
780        arg[2]     = NULL;
781        arg[3]     = NULL;
[676]782        args_nr    = 0;
783    }
784    else if( ((argc >= 4) && (argc <= 8)) &&
785             (argv[2][0] == '-') && (argv[2][1] == 'p') &&           
786             (strcmp(argv[argc-1] , "&" ) == 0) )     // background, place, 0 to 4 args
[596]787    {
[676]788        cmd_ok     = 1;
789        background = 1;
790        place      = 0xFF000000 | atoi( argv[2] + 2 );
[682]791        arg[0]     = (argc > 4) ? argv[3] : NULL;
792        arg[1]     = (argc > 5) ? argv[4] : NULL;
793        arg[2]     = (argc > 6) ? argv[5] : NULL;
794        arg[3]     = (argc > 7) ? argv[6] : NULL;
[676]795        args_nr    = argc - 4;
796    }
797    else if( ((argc >= 3) && (argc <= 7)) &&
798             (argv[2][0] == '-') && (argv[2][1] == 'p') && 
799             (strcmp(argv[argc-1] , "&" ) != 0) )     // place, no background, 0 to 4 args
800    {
801        cmd_ok     = 1;
802        background = 0;
803        place      = 0xFF000000 | atoi( argv[2] + 2 );
[682]804        arg[0]     = (argc > 3) ? argv[3] : NULL;
805        arg[1]     = (argc > 4) ? argv[4] : NULL;
806        arg[2]     = (argc > 5) ? argv[5] : NULL;
807        arg[3]     = (argc > 6) ? argv[6] : NULL;
[676]808        args_nr    = argc - 3;
809    }
810    else if( ((argc >=3) && (argc <= 7))  &&       
811             ((argv[2][0] != '-') || (argv[2][1] != 'p')) && 
812             (strcmp(argv[argc-1] , "&" ) == 0) )     // no place, background, 0 to 4 args
813    {
814        cmd_ok     = 1;
815        background = 1;
816        place      = 0;
[682]817        arg[0]     = (argc > 3) ? argv[2] : NULL;
818        arg[1]     = (argc > 4) ? argv[3] : NULL;
819        arg[2]     = (argc > 5) ? argv[4] : NULL;
820        arg[3]     = (argc > 6) ? argv[5] : NULL;
[676]821        args_nr    = argc - 3;
822    }
823    else if( (argc >= 3) && (argc <= 6 ) )     // no place, no background, 0 to 4 args
824    {
825        cmd_ok     = 1;
826        background = 0;
827        place      = 0;
[682]828        arg[0]     = (argc > 2) ? argv[2] : NULL;
829        arg[1]     = (argc > 3) ? argv[3] : NULL;
830        arg[2]     = (argc > 4) ? argv[4] : NULL;
831        arg[3]     = (argc > 5) ? argv[5] : NULL;
[676]832        args_nr    = argc - 2;
833    }
834    else                                    // illegal optional arguments
835    {
836        cmd_ok = 0;
837        background = 0;
838        place      = 0;
[682]839        arg[0]     = NULL;
840        arg[1]     = NULL;
841        arg[2]     = NULL;
842        arg[3]     = NULL;
[676]843        args_nr    = 0;
844    }
[407]845
[676]846    // check syntax errors
847    if( cmd_ok == 0 )
848    {
849        printf("  usage: load elf_path [-pcxy] [arg0] [arg1] [arg2] [arg3] [&]\n");
[427]850
[676]851        // release semaphore to get next command
852        sem_post( &semaphore );
[407]853
[676]854        return;
855    }
856
857    // get elf_path
858    strcpy( elf_path , argv[1] );
859
[611]860#if DEBUG_CMD_LOAD
[682]861if( place )
[676]862printf("\n[ksh] %s : path <%s> / place %x / args_nr %d / bg %d\n"
863"                 arg0 %s / arg1 %s / arg2 %s / arg3 %s\n",
[682]864__FUNCTION__, elf_path, place & 0xFFFF, args_nr, background, arg[0], arg[1], arg[2], arg[3] );
865
866else
867printf("\n[ksh] %s : path <%s> / args_nr %d / bg %d\n"
868"                 arg0 %s / arg1 %s / arg2 %s / arg3 %s\n",
869__FUNCTION__, elf_path, args_nr, background, arg[0], arg[1], arg[2], arg[3] );
[457]870#endif
871
[676]872    // set target cluster if required
873    if( place ) place_fork( place & 0xFFFF );
[434]874
[676]875    // KSH process fork CHILD process
876        ret_fork = fork();
[469]877
[676]878    if ( ret_fork < 0 )     // it is a failure reported to KSH
879    {
880        printf("  error: ksh process unable to fork\n");
881    }
882    else if (ret_fork == 0) // it is the CHILD process
883    {
884
[611]885#if DEBUG_CMD_LOAD
[676]886printf("\n[ksh] %s : child (pid %x) after fork, before exec\n",
887 __FUNCTION__ , getpid() );
[469]888#endif
889
[676]890        // CHILD process exec NEW process
891        ret_exec = execve( elf_path , arg , NULL );
[434]892
[611]893#if DEBUG_CMD_LOAD
[676]894printf("\n[ksh] %s : child (pid %x) after exec / ret_exec %x\n",
895 __FUNCTION__, getpid(), ret_exec );
[469]896#endif
897
[676]898        // this is only executed in case of exec failure
899        if( ret_exec )
[409]900        {
[682]901            printf("  error: child process unable to exec <%s>\n", elf_path );
[676]902            exit( 0 );
903        }   
904        } 
905    else                    // it is the KSH process : ret_fork is the new process PID
906    {
[436]907
[611]908#if DEBUG_CMD_LOAD
[676]909printf("\n[ksh] %s : ksh (pid %x) after fork / ret_fork %x\n",
910 __FUNCTION__, getpid(), ret_fork );
[457]911#endif
[676]912        // when the new process is launched in background, the KSH process
913        // takes the TXT ownership, and releases the semaphore to get the next command.
914        // Otherwise, the child process keep the TXT ownership, and the semaphore will
915        // be released by the KSH main thread when the child process exit
[457]916
[676]917        if( background )    //  KSH must keep TXT ownership
918        {
919            // KSH get back the TXT ownership
920            fg( getpid() );
[619]921
[676]922            // release semaphore to get next command
923            sem_post( &semaphore );
[457]924        }
[436]925    }
[407]926}   // end cmd_load
927
928////////////////////////////////////////////
929static void cmd_ls( int argc , char **argv )
[230]930{
[611]931    struct dirent  * entry;
932    DIR            * dir;
[230]933
[619]934#if DEBUG_CMD_LS
[676]935printf("\n[ksh] enter %s" , __FUNCTION__);
[619]936#endif
937
[612]938        if (argc > 2 )
[407]939    {
[596]940                printf("  usage: ls [path]\n");
[407]941        }
[596]942    else
[407]943    {
[612]944        // handle case with no argument
[230]945
[611]946        // get target directory path
[612]947        if ( argc == 1 ) strcpy( pathname , "." );
[625]948        else             strcpy( pathname , argv[1] );
[611]949
950        // open target directory
951            dir = opendir( pathname );
952
953#if DEBUG_CMD_LS
[682]954printf("\n[ksh] %s : directory <%s> open / DIR %x\n", __FUNCTION__, pathname , dir );
[611]955#endif
956
957        if( dir == NULL)
958            {
959                    printf("  error : directory <%s> not found\n", pathname );
[623]960
961            sem_post( &semaphore );
962            return;
[611]963            }
964
965        // loop on directory entries   
966        while ( (entry = readdir(dir)) != NULL )
967            {
[612]968                    printf("%s\n", entry->d_name);
[611]969            }
970
971        // close target directory
972            closedir( dir );
973
974#if DEBUG_CMD_LS
[676]975printf("\n[ksh] %s : directory <%s> closed", __FUNCTION__, pathname );
[611]976#endif
977
[596]978    }
[230]979
[457]980    // release semaphore to get next command
981    sem_post( &semaphore );
982
983} // end cmd_ls()
984
[407]985///////////////////////////////////////////////
986static void cmd_mkdir( int argc , char **argv )
[230]987{
[407]988        if (argc != 2)
989    {
[409]990                printf("  usage: mkdir pathname\n");
[230]991        }
[596]992    else
993    {
[625]994        strcpy( pathname , argv[1] );
[230]995
[610]996        mkdir( pathname , 0x777 );
[596]997    }
[230]998
[457]999    // release semaphore to get next command
1000    sem_post( &semaphore );
1001
1002} // end cmd_mkdir()
1003
[407]1004////////////////////////////////////////////
1005static void cmd_mv( int argc , char **argv )
[230]1006{
[610]1007        if (argc != 3) 
1008    {
1009                printf("  usage: mv old_pathname new_pathname\n");
[230]1010        }
[596]1011    else
1012    {
[625]1013        strcpy( pathname , argv[1] );
1014        strcpy( pathnew  , argv[2] );
[610]1015
1016        // call the relevant syscall
[625]1017        if( rename( pathname , pathnew ) )
[610]1018        {
[625]1019            printf("  error: unable to rename <%s> to <%s>\n", pathname , pathnew );
[610]1020        }
[596]1021    }
[610]1022
[457]1023    // release semaphore to get next command
1024    sem_post( &semaphore );
[407]1025
[457]1026}  // end cmd_mv
[230]1027
[588]1028
1029////////////////////////////////////////////
1030static void cmd_ps( int argc , char **argv )
1031{
1032    unsigned int x_size;
1033    unsigned int y_size;
1034    unsigned int x;
1035    unsigned int y;
[682]1036    unsigned int error;
[588]1037
[682]1038    char         u_buf[BUF_MAX_SIZE];
1039
[619]1040#if DEBUG_CMD_PS
[676]1041printf("\n[ksh] enter %s" , __FUNCTION__);
[619]1042#endif
1043
[676]1044        if( (argc != 1) || (argv[0] == NULL) ) 
[588]1045    {
[676]1046                printf("  usage: ps\n");
[588]1047        }
[596]1048    else
1049    {
1050        // get platform config
[659]1051        hard_config_t  config;
1052        get_config( &config );
1053        x_size = config.x_size;
1054        y_size = config.y_size;
[588]1055
[596]1056        // scan all clusters
1057        for( x = 0 ; x < x_size ; x++ )
[588]1058        {
[596]1059            for( y = 0 ; y < y_size ; y++ )
1060            {
[682]1061                int cxy = HAL_CXY_FROM_XY(x,y);
[619]1062
1063#if DEBUG_CMD_PS
[682]1064printf("\n[ksh] %s : call get_processes() in cluster %x", __FUNCTION__ , cxy );
[619]1065#endif
[682]1066                // write all owned processes in cxy to u_buf buffer
1067                // one single NUL terminated string / one line per process)
1068                error = get_processes( cxy,
1069                                       1,                      // owned only
1070                                       u_buf,
1071                                       BUF_MAX_SIZE ); 
1072                if( error )
1073                {
1074                   printf(" ... too much processes in cluster %x\n", cxy );
1075                }
[619]1076
[682]1077                // display processes owned by cluster cxy
1078                printf("%s" , u_buf ); 
[596]1079            }
[588]1080        }
1081    }
1082
1083    // release semaphore to get next command
1084    sem_post( &semaphore );
1085
1086}  // end cmd_ps()
1087
[407]1088/////////////////////////////////////////////
1089static void cmd_pwd( int argc , char **argv )
[230]1090{
[676]1091        if( (argc != 1) || (argv[0] == NULL) ) 
[407]1092    {
[676]1093                printf("  usage: pwd\n");
[407]1094        }
1095    else 
1096    {
[625]1097        if ( getcwd( pathname , PATH_MAX_SIZE ) ) 
[596]1098        {
1099                    printf("  error: unable to get current directory\n");
1100            }
1101        else 
1102        {
[625]1103                    printf("%s\n", pathname );
[596]1104            }
1105    }
[407]1106
[457]1107    // release semaphore to get next command
1108    sem_post( &semaphore );
1109
1110}  // end cmd_pwd()
1111
[407]1112////////////////////////////////////////////
1113static void cmd_rm( int argc , char **argv )
1114{
1115        if (argc != 2)
1116    {
[676]1117                printf("  usage: rm pathname\n");
[230]1118        }
[596]1119    else
1120    {
[625]1121            strcpy( pathname , argv[1] );
[230]1122
[608]1123        if ( unlink( pathname ) )
1124        {
[611]1125                    printf("  error: unable to remove <%s>\n", pathname );
[608]1126            }
[596]1127    }
[230]1128
[457]1129    // release semaphore to get next command
1130    sem_post( &semaphore );
[230]1131
[641]1132}  // end cmd_rm()
[457]1133
[407]1134///////////////////////////////////////////////
[641]1135static void cmd_stat( int argc , char **argv )
1136{
1137    struct stat    st;
1138    unsigned int   size;
1139
1140        if (argc != 2)
1141    {
[676]1142                printf("  usage: stat pathname\n");
[641]1143        }
1144    else
1145    {
1146            strcpy( pathname , argv[1] );
1147
1148        if ( stat( pathname , &st ) )
1149        {
1150                    printf("  error: cannot stat <%s>\n", argv[2] );
1151                }
1152        else
1153        {
1154            // get file size
1155            size = st.st_size;
1156
1157            // print file stat info
1158            printf("   <%s> : %d bytes\n", pathname, size );
1159        }
1160        }
1161
1162    // release semaphore to get next command
1163    sem_post( &semaphore );
1164
1165}  // end cmd_stat()
1166
1167///////////////////////////////////////////////
[407]1168static void cmd_rmdir( int argc , char **argv )
[230]1169{
[676]1170        if (argc != 2)
1171    {
1172                printf("  usage: rmdir pathname\n");
1173        }
1174    else
1175    {
1176            strcpy( pathname , argv[1] );
[230]1177
[676]1178        if ( unlink( pathname ) )
1179        {
1180                    printf("  error: unable to remove <%s>\n", pathname );
1181            }
1182    }
1183
1184    // release semaphore to get next command
1185    sem_post( &semaphore );
1186
1187}  // end cmd_rmdir()
1188
[442]1189///////////////////////////////////////////////
1190static void cmd_trace( int argc , char **argv )
1191{
1192    unsigned int cxy;
1193    unsigned int lid;
1194
1195        if (argc != 3)
1196    {
1197                printf("  usage: trace cxy lid \n");
1198        }
[596]1199    else
1200    {
1201        cxy = atoi(argv[1]);
1202        lid = atoi(argv[2]);
[442]1203
[596]1204        if( trace( 1 , cxy , lid ) )
1205        {
1206            printf("  error: core[%x,%d] not found\n", cxy, lid );
1207        }
[442]1208    }
1209
[457]1210    // release semaphore to get next command
1211    sem_post( &semaphore );
1212
1213}  // end cmd_trace
1214
[442]1215///////////////////////////////////////////////
1216static void cmd_untrace( int argc , char **argv )
1217{
1218    unsigned int cxy;
1219    unsigned int lid;
1220
1221        if (argc != 3)
1222    {
1223                printf("  usage: untrace cxy lid \n");
1224        }
[596]1225    else
1226    {
1227        cxy = atoi(argv[1]);
1228        lid = atoi(argv[2]);
[442]1229
[596]1230        if( trace( 0 , cxy , lid ) )
1231        {
1232            printf("  error: core[%x,%d] not found\n", cxy, lid );
1233        }
[442]1234    }
1235
[457]1236    // release semaphore to get next command
1237    sem_post( &semaphore );
1238
1239}  // end cmd_untrace()
1240
1241///////////////////////////////////////////////////////////////////////////////////
[407]1242// Array of commands
[457]1243///////////////////////////////////////////////////////////////////////////////////
[230]1244
[619]1245ksh_cmd_t command[] =
[230]1246{
[435]1247        { "cat",     "display file content",                            cmd_cat     },
1248        { "cd",      "change current directory",                        cmd_cd      },
1249        { "cp",      "replicate a file in file system",                 cmd_cp      },
1250    { "fg",      "put a process in foreground",                     cmd_fg      },
1251    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1252        { "load",    "load an user application",                        cmd_load    },
1253        { "help",    "list available commands",                         cmd_help    },
[676]1254        { "history", "list registered commands",                        cmd_history },
[457]1255        { "kill",    "kill a process (all threads)",                    cmd_kill    },
[435]1256        { "ls",      "list directory entries",                          cmd_ls      },
1257        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1258        { "mv",      "move a file in file system",                      cmd_mv      },
1259        { "pwd",     "print current working directory",                 cmd_pwd     },
[588]1260        { "ps",      "display all processes",                           cmd_ps      },
[435]1261        { "rm",      "remove a file from file system",                  cmd_rm      },
1262        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[641]1263        { "stat",    "print infos on a given file",                     cmd_stat    },
[442]1264        { "trace",   "activate trace for a given core",                 cmd_trace   },
1265        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]1266        { NULL,      NULL,                                                                              NULL        }
[230]1267};
1268
[407]1269////////////////////////////////////////////////////////////////////////////////////
[457]1270// This function analyses one command (with arguments), executes it, and returns.
[407]1271////////////////////////////////////////////////////////////////////////////////////
[625]1272static void __attribute__ ((noinline)) execute( char * buf )
[230]1273{
[619]1274        int    argc = 0;
1275        char * argv[MAX_ARGS];
1276        int    i;
1277        int    len = strlen(buf);
[230]1278
[625]1279#if DEBUG_EXECUTE
[676]1280printf("\n[ksh] enter %s for command <%s>" , __FUNCTION__ , buf );
[619]1281#endif
1282
[676]1283        // build argc/argv :
1284    // arg[0] is the command type
1285    // - other arg[i] are the command arguments
1286
[407]1287        for (i = 0; i < len; i++) 
1288    {
[619]1289        // convert SPACE to NUL
[407]1290                if (buf[i] == ' ') 
1291        {
[230]1292                        buf[i] = '\0';
[407]1293                }
1294        else if (i == 0 || buf[i - 1] == '\0') 
1295        {
1296                        if (argc < MAX_ARGS) 
1297            {
[230]1298                                argv[argc] = &buf[i];
1299                                argc++;
1300                        }
1301                }
1302        }
1303
[625]1304    // check command
1305        if (argc == 0)
1306    {
1307        // release semaphore to get next command
1308        sem_post( &semaphore );
1309    }
1310
1311#if DEBUG_EXECUTE
[676]1312printf("\n[ksh] in %s : argc = %d / type = %s", __FUNCTION__ , argc , argv[0] );
[619]1313#endif
1314
[682]1315    // scan the list of commands to match cmd_type (contained in argv[0]
[625]1316    int found = 0;
1317    for ( i = 0 ; (command[i].name != NULL) && (found == 0) ; i++ )
[407]1318    {
[625]1319        if (strcmp(argv[0], command[i].name) == 0)
[407]1320        {
[625]1321                        command[i].fn(argc, argv);
1322                        found = 1;
[230]1323                }
[625]1324    }
[230]1325
[625]1326    // check undefined command
1327        if (!found) 
1328    {   
[682]1329        printf("  error : undefined command type <%s>\n", argv[0]);
[457]1330
[625]1331        // release semaphore to get next command
1332        sem_post( &semaphore );
[230]1333        }
[625]1334}  // end execute()
[230]1335
[626]1336
1337
[574]1338///////////////////////////////
[503]1339static void interactive( void )
[230]1340{
[469]1341        char           c;                                               // read character
1342    unsigned int   end_command;             // last character found in a command
1343        unsigned int   count;                   // pointer in command buffer
1344        unsigned int   i;                                               // index for loops
1345        unsigned int   state;                   // escape sequence state
[230]1346
[457]1347
[682]1348//  direct command to help debug
[641]1349
[682]1350    if( getpid() == 0x2) 
[659]1351    {
1352        if( sem_wait( &semaphore ) )
1353        {
1354            printf("\n[ksh %d] error : cannot found semafore\n" );
1355            exit( 1 );
1356        }
1357        else
1358        {
[682]1359           strcpy( cmd , "load bin/user/tcp_chat.elf 1 0xbbbbbbbb 0xaaaaaaaa 0xcc" );
[659]1360            printf("[ksh] %s\n", cmd );
1361            execute( cmd );
1362        }
1363    }
[676]1364
[682]1365    if( getpid() == 0x3 )
[659]1366    {
1367        if( sem_wait( &semaphore ) )
1368        {
1369            printf("\n[ksh %d] error : cannot found semafore\n" );
1370            exit( 1 );
1371        }
1372        else
1373        {
[682]1374            strcpy( cmd , "load bin/user/tcp_chat.elf 0 0xaaaaaaaa 0xbbbbbbbb 0xcc" );
[659]1375            printf("[ksh] %s\n", cmd );
1376            execute( cmd );
1377        }
1378    }
[469]1379
[682]1380//
[625]1381
[407]1382        enum fsm_states
1383    {
[457]1384                NORMAL = 0,
1385                ESCAPE = 1,
1386                BRAKET = 2,
[230]1387        };
1388
[457]1389        // This lexical analyser writes one command line in the command buffer.
1390        // It is implemented as a 3 states FSM to handle the following escape sequences:
[230]1391        // - ESC [ A : up arrow
1392        // - ESC [ B : down arrow
1393        // - ESC [ C : right arrow
1394        // - ESC [ D : left arrow
[407]1395        // The three states have the following semantic:
[230]1396        // - NORMAL : no (ESC) character has been found
1397        // - ESCAPE : the character (ESC) has been found
1398        // - BRAKET : the wo characters (ESC,[) have been found
[436]1399
[619]1400    // take the semaphore for the first command
1401    if ( sem_wait( &semaphore ) )
1402    {
1403        printf("\n[ksh error] cannot found semafore\n" );
1404        exit( 1 );
1405    }
1406
1407    // display prompt for the first command
1408    printf("\n[ksh] ");
1409
1410    // external loop on the commands / the interactive thread do not exit this loop
[230]1411        while (1)
1412        {
[457]1413            // initialize command buffer
[619]1414            count       = 0;
1415            state       = NORMAL;
1416        end_command = 0;
[230]1417
[457]1418        // internal loop on characters in one command
1419        while( end_command == 0 )
1420        {
1421            // get one character from TXT_RX
1422                c = (char)getchar();
1423
1424            if( c == 0 ) continue;
1425
1426                    if( state == NORMAL )  // we are not in an escape sequence
1427                    {
[230]1428                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1429                                {
[457]1430                                    if (count > 0)
1431                    {
1432                                        printf("\b \b");
1433                                        count--;
1434                                    }
[230]1435                                }
[457]1436                                else if (c == '\n')                  // new line => end of command
[230]1437                                {
[457]1438                                    if (count > 0)               // analyse & execute command
1439                                    {
1440                                            // complete command with NUL character
[619]1441                                            cmd[count] = 0;
[457]1442                        count++;
[676]1443
[625]1444                        // register command in log_entries[] array
[619]1445                                            strncpy( log_entries[ptw].buf , cmd , count );
[457]1446                                            log_entries[ptw].count = count;
1447                                            ptw = (ptw + 1) % LOG_DEPTH;
1448                                            ptr = ptw;
[230]1449
[457]1450                        // echo character
1451                        putchar( c );
[230]1452
[625]1453                                            // execute command
1454                                            execute( cmd );
[457]1455                                    }
1456                    else                         // no command registered
[441]1457                    {
[457]1458                        // release semaphore to get next command
1459                        sem_post( &semaphore );
[441]1460                    }
[457]1461
1462                    // exit internal loop on characters
1463                    end_command = 1;
1464                }
1465                            else if (c == '\t')             // tabulation => do nothing
1466                                {
1467                            }
1468                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1469                            {
1470                    state = ESCAPE;
1471                            }
1472                            else                                               // normal character
[230]1473                                {
[619]1474                                    if (count < (sizeof(cmd) - 1) )
[457]1475                                    {
1476                        // register character in command buffer
[619]1477                                            cmd[count] = c;
[457]1478                                            count++;
1479
1480                        // echo character
1481                        putchar( c );
[230]1482                                        }
[619]1483                    else
1484                    {
1485                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1486                    }
[230]1487                                }
1488                        }
[457]1489                        else if( state == ESCAPE ) 
[230]1490                        {
1491                                if (c == '[')           //  valid sequence => continue
1492                                {
1493                                        state = BRAKET;
1494                                }
1495                                else                               // invalid sequence => do nothing
1496                                {
1497                                        state = NORMAL;
1498                                }
1499                        }
[457]1500                        else if( state == BRAKET )
[230]1501                        {
[619]1502                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
[230]1503                                {
1504                                        if (count > 0)
1505                                        {
1506                                                printf("\b");
1507                                                count--;
1508                                        }
1509
1510                                        // get next user char
1511                                        state = NORMAL;
1512                                }
[619]1513                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
[230]1514                                {
[619]1515                                        if (count < sizeof(cmd) - 1)
[230]1516                                        {
[619]1517                                                printf("%c", cmd[count]);
[230]1518                                                count++;
1519                                        }
1520
1521                                        // get next user char
1522                                        state = NORMAL;
1523                                }
1524                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1525                                {
1526                                        // cancel current command
1527                                        for (i = 0; i < count; i++) printf("\b \b");
1528                                        count = 0;
1529
[619]1530                                        // copy log command into cmd
[230]1531                                        ptr = (ptr - 1) % LOG_DEPTH;
[619]1532                                        strcpy(cmd, log_entries[ptr].buf);
[458]1533                                        count = log_entries[ptr].count - 1;
[230]1534
1535                                        // display log command
[619]1536                                        printf("%s", cmd);
[230]1537
1538                                        // get next user char
1539                                        state = NORMAL;
1540                                }
1541                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1542                                {
1543                                        // cancel current command
1544                                        for (i = 0 ; i < count; i++) printf("\b \b");
1545                                        count = 0;
1546
[619]1547                                        // copy log command into cmd
[230]1548                                        ptr = (ptr + 1) % LOG_DEPTH;
[619]1549                                        strcpy(cmd, log_entries[ptr].buf);
[230]1550                                        count = log_entries[ptr].count;
1551
1552                                        // display log command
[619]1553                                        printf("%s", cmd);
[230]1554
1555                                        // get next user char
1556                                        state = NORMAL;
1557                                }
1558                                else                               // other character => do nothing
1559                                {
1560                                        // get next user char
1561                                        state = NORMAL;
1562                                }
1563                        }
[457]1564                }  // end internal while loop on characters
[619]1565
1566        // block interactive thread if KSH loose TXT ownership
1567        if ( sem_wait( &semaphore ) )
1568        {
1569            printf("\n[ksh error] cannot found semafore\n" );
1570            exit( 1 );
1571        }
1572
1573        // display prompt for next command
1574        printf("\n[ksh] ");
1575
[457]1576        }  // end external while loop on commands
[619]1577
[446]1578}  // end interactive()
1579
[574]1580////////////////
[503]1581int main( void )
[446]1582{
1583    unsigned int cxy;             // owner cluster identifier for this KSH process
1584    unsigned int lid;             // core identifier for this KSH main thread
1585    int          status;          // child process termination status
[633]1586    int          parent_pid;      // parent process identifier (i.e. this process)
[457]1587    int          child_pid;       // child process identifier
1588    unsigned int is_owner;        // non-zero if KSH process is TXT owner
[446]1589
1590    // initialize log buffer
1591        memset( &log_entries , 0, sizeof(log_entries));
1592        ptw   = 0;
1593        ptr   = 0;
1594
[457]1595    // get KSH process pid and core
1596    parent_pid = getpid();
[637]1597    get_core_id( &cxy , &lid );
[457]1598
[611]1599#if DEBUG_MAIN
[676]1600printf("\n[ksh] main started on core[%x,%d]", cxy , lid ); 
[574]1601#endif
1602   
1603    // initializes the semaphore used to synchronize with interactive thread
[469]1604    if ( sem_init( &semaphore , 0 , 1 ) )
1605    {
1606        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1607        exit( 1 ); 
1608    }
[457]1609
[611]1610#if DEBUG_MAIN
[676]1611printf("\n[ksh] main initialized semaphore" ); 
[574]1612#endif
1613   
[446]1614    // initialize interactive thread attributes
1615    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1616    attr.cxy        = cxy;
1617
1618    // lauch the interactive thread
1619    pthread_create( &trdid,
1620                    &attr,
1621                    &interactive,   // entry function
1622                    NULL ); 
[611]1623#if DEBUG_MAIN
[676]1624printf("\n[ksh] main thread launched interactive thread %x", trdid ); 
[574]1625#endif
[588]1626
[682]1627    // enter infinite loop monitoring children  termination
[446]1628    while( 1 )
1629    {
[457]1630        // wait children termination
1631        child_pid = wait( &status );
[446]1632
[633]1633        if( DEBUG_MAIN )
1634        {
1635            if(WIFEXITED  (status)) printf("\n[ksh] child process %x exit\n"   ,child_pid);
1636            if(WIFSIGNALED(status)) printf("\n[ksh] child process %x killed\n" ,child_pid);
1637            if(WIFSTOPPED (status)) printf("\n[ksh] child process %x stopped\n",child_pid);
1638        }
[446]1639
[457]1640        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1641        is_fg( parent_pid , &is_owner );
1642        if( is_owner ) sem_post( &semaphore );
[446]1643    }
[436]1644}  // end main()
[230]1645
[446]1646
Note: See TracBrowser for help on using the repository browser.