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

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

This version has been tested on the sort multithreaded application
for TSAR_IOB architectures ranging from 1 to 8 clusters.
It fixes three bigs bugs:
1) the dev_ioc device API has been modified: the dev_ioc_sync_read()
and dev_ioc_sync_write() function use now extended pointers on the
kernel buffer to access a mapper stored in any cluster.
2) the hal_uspace API has been modified: the hal_copy_to_uspace()
and hal_copy_from_uspace() functions use now a (cxy,ptr) couple
to identify the target buffer (equivalent to an extended pointer.
3) an implementation bug has been fixed in the assembly code contained
in the hal_copy_to_uspace() and hal_copy_from_uspace() functions.

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// Lauch one or several commands without interactive mode
1182
1183// 1. first command
1184if( sem_wait( &semaphore ) )
1185{
1186    printf("\n[ksh error] cannot found semafore\n" );
1187    exit( 1 );
1188}
1189else
1190{
1191    printf("\n[ksh] display fat 0 32\n");
1192}
1193
1194strcpy( cmd , "display fat 0 32" );
1195execute( cmd );
1196
1197// 2. second command
1198if( sem_wait( &semaphore ) )
1199{
1200    printf("\n[ksh error] cannot found semafore\n" );
1201    exit( 1 );
1202}
1203else
1204{
1205    printf("\n[ksh] load bin/user/pgcd.elf\n");
1206}
1207
1208strcpy( cmd , "load bin/user/pgcd.elf" );
1209execute( cmd );
1210
1211// end non-interactive mode
1212*/
1213
1214        enum fsm_states
1215    {
1216                NORMAL = 0,
1217                ESCAPE = 1,
1218                BRAKET = 2,
1219        };
1220
1221        // This lexical analyser writes one command line in the command buffer.
1222        // It is implemented as a 3 states FSM to handle the following escape sequences:
1223        // - ESC [ A : up arrow
1224        // - ESC [ B : down arrow
1225        // - ESC [ C : right arrow
1226        // - ESC [ D : left arrow
1227        // The three states have the following semantic:
1228        // - NORMAL : no (ESC) character has been found
1229        // - ESCAPE : the character (ESC) has been found
1230        // - BRAKET : the wo characters (ESC,[) have been found
1231
1232    // take the semaphore for the first command
1233    if ( sem_wait( &semaphore ) )
1234    {
1235        printf("\n[ksh error] cannot found semafore\n" );
1236        exit( 1 );
1237    }
1238
1239    // display prompt for the first command
1240    printf("\n[ksh] ");
1241
1242    // external loop on the commands / the interactive thread do not exit this loop
1243        while (1)
1244        {
1245            // initialize command buffer
1246            // memset( cmd , 0x20 , sizeof(cmd) );   // TODO useful ?
1247            count       = 0;
1248            state       = NORMAL;
1249        end_command = 0;
1250
1251#if DEBUG_INTER
1252unsigned int pid = getpid();
1253snprintf( string , 128 , "\n[ksh] %s : request a new command", __FUNCTION__ );
1254display_string( string );
1255#endif
1256
1257        // internal loop on characters in one command
1258        while( end_command == 0 )
1259        {
1260            // get one character from TXT_RX
1261                c = (char)getchar();
1262
1263            if( c == 0 ) continue;
1264
1265                    if( state == NORMAL )  // we are not in an escape sequence
1266                    {
1267                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1268                                {
1269                                    if (count > 0)
1270                    {
1271                                        printf("\b \b");
1272                                        count--;
1273                                    }
1274                                }
1275                                else if (c == '\n')                  // new line => end of command
1276                                {
1277                                    if (count > 0)               // analyse & execute command
1278                                    {
1279                                            // complete command with NUL character
1280                                            cmd[count] = 0;
1281                        count++;
1282#if DEBUG_INTER
1283snprintf( string , 128 , "[ksh] %s : get command <%s> / &log = %x / ptw = %d / &ptw = %x",
1284__FUNCTION__, cmd , log_entries[ptw].buf , ptw , &ptw );
1285display_string( string );
1286display_vmm( 0 , 2 );
1287#endif
1288                        // register command in log_entries[] array
1289                                            strncpy( log_entries[ptw].buf , cmd , count );
1290                                            log_entries[ptw].count = count;
1291                                            ptw = (ptw + 1) % LOG_DEPTH;
1292                                            ptr = ptw;
1293
1294#if DEBUG_INTER
1295snprintf( string , 128 , "[ksh] %s : execute <%s>", __FUNCTION__, cmd );
1296display_string( string );
1297#endif
1298                        // echo character
1299                        putchar( c );
1300
1301                                            // execute command
1302                                            execute( cmd );
1303                                    }
1304                    else                         // no command registered
1305                    {
1306                        // release semaphore to get next command
1307                        sem_post( &semaphore );
1308                    }
1309
1310                    // exit internal loop on characters
1311                    end_command = 1;
1312                }
1313                            else if (c == '\t')             // tabulation => do nothing
1314                                {
1315                            }
1316                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1317                            {
1318                    state = ESCAPE;
1319                            }
1320                            else                                               // normal character
1321                                {
1322                                    if (count < (sizeof(cmd) - 1) )
1323                                    {
1324                        // register character in command buffer
1325                                            cmd[count] = c;
1326                                            count++;
1327
1328                        // echo character
1329                        putchar( c );
1330                                        }
1331                    else
1332                    {
1333                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1334                    }
1335                                }
1336                        }
1337                        else if( state == ESCAPE ) 
1338                        {
1339                                if (c == '[')           //  valid sequence => continue
1340                                {
1341                                        state = BRAKET;
1342                                }
1343                                else                               // invalid sequence => do nothing
1344                                {
1345                                        state = NORMAL;
1346                                }
1347                        }
1348                        else if( state == BRAKET )
1349                        {
1350                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
1351                                {
1352                                        if (count > 0)
1353                                        {
1354                                                printf("\b");
1355                                                count--;
1356                                        }
1357
1358                                        // get next user char
1359                                        state = NORMAL;
1360                                }
1361                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
1362                                {
1363                                        if (count < sizeof(cmd) - 1)
1364                                        {
1365                                                printf("%c", cmd[count]);
1366                                                count++;
1367                                        }
1368
1369                                        // get next user char
1370                                        state = NORMAL;
1371                                }
1372                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1373                                {
1374                                        // cancel current command
1375                                        for (i = 0; i < count; i++) printf("\b \b");
1376                                        count = 0;
1377
1378                                        // copy log command into cmd
1379                                        ptr = (ptr - 1) % LOG_DEPTH;
1380                                        strcpy(cmd, log_entries[ptr].buf);
1381                                        count = log_entries[ptr].count - 1;
1382
1383                                        // display log command
1384                                        printf("%s", cmd);
1385
1386                                        // get next user char
1387                                        state = NORMAL;
1388                                }
1389                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1390                                {
1391                                        // cancel current command
1392                                        for (i = 0 ; i < count; i++) printf("\b \b");
1393                                        count = 0;
1394
1395                                        // copy log command into cmd
1396                                        ptr = (ptr + 1) % LOG_DEPTH;
1397                                        strcpy(cmd, log_entries[ptr].buf);
1398                                        count = log_entries[ptr].count;
1399
1400                                        // display log command
1401                                        printf("%s", cmd);
1402
1403                                        // get next user char
1404                                        state = NORMAL;
1405                                }
1406                                else                               // other character => do nothing
1407                                {
1408                                        // get next user char
1409                                        state = NORMAL;
1410                                }
1411                        }
1412                }  // end internal while loop on characters
1413
1414#if DEBUG_INTER
1415snprintf( string , 128 , "\n[ksh] %s : complete <%s> command", __FUNCTION__, cmd );
1416display_string( string );
1417#endif
1418
1419        // block interactive thread if KSH loose TXT ownership
1420        if ( sem_wait( &semaphore ) )
1421        {
1422            printf("\n[ksh error] cannot found semafore\n" );
1423            exit( 1 );
1424        }
1425
1426        // display prompt for next command
1427        printf("\n[ksh] ");
1428
1429        }  // end external while loop on commands
1430
1431}  // end interactive()
1432
1433////////////////
1434int main( void )
1435{
1436    unsigned int cxy;             // owner cluster identifier for this KSH process
1437    unsigned int lid;             // core identifier for this KSH main thread
1438    int          status;          // child process termination status
1439    int          child_pid;       // child process identifier
1440    int          parent_pid;      // parent process identifier (i.e. this process)
1441    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1442
1443    // initialize log buffer
1444        memset( &log_entries , 0, sizeof(log_entries));
1445        ptw   = 0;
1446        ptr   = 0;
1447
1448    // get KSH process pid and core
1449    parent_pid = getpid();
1450    get_core( &cxy , &lid );
1451
1452#if DEBUG_MAIN
1453printf("\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1454#endif
1455   
1456    // initializes the semaphore used to synchronize with interactive thread
1457    if ( sem_init( &semaphore , 0 , 1 ) )
1458    {
1459        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1460        exit( 1 ); 
1461    }
1462
1463#if DEBUG_MAIN
1464printf("\n[ksh] main initialized semaphore\n" ); 
1465#endif
1466   
1467    // initialize interactive thread attributes
1468    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1469    attr.cxy        = cxy;
1470
1471    // lauch the interactive thread
1472    pthread_create( &trdid,
1473                    &attr,
1474                    &interactive,   // entry function
1475                    NULL ); 
1476#if DEBUG_MAIN
1477printf("\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1478#endif
1479
1480    // signal INIT process
1481    kill( 1 , SIGCONT );
1482   
1483    // enter infinite loop monitoring children processes termination
1484    while( 1 )
1485    {
1486        // wait children termination
1487        child_pid = wait( &status );
1488
1489#if DEBUG_MAIN
1490if( WIFEXITED  (status) ) printf("\n[ksh] child process %x exit\n"   , child_pid );
1491if( WIFSIGNALED(status) ) printf("\n[ksh] child process %x killed\n" , child_pid );
1492if( WIFSTOPPED (status) ) printf("\n[ksh] child process %x stopped\n", child_pid );
1493#endif
1494
1495        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1496        is_fg( parent_pid , &is_owner );
1497        if( is_owner ) sem_post( &semaphore );
1498    }
1499}  // end main()
1500
1501
Note: See TracBrowser for help on using the repository browser.