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

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

Introduce cat, rm, cp commands in ksh.

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