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

Last change on this file since 663 was 659, checked in by alain, 4 years ago

euh...

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