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

Last change on this file since 610 was 610, checked in by alain, 5 years ago

Fix several bugs in VFS to support the following
ksh commandis : cp, mv, rm, mkdir, cd, pwd

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