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

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

Introducing application "display".

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