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

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

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

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