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

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

cosmetic

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