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

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

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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