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

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

Fix a big bug in ksh: wrong handling of illegal command, blocking ksh.

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