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

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

Introduce sigificant modifs in VFS to support the <ls> command,
and the . and .. directories entries.

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