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

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

1) Fix a bug in KSH : after the "load" command,

the [ksh] prompt is now printed after completion
of the loaded application.

2) Fix a bug in vmm_handle_cow() : the copy-on-write

use now a hal_remote_memcpy() to replicate the page content.


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