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

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

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

File size: 34.2 KB
Line 
1/////////////////////////////////////////////////////////////////////////////////////////
2// File   :  ksh.c
3// Date   :  October 2017
4// Author :  Alain Greiner
5/////////////////////////////////////////////////////////////////////////////////////////
6// This application implements a minimal shell for ALMOS-MKH.
7//
8// This user KSH process contains two POSIX threads:
9// - the "main" thread contains the infinite loop implementing
10//   the children processes termination monitoring, using the wait() syscall.
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.
14//
15// The children processes are created by the <load> command, and are
16// attached to the same TXT terminal as the KSH process itself.
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//
23// We use a semaphore to synchronize the two KSH threads. At each iteration,
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/////////////////////////////////////////////////////////////////////////////////////////
38
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/wait.h>
43#include <signal.h>
44#include <unistd.h>
45#include <dirent.h>
46#include <almosmkh.h>
47#include <semaphore.h>
48#include <hal_macros.h>
49#include <sys/stat.h>
50#include <sys/mman.h>
51#include <fcntl.h>
52
53#define CMD_MAX_SIZE   (256)    // max number of characters in one command
54#define LOG_DEPTH      (32)     // max number of registered commands
55#define MAX_ARGS           (32)     // max number of arguments in a command
56
57#define DEBUG_MAIN          0
58
59#define DEBUG_CMD_CAT       0
60#define DEBUG_CMD_CP        0
61#define DEBUG_CMD_LOAD      0
62#define DEBUG_CMD_LS        0
63
64//////////////////////////////////////////////////////////////////////////////////////////
65//         Structures
66//////////////////////////////////////////////////////////////////////////////////////////
67
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;
75
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
86//////////////////////////////////////////////////////////////////////////////////////////
87//         Global Variables
88//////////////////////////////////////////////////////////////////////////////////////////
89
90ksh_cmd_t       cmd[];                    // array of supported commands
91
92log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
93
94unsigned int    ptw;                      // write pointer in log_entries[]
95unsigned int    ptr;                      // read pointer in log_entries[]
96
97pthread_attr_t  attr;                     // interactive thread attributes
98
99sem_t           semaphore;                // block interactive thread when zero
100
101//////////////////////////////////////////////////////////////////////////////////////////
102//         Shell  Commands
103//////////////////////////////////////////////////////////////////////////////////////////
104
105/////////////////////////////////////////////
106static void cmd_cat( int argc , char **argv )
107{
108        char         * path;
109    struct stat    st;
110    int            fd;
111    int            size;
112    char         * buf;
113
114        if (argc != 2) 
115    {
116        fd   = -1;
117        buf  = NULL;
118        size = 0;
119                printf("  usage: cat pathname\n");
120            goto cmd_cat_exit;
121    }
122
123    path = argv[1];
124
125    // open the file
126    fd = open( path , O_RDONLY , 0 );
127    if (fd < 0) 
128    {
129        buf  = NULL;
130        size = 0;
131            printf("  error: cannot open file <%s>\n", path);
132            goto cmd_cat_exit;
133    }
134
135#if DEBUG_CMD_CAT
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)
144    {
145        buf  = NULL;
146        size = 0;
147            printf("  error: cannot stat <%s>\n", path);
148            goto cmd_cat_exit;
149    }
150
151        if ( S_ISDIR(st.st_mode) )
152    {
153        buf  = NULL;
154        size = 0;
155            printf("  error: <%s> is a directory\n", path);
156            goto cmd_cat_exit;
157    }
158
159    // get file size
160    size = st.st_size;
161
162#if DEBUG_CMD_CAT
163get_cycle( &cycle );
164printf("\n[%s] get size %d / cycle %d\n",
165__FUNCTION__ , size , (int)cycle );
166#endif
167
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 );
170
171    if ( buf == NULL )
172    {
173            printf("  error: cannot map file <%s>\n", path );
174            goto cmd_cat_exit;
175    }
176
177#if DEBUG_CMD_CAT
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
192cmd_cat_exit:
193
194        if (buf != NULL) munmap(buf, size);
195        if (fd >= 0) close(fd);
196
197    // release semaphore to get next command
198    sem_post( &semaphore );
199
200}   // end cmd_cat()
201
202////////////////////////////////////////////
203static void cmd_cd( int argc , char **argv )
204{
205        char * path;
206
207        if (argc != 2)
208    {
209                printf("  usage: cd pathname\n");
210        }
211    else
212    {
213            path = argv[1];
214
215        // call the relevant syscall
216        if( chdir( path ) )
217        {
218            printf("  error: cannot found <%s> directory\n", path );
219        }
220    }
221
222    // release semaphore to get next command
223    sem_post( &semaphore );
224
225}   // end cmd_cd()
226
227/////////////////////////////////////////
228static void cmd_cp(int argc, char **argv)
229{
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;
238
239        if (argc != 3) 
240    {
241        src_fd = -1;
242        dst_fd = -1;
243                printf("  usage: cp src_pathname dst_pathname\n");
244        goto cmd_cp_exit;
245        }
246
247    srcpath = argv[1];
248    dstpath = argv[2];
249
250    // open the src file
251    src_fd = open( srcpath , O_RDONLY , 0 );
252
253    if ( src_fd < 0 ) 
254    {
255        dst_fd = -1;
256            printf("  error: cannot open <%s>\n", srcpath );
257            goto cmd_cp_exit;
258    }
259
260#if DEBUG_CMD_CP
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
267    // get file stats
268    if ( stat( srcpath , &st ) )
269    {
270        dst_fd = -1;
271            printf("  error: cannot stat <%s>\n", srcpath);
272            goto cmd_cp_exit;
273    }
274
275#if DEBUG_CMD_CP
276get_cycle( &cycle );
277printf("\n[%s] stats file <%s> done / cycle %d\n",
278__FUNCTION__ , srcpath , (int)cycle );
279#endif
280
281        if ( S_ISDIR(st.st_mode) )
282    {
283        dst_fd = -1;
284                printf("  error: <%s> is a directory\n", srcpath);
285                goto cmd_cp_exit;
286        }
287
288    // get src file size
289        size = st.st_size;
290
291        // open the dst file
292        dst_fd = open( dstpath , O_CREAT|O_TRUNC|O_RDWR , 0 );
293
294        if ( dst_fd < 0 ) 
295    {
296                printf("  error: cannot open <%s>\n", dstpath );
297                goto cmd_cp_exit;
298        }
299
300#if DEBUG_CMD_CP
301get_cycle( &cycle );
302printf("\n[%s] open file <%s> done / cycle %d\n",
303__FUNCTION__ , dstpath , (int)cycle );
304#endif
305
306        if ( stat( dstpath , &st ) )
307    {
308                printf("  error: cannot stat <%s>\n", dstpath );
309                goto cmd_cp_exit;
310        }
311
312#if DEBUG_CMD_CP
313get_cycle( &cycle );
314printf("\n[%s] stats file <%s> done / cycle %d\n",
315__FUNCTION__ , dstpath , (int)cycle );
316#endif
317
318        if ( S_ISDIR(st.st_mode ) ) 
319    {
320                printf("  error: <%s> is a directory\n", dstpath );
321                goto cmd_cp_exit;
322        }
323
324        bytes = 0;
325
326        while (bytes < size)
327        {
328                int len = ((size - bytes) < 4096) ? (size - bytes) : 4096;
329
330                // read the source
331                if ( read( src_fd , buf , len ) != len )
332        {
333                        printf("  error: cannot read from file <%s>\n", srcpath);
334                        goto cmd_cp_exit;
335                }
336
337#if DEBUG_CMD_CP
338get_cycle( &cycle );
339printf("\n[%s] %d bytes read from <%s> / cycle %d\n",
340__FUNCTION__ , len, srcpath , (int)cycle );
341#endif
342
343                // write to the destination
344                if ( write( dst_fd , buf , len ) != len )
345        {
346                        printf("  error: cannot write to file <%s>\n", dstpath);
347                        goto cmd_cp_exit;
348                }
349
350#if DEBUG_CMD_CP
351get_cycle( &cycle );
352printf("\n[%s] %d bytes writen to <%s> / cycle %d\n",
353__FUNCTION__ , len, dstpath , (int)cycle );
354#endif
355
356                bytes += len;
357        }
358
359cmd_cp_exit:
360
361        if (src_fd >= 0) close(src_fd);
362        if (dst_fd >= 0) close(dst_fd);
363
364    // release semaphore to get next command
365    sem_post( &semaphore );
366
367}   // end cmd_cp()
368
369/////////////////////////////////////////////////
370static void cmd_display( int argc , char **argv )
371{
372    if( argc < 2 )
373    {
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");
383    }
384    ////////////////////////////////////
385    else if( strcmp( argv[1] , "vmm" ) == 0 )
386    {
387        if( argc != 4 )
388        {
389                    printf("  usage: display vmm cxy pid\n");
390            }
391        else
392        {
393                unsigned int cxy = atoi(argv[2]);
394                unsigned int pid = atoi(argv[3]);
395
396            if( display_vmm( cxy , pid ) )
397            {
398                printf("  error: no process %x in cluster %x\n", pid , cxy );
399            }
400        }
401    }
402    ///////////////////////////////////////////
403    else if( strcmp( argv[1] , "sched" ) == 0 )
404    {
405        if( argc != 4 )
406        {
407                    printf("  usage: display sched cxy lid\n");
408            }
409        else
410        {
411                unsigned int cxy = atoi(argv[2]);
412                unsigned int lid = atoi(argv[3]);
413
414            if( display_sched( cxy , lid ) )
415            {
416                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
417            }
418        }
419    }
420    /////////////////////////////////////////////
421    else if( strcmp( argv[1] , "process" ) == 0 )
422    {
423        if( argc != 3 )
424        {
425                    printf("  usage: display process cxy\n");
426            }
427        else
428        {
429                unsigned int cxy = atoi(argv[2]);
430
431            if( display_cluster_processes( cxy , 0 ) )
432            {
433                printf("  error: illegal argument cxy = %x\n", cxy );
434            }
435        }
436    }
437    /////////////////////////////////////////
438    else if( strcmp( argv[1] , "txt" ) == 0 )
439    {
440        if( argc != 3 )
441        {
442                    printf("  usage: display txt txt_id\n");
443            }
444        else
445        {
446                unsigned int txtid = atoi(argv[2]);
447
448            if( display_txt_processes( txtid ) )
449            {
450                printf("  error: illegal argument txtid = %d\n", txtid );
451            }
452        }
453    }
454    /////////////////////////////////////////
455    else if( strcmp( argv[1] , "vfs" ) == 0 )
456    {
457        if( argc != 2 )
458        {
459                    printf("  usage: display vfs\n");
460            }
461        else
462        {
463            display_vfs();
464        }
465    }
466    //////////////////////////////////////////
467    else if( strcmp( argv[1] , "chdev" ) == 0 )
468    {
469        if( argc != 2 )
470        {
471                    printf("  usage: display chdev\n");
472            }
473        else
474        {
475            display_chdev();
476        }
477    }
478    //////////////////////////////////////////
479    else if( strcmp( argv[1] , "dqdt" ) == 0 )
480    {
481        if( argc != 2 )
482        {
483                    printf("  usage: display dqdt\n");
484            }
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]);
501
502            if( display_busylocks( pid , trdid ) )
503            {
504                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
505            }
506        }
507    }
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    }
526    else
527    {
528        printf("  error: undefined display request : %s\n", argv[1] ); 
529    }       
530
531    // release semaphore to get next command
532    sem_post( &semaphore );
533
534} // end cmd_display()
535
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        }
545    else
546    {
547        pid = atoi( argv[1] );   
548
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    }
558
559    // release semaphore to get next command
560    sem_post( &semaphore );
561
562}  // end cmd_fg()
563
564//////////////////////////////////////////////
565static void cmd_help( int argc , char **argv )
566{
567        unsigned int i;
568
569        if (argc != 1) 
570    {
571                printf("  usage: %s\n", argv[0]);
572        }
573    else
574    {
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    }
581
582    // release semaphore to get next command
583    sem_post( &semaphore );
584
585}   // end cmd_help()
586
587//////////////////////////////////////////////
588static void cmd_kill( int argc , char **argv )
589{
590        unsigned int pid;
591
592        if (argc != 2) 
593    {
594                printf("  usage: %s pid\n", argv[0]);
595        }
596    else
597    {
598            pid = atoi( argv[1] );
599
600        if( pid == 0 )
601        {
602                    printf("  error: kernel process 0 cannot be killed\n" );
603            }
604
605            else if( kill( pid , SIGKILL ) )
606        {
607                    printf("  error: process %x cannot be killed\n", pid );
608            }
609    }
610
611    // release semaphore to get next command
612    sem_post( &semaphore );
613
614}   // end cmd_kill()
615
616//////////////////////////////////////////////
617static void cmd_load( int argc , char **argv )
618{
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
624    unsigned int         placement;          // placement specified if non zero
625    unsigned int         cxy;                // target cluster if placement specified
626
627        if( (argc < 2) || (argc > 4) ) 
628    {
629                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
630        }
631    else
632    {
633            pathname = argv[1];
634
635        if( argc == 2 )
636        {
637            background = 0;
638            placement  = 0;
639            cxy        = 0;
640        }
641        else if( argc == 3 )
642        {
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) );
659            placement  = 1;
660            cxy        = atoi( argv[2] );
661        }
662
663        // get KSH process PID
664        ksh_pid = getpid();
665
666#if DEBUG_CMD_LOAD
667long long unsigned cycle;
668get_cycle( &cycle );
669printf("\n[ksh] %s : ksh_pid %x / path %s / bg %d / place %d (%x) / cycle %d\n",
670__FUNCTION__, ksh_pid, argv[1], background, placement, cxy, (int)cycle );
671#endif
672
673        // set target cluster if required
674        if( placement ) place_fork( cxy );
675
676        // KSH process fork CHILD process
677            ret_fork = fork();
678
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        {
685
686#if DEBUG_CMD_LOAD
687get_cycle( &cycle );
688printf("\n[ksh] %s : child_pid %x after fork, before exec / cycle %d\n",
689__FUNCTION__ , getpid(), (int)cycle );
690#endif
691
692            // CHILD process exec NEW process
693            ret_exec = execve( pathname , NULL , NULL );
694
695#if DEBUG_CMD_LOAD
696get_cycle( &cycle );
697printf("\n[ksh] %s : child_pid %x after exec / ret_exec %d / cycle %d\n",
698__FUNCTION__ , getpid(), ret_exec, (int)cycle );
699#endif
700
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
709        {
710
711#if DEBUG_CMD_LOAD
712get_cycle( &cycle );
713printf("\n[ksh] %s : ksh_pid %x after fork / ret_fork %x / cycle %d\n",
714__FUNCTION__, getpid(), ret_fork, (int)cycle );
715#endif
716
717            if( background )    // child in background =>  KSH must keep TXT ownership
718            {
719                fg( ksh_pid );
720            }
721        }
722    }
723
724    // release semaphore to get next command
725    sem_post( &semaphore );
726   
727}   // end cmd_load
728
729/////////////////////////////////////////////
730static void cmd_log( int argc , char **argv )
731{
732        unsigned int i;
733
734        if (argc != 1)
735    {
736                printf("  usage: %s\n", argv[0], argc ); 
737        }
738    else
739    {
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    }
746
747    // release semaphore to get next command
748    sem_post( &semaphore );
749
750} // end cmd_log()
751
752
753////////////////////////////////////////////
754static void cmd_ls( int argc , char **argv )
755{
756        char           * pathname;
757    struct dirent  * entry;
758    DIR            * dir;
759
760        if (argc != 2 )
761    {
762                printf("  usage: ls [path]\n");
763        }
764    else
765    {
766
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
801    }
802
803cmd_ls_exit:
804
805    // release semaphore to get next command
806    sem_post( &semaphore );
807
808} // end cmd_ls()
809
810///////////////////////////////////////////////
811static void cmd_mkdir( int argc , char **argv )
812{
813        char * pathname;
814
815        if (argc != 2)
816    {
817                printf("  usage: mkdir pathname\n");
818        }
819    else
820    {
821        pathname = argv[1];
822
823        mkdir( pathname , 0x777 );
824    }
825
826    // release semaphore to get next command
827    sem_post( &semaphore );
828
829} // end cmd_mkdir()
830
831////////////////////////////////////////////
832static void cmd_mv( int argc , char **argv )
833{
834        char * old_path;
835    char * new_path;
836
837        if (argc != 3) 
838    {
839                printf("  usage: mv old_pathname new_pathname\n");
840        }
841    else
842    {
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        }
851    }
852
853    // release semaphore to get next command
854    sem_post( &semaphore );
855
856}  // end cmd_mv
857
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        }
872    else
873    {
874        // get platform config
875        get_config( &x_size , &y_size , &ncores );
876
877        // scan all clusters
878        for( x = 0 ; x < x_size ; x++ )
879        {
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            }
885        }
886    }
887
888    // release semaphore to get next command
889    sem_post( &semaphore );
890
891}  // end cmd_ps()
892
893/////////////////////////////////////////////
894static void cmd_pwd( int argc , char **argv )
895{
896        char buf[1024];
897
898        if (argc != 1)
899    {
900                printf("  usage: %s\n", argv[0]);
901        }
902    else 
903    {
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    }
913
914    // release semaphore to get next command
915    sem_post( &semaphore );
916
917}  // end cmd_pwd()
918
919////////////////////////////////////////////
920static void cmd_rm( int argc , char **argv )
921{
922        char * pathname;
923
924        if (argc != 2)
925    {
926                printf("  usage: %s pathname\n", argv[0]);
927        }
928    else
929    {
930            pathname = argv[1];
931
932        if ( unlink( pathname ) )
933        {
934                    printf("  error: unable to remove <%s>\n", pathname );
935            }
936    }
937
938    // release semaphore to get next command
939    sem_post( &semaphore );
940
941}  // end_cmd_rm()
942
943///////////////////////////////////////////////
944static void cmd_rmdir( int argc , char **argv )
945{
946    // same as cmd_rm()
947        cmd_rm(argc, argv);
948}
949
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        }
960    else
961    {
962        cxy = atoi(argv[1]);
963        lid = atoi(argv[2]);
964
965        if( trace( 1 , cxy , lid ) )
966        {
967            printf("  error: core[%x,%d] not found\n", cxy, lid );
968        }
969    }
970
971    // release semaphore to get next command
972    sem_post( &semaphore );
973
974}  // end cmd_trace
975
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        }
986    else
987    {
988        cxy = atoi(argv[1]);
989        lid = atoi(argv[2]);
990
991        if( trace( 0 , cxy , lid ) )
992        {
993            printf("  error: core[%x,%d] not found\n", cxy, lid );
994        }
995    }
996
997    // release semaphore to get next command
998    sem_post( &semaphore );
999
1000}  // end cmd_untrace()
1001
1002///////////////////////////////////////////////////////////////////////////////////
1003// Array of commands
1004///////////////////////////////////////////////////////////////////////////////////
1005
1006ksh_cmd_t cmd[] =
1007{
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    },
1015        { "kill",    "kill a process (all threads)",                    cmd_kill    },
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     },
1021        { "ps",      "display all processes",                           cmd_ps      },
1022        { "rm",      "remove a file from file system",                  cmd_rm      },
1023        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
1024        { "trace",   "activate trace for a given core",                 cmd_trace   },
1025        { "untrace", "desactivate trace for a given core",              cmd_untrace },
1026        { NULL,      NULL,                                                                              NULL        }
1027};
1028
1029////////////////////////////////////////////////////////////////////////////////////
1030// This function analyses one command (with arguments), executes it, and returns.
1031////////////////////////////////////////////////////////////////////////////////////
1032static void __attribute__ ((noinline)) parse( char * buf )
1033{
1034        int argc = 0;
1035        char *argv[MAX_ARGS];
1036        int i;
1037        int len = strlen(buf);
1038
1039        // build argc/argv
1040        for (i = 0; i < len; i++) 
1041    {
1042                if (buf[i] == ' ') 
1043        {
1044                        buf[i] = '\0';
1045                }
1046        else if (i == 0 || buf[i - 1] == '\0') 
1047        {
1048                        if (argc < MAX_ARGS) 
1049            {
1050                                argv[argc] = &buf[i];
1051                                argc++;
1052                        }
1053                }
1054        }
1055
1056    // analyse command type
1057        if (argc > 0)
1058    {
1059                int found = 0;
1060
1061                argv[argc] = NULL;
1062
1063                // try to match typed command
1064                for (i = 0 ; cmd[i].name ; i++)
1065        {
1066                        if (strcmp(argv[0], cmd[i].name) == 0)
1067            {
1068                                cmd[i].fn(argc, argv);
1069                                found = 1;
1070                                break;
1071                        }
1072                }
1073
1074                if (!found)  // undefined command
1075        {
1076                        printf("  error : undefined command <%s>\n", argv[0]);
1077
1078            // release semaphore to get next command
1079            sem_post( &semaphore );
1080                }
1081        }
1082}  // end parse()
1083
1084///////////////////////////////
1085static void interactive( void )
1086{
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
1093
1094
1095/* To lauch one command without interactive mode
1096   
1097if( sem_wait( &semaphore ) )
1098{
1099    printf("\n[ksh error] cannot found semafore\n" );
1100    exit( 1 );
1101}
1102else
1103{
1104    printf("\n[ksh] ls bin/user\n");
1105}
1106
1107strcpy( buf , "ls bin/user" );
1108parse( buf );
1109
1110*/
1111
1112        enum fsm_states
1113    {
1114                NORMAL = 0,
1115                ESCAPE = 1,
1116                BRAKET = 2,
1117        };
1118
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:
1121        // - ESC [ A : up arrow
1122        // - ESC [ B : down arrow
1123        // - ESC [ C : right arrow
1124        // - ESC [ D : left arrow
1125        // The three states have the following semantic:
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
1129
1130    // external loop on the commands
1131    // the in teractive thread should not exit this loop
1132        while (1)
1133        {
1134            // initialize command buffer
1135            memset( buf, 0x20 , sizeof(buf) );   // TODO useful ?
1136            count = 0;
1137            state = NORMAL;
1138
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        }
1145
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                    {
1161                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1162                                {
1163                                    if (count > 0)
1164                    {
1165                                        printf("\b \b");
1166                                        count--;
1167                                    }
1168                                }
1169                                else if (c == '\n')                  // new line => end of command
1170                                {
1171                                    if (count > 0)               // analyse & execute command
1172                                    {
1173                                            // complete command with NUL character
1174                                            buf[count] = 0;
1175                        count++;
1176
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;
1182
1183                        // echo character
1184                        putchar( c );
1185
1186                                            // call parser to analyse and execute command
1187                                            parse( buf );
1188                                    }
1189                    else                         // no command registered
1190                    {
1191                        // release semaphore to get next command
1192                        sem_post( &semaphore );
1193                    }
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
1206                                {
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 );
1215                                        }
1216                                }
1217                        }
1218                        else if( state == ESCAPE ) 
1219                        {
1220                                if (c == '[')           //  valid sequence => continue
1221                                {
1222                                        state = BRAKET;
1223                                }
1224                                else                               // invalid sequence => do nothing
1225                                {
1226                                        state = NORMAL;
1227                                }
1228                        }
1229                        else if( state == BRAKET )
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);
1262                                        count = log_entries[ptr].count - 1;
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                        }
1293                }  // end internal while loop on characters
1294        }  // end external while loop on commands
1295}  // end interactive()
1296
1297////////////////
1298int main( void )
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
1303    int          child_pid;       // child process identifier
1304    int          parent_pid;      // parent process identifier (i.e. this process)
1305    pthread_t    trdid;           // interactive thread identifier (unused)
1306    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1307
1308    // initialize log buffer
1309        memset( &log_entries , 0, sizeof(log_entries));
1310        ptw   = 0;
1311        ptr   = 0;
1312
1313    // get KSH process pid and core
1314    parent_pid = getpid();
1315    get_core( &cxy , &lid );
1316
1317#if DEBUG_MAIN
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
1322    if ( sem_init( &semaphore , 0 , 1 ) )
1323    {
1324        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1325        exit( 1 ); 
1326    }
1327
1328#if DEBUG_MAIN
1329printf("\n[ksh] main initialized semaphore\n" ); 
1330#endif
1331   
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 ); 
1341#if DEBUG_MAIN
1342printf("\n[ksh] main launched interactive thread => wait children termination\n" ); 
1343#endif
1344
1345    // signal INIT process
1346    kill( 1 , SIGCONT );
1347   
1348    // enter infinite loop monitoring children processes termination
1349    while( 1 )
1350    {
1351        // wait children termination
1352        child_pid = wait( &status );
1353
1354#if DEBUG_MAIN
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 );
1358#endif
1359
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
1364    }
1365}  // end main()
1366
1367
Note: See TracBrowser for help on using the repository browser.