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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 37.6 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 lauched 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_id  nbytes\n");
403    }
404    ////////////////////////////////////
405    else if( strcmp( argv[1] , "vmm" ) == 0 )
406    {
407        if( argc != 4 )
408        {
409                    printf("  usage: display vmm cxy pid\n");
410            }
411        else
412        {
413                unsigned int cxy = atoi(argv[2]);
414                unsigned int pid = atoi(argv[3]);
415
416            if( display_vmm( cxy , pid ) )
417            {
418                printf("  error: no process %x in cluster %x\n", pid , cxy );
419            }
420        }
421    }
422    ///////////////////////////////////////////
423    else if( strcmp( argv[1] , "sched" ) == 0 )
424    {
425        if( argc != 4 )
426        {
427                    printf("  usage: display sched cxy lid\n");
428            }
429        else
430        {
431                unsigned int cxy = atoi(argv[2]);
432                unsigned int lid = atoi(argv[3]);
433
434            if( display_sched( cxy , lid ) )
435            {
436                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
437            }
438        }
439    }
440    /////////////////////////////////////////////
441    else if( strcmp( argv[1] , "process" ) == 0 )
442    {
443        if( argc != 3 )
444        {
445                    printf("  usage: display process cxy\n");
446            }
447        else
448        {
449                unsigned int cxy = atoi(argv[2]);
450
451            if( display_cluster_processes( cxy , 0 ) )
452            {
453                printf("  error: illegal argument cxy = %x\n", cxy );
454            }
455        }
456    }
457    /////////////////////////////////////////
458    else if( strcmp( argv[1] , "txt" ) == 0 )
459    {
460        if( argc != 3 )
461        {
462                    printf("  usage: display txt txt_id\n");
463            }
464        else
465        {
466                unsigned int txtid = atoi(argv[2]);
467
468            if( display_txt_processes( txtid ) )
469            {
470                printf("  error: illegal argument txtid = %d\n", txtid );
471            }
472        }
473    }
474    /////////////////////////////////////////
475    else if( strcmp( argv[1] , "vfs" ) == 0 )
476    {
477        if( argc != 2 )
478        {
479                    printf("  usage: display vfs\n");
480            }
481        else
482        {
483            display_vfs();
484        }
485    }
486    //////////////////////////////////////////
487    else if( strcmp( argv[1] , "chdev" ) == 0 )
488    {
489        if( argc != 2 )
490        {
491                    printf("  usage: display chdev\n");
492            }
493        else
494        {
495            display_chdev();
496        }
497    }
498    //////////////////////////////////////////
499    else if( strcmp( argv[1] , "dqdt" ) == 0 )
500    {
501        if( argc != 2 )
502        {
503                    printf("  usage: display dqdt\n");
504            }
505        else
506        {
507            display_dqdt();
508        }
509    }
510    ///////////////////////////////////////////
511    else if( strcmp( argv[1] , "locks" ) == 0 )
512    {
513        if( argc != 4 )
514        {
515                    printf("  usage: display locks pid trdid\n");
516            }
517        else
518        {
519                unsigned int pid   = atoi(argv[2]);
520            unsigned int trdid = atoi(argv[3]);
521
522            if( display_busylocks( pid , trdid ) )
523            {
524                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
525            }
526        }
527    }
528    /////////////////////////////////////////////////
529    else if( strcmp( argv[1] , "barrier" ) == 0 )
530    {
531        if( argc != 3 )
532        {
533                    printf("  usage: display barrier pid\n");
534            }
535        else
536        {
537                unsigned int pid   = atoi(argv[2]);
538
539            if( display_barrier( pid ) )
540            {
541                printf("  error: illegal arguments pid = %x\n", pid );
542            }
543        }
544    }
545    ///////////////////////////////////////////
546    else if( strcmp( argv[1] , "mapper" ) == 0 )
547    {
548        if( argc != 5 )
549        {
550                    printf("  usage: display mapper path page_id nbytes\n");
551            }
552        else
553        {
554                unsigned int page_id   = atoi(argv[3]);
555            unsigned int nbytes    = atoi(argv[4]);
556
557            if( display_mapper( argv[2] , page_id, nbytes ) )
558            {
559                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
560            }
561        }
562    }
563    else
564    {
565        printf("  error: undefined display request : %s\n", argv[1] ); 
566    }       
567
568    // release semaphore to get next command
569    sem_post( &semaphore );
570
571} // end cmd_display()
572
573/////////////////////////////////////////
574static void cmd_fg(int argc, char **argv)
575{
576        unsigned int pid;
577
578        if (argc != 2) 
579    {
580                printf("  usage: %s pid\n", argv[0]);
581        }
582    else
583    {
584        pid = atoi( argv[1] );   
585
586        if( pid == 0 )
587        { 
588                    printf("  error: PID cannot be 0\n" );
589            }
590        else if( fg( pid ) )
591        {
592                    printf("  error: cannot find process %x\n", pid );
593            }
594    }
595
596    // release semaphore to get next command
597    sem_post( &semaphore );
598
599}  // end cmd_fg()
600
601//////////////////////////////////////////////
602static void cmd_help( int argc , char **argv )
603{
604        unsigned int i;
605
606        if (argc != 1) 
607    {
608                printf("  usage: %s\n", argv[0]);
609        }
610    else
611    {
612        printf("available commands:\n");
613            for (i = 0 ; command[i].name ; i++) 
614        {
615                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
616            }
617    }
618
619    // release semaphore to get next command
620    sem_post( &semaphore );
621
622}   // end cmd_help()
623
624//////////////////////////////////////////////
625static void cmd_kill( int argc , char **argv )
626{
627        unsigned int pid;
628
629        if (argc != 2) 
630    {
631                printf("  usage: %s pid\n", argv[0]);
632        }
633    else
634    {
635            pid = atoi( argv[1] );
636
637        if( pid == 0 )
638        {
639                    printf("  error: kernel process 0 cannot be killed\n" );
640            }
641
642            else if( kill( pid , SIGKILL ) )
643        {
644                    printf("  error: process %x cannot be killed\n", pid );
645            }
646    }
647
648    // release semaphore to get next command
649    sem_post( &semaphore );
650
651}   // end cmd_kill()
652
653//////////////////////////////////////////////
654static void cmd_load( int argc , char **argv )
655{
656        int                  ret_fork;           // return value from fork
657        int                  ret_exec;           // return value from exec
658    unsigned int         ksh_pid;            // KSH process PID
659    unsigned int         background;         // background execution if non zero
660    unsigned int         placement;          // placement specified if non zero
661    unsigned int         cxy;                // target cluster if placement specified
662
663#if DEBUG_CMD_LOAD
664char string[64];
665#endif
666
667        if( (argc < 2) || (argc > 4) ) 
668    {
669                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
670        }
671    else
672    {
673            strcpy( pathname , argv[1] );
674
675        if( argc == 2 )
676        {
677            background = 0;
678            placement  = 0;
679            cxy        = 0;
680        }
681        else if( argc == 3 )
682        {
683            if( (argv[2][0] == '&') && (argv[2][1] == 0) )
684            {
685                background = 1;
686                placement  = 0;
687                cxy        = 0;
688            }
689            else 
690            {
691                background = 0;
692                placement  = 1;
693                cxy        = atoi( argv[2] );
694            }
695        }
696        else  // argc == 4
697        { 
698            background = ( (argv[3][0] == '&') && (argv[3][1] == 0) );
699            placement  = 1;
700            cxy        = atoi( argv[2] );
701        }
702
703        // get KSH process PID
704        ksh_pid = getpid();
705
706#if DEBUG_CMD_LOAD
707snprintf( string , 64 , "[ksh] %s : ksh_pid %x / path %s / bg %d / place %d (%x)\n",
708__FUNCTION__, ksh_pid, argv[1], background, placement, cxy );
709display_string( string );
710#endif
711
712        // set target cluster if required
713        if( placement ) place_fork( cxy );
714
715        // KSH process fork CHILD process
716            ret_fork = fork();
717
718        if ( ret_fork < 0 )     // it is a failure reported to KSH
719        {
720            printf("  error: ksh process unable to fork\n");
721        }
722        else if (ret_fork == 0) // it is the CHILD process
723        {
724
725#if DEBUG_CMD_LOAD
726snprintf( string , 64 , "[ksh] %s : child_pid %x after fork, before exec\n",
727__FUNCTION__ , getpid() );
728display_string( string );
729#endif
730
731            // CHILD process exec NEW process
732            ret_exec = execve( pathname , NULL , NULL );
733
734#if DEBUG_CMD_LOAD
735snprintf( string , 64 , "[ksh] %s : child_pid %x after exec / ret_exec %x\n",
736__FUNCTION__ , getpid(), ret_exec );
737display_string( string );
738#endif
739
740            // this is only executed in case of exec failure
741            if( ret_exec )
742            {
743                printf("  error: child process unable to exec <%s>\n", pathname );
744                exit( 0 );
745            }   
746            } 
747        else                    // it is the KSH process : ret_fork is the new process PID
748        {
749
750#if DEBUG_CMD_LOAD
751snprintf( string , 64 , "[ksh] %s : ksh_pid %x after fork / ret_fork %x\n",
752__FUNCTION__, getpid(), ret_fork );
753display_string( string );
754#endif
755            // when the new process is launched in background, the KSH process
756            // takes the TXT ownership, and release the semaphore to get the next command.
757            // Otherwise, the child process keep the TXT ownership, and the semaphore will
758            // be released by the KSH main thread when the child process exit
759
760            if( background )    //  KSH must keep TXT ownership
761            {
762                // get back the TXT ownership
763                fg( ksh_pid );
764
765                // release semaphore to get next command
766                sem_post( &semaphore );
767            }
768        }
769    }
770}   // end cmd_load
771
772/////////////////////////////////////////////
773static void cmd_log( int argc , char **argv )
774{
775        unsigned int i;
776
777        if (argc != 1)
778    {
779                printf("  usage: %s\n", argv[0], argc ); 
780        }
781    else
782    {
783            printf("--- registered commands ---\n");
784            for (i = 0; i < LOG_DEPTH; i++) 
785        {
786                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
787            }
788    }
789
790    // release semaphore to get next command
791    sem_post( &semaphore );
792
793} // end cmd_log()
794
795
796////////////////////////////////////////////
797static void cmd_ls( int argc , char **argv )
798{
799    struct dirent  * entry;
800    DIR            * dir;
801
802#if DEBUG_CMD_LS
803char string[64];
804#endif
805
806        if (argc > 2 )
807    {
808                printf("  usage: ls [path]\n");
809        }
810    else
811    {
812        // handle case with no argument
813
814        // get target directory path
815        if ( argc == 1 ) strcpy( pathname , "." );
816        else             strcpy( pathname , argv[1] );
817
818        // open target directory
819            dir = opendir( pathname );
820
821#if DEBUG_CMD_LS
822snprintf( string , 64 , "[ksh] %s : directory <%s> open / DIR %x\n",
823__FUNCTION__, pathname , dir );
824display_string( string );
825#endif
826
827        if( dir == NULL)
828            {
829                    printf("  error : directory <%s> not found\n", pathname );
830
831            sem_post( &semaphore );
832            return;
833            }
834
835        // loop on directory entries   
836        while ( (entry = readdir(dir)) != NULL )
837            {
838                    printf("%s\n", entry->d_name);
839            }
840
841        // close target directory
842            closedir( dir );
843
844#if DEBUG_CMD_LS
845snprintf( string , 64 , "[ksh] %s : directory <%s> closed\n",
846__FUNCTION__, pathname );
847display_string( string );
848#endif
849
850    }
851
852    // release semaphore to get next command
853    sem_post( &semaphore );
854
855} // end cmd_ls()
856
857///////////////////////////////////////////////
858static void cmd_mkdir( int argc , char **argv )
859{
860        if (argc != 2)
861    {
862                printf("  usage: mkdir pathname\n");
863        }
864    else
865    {
866        strcpy( pathname , argv[1] );
867
868        mkdir( pathname , 0x777 );
869    }
870
871    // release semaphore to get next command
872    sem_post( &semaphore );
873
874} // end cmd_mkdir()
875
876////////////////////////////////////////////
877static void cmd_mv( int argc , char **argv )
878{
879        if (argc != 3) 
880    {
881                printf("  usage: mv old_pathname new_pathname\n");
882        }
883    else
884    {
885        strcpy( pathname , argv[1] );
886        strcpy( pathnew  , argv[2] );
887
888        // call the relevant syscall
889        if( rename( pathname , pathnew ) )
890        {
891            printf("  error: unable to rename <%s> to <%s>\n", pathname , pathnew );
892        }
893    }
894
895    // release semaphore to get next command
896    sem_post( &semaphore );
897
898}  // end cmd_mv
899
900
901////////////////////////////////////////////
902static void cmd_ps( int argc , char **argv )
903{
904    unsigned int x_size;
905    unsigned int y_size;
906    unsigned int ncores;
907    unsigned int x;
908    unsigned int y;
909
910#if DEBUG_CMD_PS
911char string[64];
912#endif
913
914        if (argc != 1)
915    {
916                printf("  usage: %s\n", argv[0]);
917        }
918    else
919    {
920        // get platform config
921        get_config( &x_size , &y_size , &ncores );
922
923        // scan all clusters
924        for( x = 0 ; x < x_size ; x++ )
925        {
926            for( y = 0 ; y < y_size ; y++ )
927            {
928
929#if DEBUG_CMD_PS
930snprintf( string , 64 , "\n[ksh] %s : call display_cluster_process()", __FUNCTION__ );
931display_string( string );
932#endif
933
934                // display only owned processes
935                display_cluster_processes( HAL_CXY_FROM_XY(x,y), 1 ); 
936            }
937        }
938    }
939
940    // release semaphore to get next command
941    sem_post( &semaphore );
942
943}  // end cmd_ps()
944
945/////////////////////////////////////////////
946static void cmd_pwd( int argc , char **argv )
947{
948        if (argc != 1)
949    {
950                printf("  usage: %s\n", argv[0]);
951        }
952    else 
953    {
954        if ( getcwd( pathname , PATH_MAX_SIZE ) ) 
955        {
956                    printf("  error: unable to get current directory\n");
957            }
958        else 
959        {
960                    printf("%s\n", pathname );
961            }
962    }
963
964    // release semaphore to get next command
965    sem_post( &semaphore );
966
967}  // end cmd_pwd()
968
969////////////////////////////////////////////
970static void cmd_rm( int argc , char **argv )
971{
972        if (argc != 2)
973    {
974                printf("  usage: %s pathname\n", argv[0]);
975        }
976    else
977    {
978            strcpy( pathname , argv[1] );
979
980        if ( unlink( pathname ) )
981        {
982                    printf("  error: unable to remove <%s>\n", pathname );
983            }
984    }
985
986    // release semaphore to get next command
987    sem_post( &semaphore );
988
989}  // end_cmd_rm()
990
991///////////////////////////////////////////////
992static void cmd_rmdir( int argc , char **argv )
993{
994    // same as cmd_rm()
995        cmd_rm (argc , argv );
996}
997
998///////////////////////////////////////////////
999static void cmd_trace( int argc , char **argv )
1000{
1001    unsigned int cxy;
1002    unsigned int lid;
1003
1004        if (argc != 3)
1005    {
1006                printf("  usage: trace cxy lid \n");
1007        }
1008    else
1009    {
1010        cxy = atoi(argv[1]);
1011        lid = atoi(argv[2]);
1012
1013        if( trace( 1 , cxy , lid ) )
1014        {
1015            printf("  error: core[%x,%d] not found\n", cxy, lid );
1016        }
1017    }
1018
1019    // release semaphore to get next command
1020    sem_post( &semaphore );
1021
1022}  // end cmd_trace
1023
1024///////////////////////////////////////////////
1025static void cmd_untrace( int argc , char **argv )
1026{
1027    unsigned int cxy;
1028    unsigned int lid;
1029
1030        if (argc != 3)
1031    {
1032                printf("  usage: untrace cxy lid \n");
1033        }
1034    else
1035    {
1036        cxy = atoi(argv[1]);
1037        lid = atoi(argv[2]);
1038
1039        if( trace( 0 , cxy , lid ) )
1040        {
1041            printf("  error: core[%x,%d] not found\n", cxy, lid );
1042        }
1043    }
1044
1045    // release semaphore to get next command
1046    sem_post( &semaphore );
1047
1048}  // end cmd_untrace()
1049
1050///////////////////////////////////////////////////////////////////////////////////
1051// Array of commands
1052///////////////////////////////////////////////////////////////////////////////////
1053
1054ksh_cmd_t command[] =
1055{
1056        { "cat",     "display file content",                            cmd_cat     },
1057        { "cd",      "change current directory",                        cmd_cd      },
1058        { "cp",      "replicate a file in file system",                 cmd_cp      },
1059    { "fg",      "put a process in foreground",                     cmd_fg      },
1060    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1061        { "load",    "load an user application",                        cmd_load    },
1062        { "help",    "list available commands",                         cmd_help    },
1063        { "kill",    "kill a process (all threads)",                    cmd_kill    },
1064        { "log",     "list registered commands",                        cmd_log     },
1065        { "ls",      "list directory entries",                          cmd_ls      },
1066        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1067        { "mv",      "move a file in file system",                      cmd_mv      },
1068        { "pwd",     "print current working directory",                 cmd_pwd     },
1069        { "ps",      "display all processes",                           cmd_ps      },
1070        { "rm",      "remove a file from file system",                  cmd_rm      },
1071        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
1072        { "trace",   "activate trace for a given core",                 cmd_trace   },
1073        { "untrace", "desactivate trace for a given core",              cmd_untrace },
1074        { NULL,      NULL,                                                                              NULL        }
1075};
1076
1077////////////////////////////////////////////////////////////////////////////////////
1078// This function analyses one command (with arguments), executes it, and returns.
1079////////////////////////////////////////////////////////////////////////////////////
1080static void __attribute__ ((noinline)) execute( char * buf )
1081{
1082        int    argc = 0;
1083        char * argv[MAX_ARGS];
1084        int    i;
1085        int    len = strlen(buf);
1086
1087#if DEBUG_EXECUTE
1088printf("\n[ksh] %s : command <%s>\n",
1089__FUNCTION__ , buf );
1090#endif
1091
1092        // build argc/argv
1093        for (i = 0; i < len; i++) 
1094    {
1095        // convert SPACE to NUL
1096                if (buf[i] == ' ') 
1097        {
1098                        buf[i] = '\0';
1099                }
1100        else if (i == 0 || buf[i - 1] == '\0') 
1101        {
1102                        if (argc < MAX_ARGS) 
1103            {
1104                                argv[argc] = &buf[i];
1105                                argc++;
1106                        }
1107                }
1108        }
1109
1110    // check command
1111        if (argc == 0)
1112    {
1113        // release semaphore to get next command
1114        sem_post( &semaphore );
1115    }
1116
1117#if DEBUG_EXECUTE
1118printf("\n[ksh] %s : argc %d / arg0 %s / arg1 %s\n",
1119__FUNCTION__ , argc , argv[0], argv[1] );
1120#endif
1121
1122    // scan the list of commands to match typed command
1123    int found = 0;
1124    for ( i = 0 ; (command[i].name != NULL) && (found == 0) ; i++ )
1125    {
1126        if (strcmp(argv[0], command[i].name) == 0)
1127        {
1128                        command[i].fn(argc, argv);
1129                        found = 1;
1130                }
1131    }
1132
1133    // check undefined command
1134        if (!found) 
1135    {   
1136        printf("  error : undefined command <%s>\n", argv[0]);
1137
1138        // release semaphore to get next command
1139        sem_post( &semaphore );
1140        }
1141}  // end execute()
1142
1143///////////////////////////////
1144static void interactive( void )
1145{
1146        char           c;                                               // read character
1147    unsigned int   end_command;             // last character found in a command
1148        unsigned int   count;                   // pointer in command buffer
1149        unsigned int   i;                                               // index for loops
1150        unsigned int   state;                   // escape sequence state
1151
1152        char           cmd[CMD_MAX_SIZE];               // buffer for one command
1153
1154#if DEBUG_INTER
1155char string[128];
1156#endif
1157
1158/*
1159// To lauch one or several commands without interactive mode
1160
1161// 1. first command
1162if( sem_wait( &semaphore ) )
1163{
1164    printf("\n[ksh error] cannot found semafore\n" );
1165    exit( 1 );
1166}
1167else
1168{
1169    printf("\n[ksh] load bin/user/pgcd.elf\n");
1170}
1171
1172strcpy( cmd , "load bin/user/pgcd.elf" );
1173execute( cmd );
1174
1175// 2. second command
1176if( sem_wait( &semaphore ) )
1177{
1178    printf("\n[ksh error] cannot found semafore\n" );
1179    exit( 1 );
1180}
1181else
1182{
1183    printf("\n[ksh] ls home\n");
1184}
1185
1186strcpy( cmd , "ls home" );
1187execute( cmd );
1188
1189// end non-interactive mode
1190*/
1191
1192        enum fsm_states
1193    {
1194                NORMAL = 0,
1195                ESCAPE = 1,
1196                BRAKET = 2,
1197        };
1198
1199        // This lexical analyser writes one command line in the command buffer.
1200        // It is implemented as a 3 states FSM to handle the following escape sequences:
1201        // - ESC [ A : up arrow
1202        // - ESC [ B : down arrow
1203        // - ESC [ C : right arrow
1204        // - ESC [ D : left arrow
1205        // The three states have the following semantic:
1206        // - NORMAL : no (ESC) character has been found
1207        // - ESCAPE : the character (ESC) has been found
1208        // - BRAKET : the wo characters (ESC,[) have been found
1209
1210    // take the semaphore for the first command
1211    if ( sem_wait( &semaphore ) )
1212    {
1213        printf("\n[ksh error] cannot found semafore\n" );
1214        exit( 1 );
1215    }
1216
1217    // display prompt for the first command
1218    printf("\n[ksh] ");
1219
1220    // external loop on the commands / the interactive thread do not exit this loop
1221        while (1)
1222        {
1223            // initialize command buffer
1224            // memset( cmd , 0x20 , sizeof(cmd) );   // TODO useful ?
1225            count       = 0;
1226            state       = NORMAL;
1227        end_command = 0;
1228
1229#if DEBUG_INTER
1230unsigned int pid = getpid();
1231snprintf( string , 128 , "\n[ksh] %s : request a new command", __FUNCTION__ );
1232display_string( string );
1233#endif
1234
1235        // internal loop on characters in one command
1236        while( end_command == 0 )
1237        {
1238            // get one character from TXT_RX
1239                c = (char)getchar();
1240
1241            if( c == 0 ) continue;
1242
1243                    if( state == NORMAL )  // we are not in an escape sequence
1244                    {
1245                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1246                                {
1247                                    if (count > 0)
1248                    {
1249                                        printf("\b \b");
1250                                        count--;
1251                                    }
1252                                }
1253                                else if (c == '\n')                  // new line => end of command
1254                                {
1255                                    if (count > 0)               // analyse & execute command
1256                                    {
1257                                            // complete command with NUL character
1258                                            cmd[count] = 0;
1259                        count++;
1260#if DEBUG_INTER
1261snprintf( string , 128 , "[ksh] %s : get command <%s> / &log = %x / ptw = %d / &ptw = %x",
1262__FUNCTION__, cmd , log_entries[ptw].buf , ptw , &ptw );
1263display_string( string );
1264display_vmm( 0 , 2 );
1265#endif
1266                        // register command in log_entries[] array
1267                                            strncpy( log_entries[ptw].buf , cmd , count );
1268                                            log_entries[ptw].count = count;
1269                                            ptw = (ptw + 1) % LOG_DEPTH;
1270                                            ptr = ptw;
1271
1272#if DEBUG_INTER
1273snprintf( string , 128 , "[ksh] %s : execute <%s>", __FUNCTION__, cmd );
1274display_string( string );
1275#endif
1276                        // echo character
1277                        putchar( c );
1278
1279                                            // execute command
1280                                            execute( cmd );
1281                                    }
1282                    else                         // no command registered
1283                    {
1284                        // release semaphore to get next command
1285                        sem_post( &semaphore );
1286                    }
1287
1288                    // exit internal loop on characters
1289                    end_command = 1;
1290                }
1291                            else if (c == '\t')             // tabulation => do nothing
1292                                {
1293                            }
1294                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1295                            {
1296                    state = ESCAPE;
1297                            }
1298                            else                                               // normal character
1299                                {
1300                                    if (count < (sizeof(cmd) - 1) )
1301                                    {
1302                        // register character in command buffer
1303                                            cmd[count] = c;
1304                                            count++;
1305
1306                        // echo character
1307                        putchar( c );
1308                                        }
1309                    else
1310                    {
1311                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1312                    }
1313                                }
1314                        }
1315                        else if( state == ESCAPE ) 
1316                        {
1317                                if (c == '[')           //  valid sequence => continue
1318                                {
1319                                        state = BRAKET;
1320                                }
1321                                else                               // invalid sequence => do nothing
1322                                {
1323                                        state = NORMAL;
1324                                }
1325                        }
1326                        else if( state == BRAKET )
1327                        {
1328                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
1329                                {
1330                                        if (count > 0)
1331                                        {
1332                                                printf("\b");
1333                                                count--;
1334                                        }
1335
1336                                        // get next user char
1337                                        state = NORMAL;
1338                                }
1339                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
1340                                {
1341                                        if (count < sizeof(cmd) - 1)
1342                                        {
1343                                                printf("%c", cmd[count]);
1344                                                count++;
1345                                        }
1346
1347                                        // get next user char
1348                                        state = NORMAL;
1349                                }
1350                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1351                                {
1352                                        // cancel current command
1353                                        for (i = 0; i < count; i++) printf("\b \b");
1354                                        count = 0;
1355
1356                                        // copy log command into cmd
1357                                        ptr = (ptr - 1) % LOG_DEPTH;
1358                                        strcpy(cmd, log_entries[ptr].buf);
1359                                        count = log_entries[ptr].count - 1;
1360
1361                                        // display log command
1362                                        printf("%s", cmd);
1363
1364                                        // get next user char
1365                                        state = NORMAL;
1366                                }
1367                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1368                                {
1369                                        // cancel current command
1370                                        for (i = 0 ; i < count; i++) printf("\b \b");
1371                                        count = 0;
1372
1373                                        // copy log command into cmd
1374                                        ptr = (ptr + 1) % LOG_DEPTH;
1375                                        strcpy(cmd, log_entries[ptr].buf);
1376                                        count = log_entries[ptr].count;
1377
1378                                        // display log command
1379                                        printf("%s", cmd);
1380
1381                                        // get next user char
1382                                        state = NORMAL;
1383                                }
1384                                else                               // other character => do nothing
1385                                {
1386                                        // get next user char
1387                                        state = NORMAL;
1388                                }
1389                        }
1390                }  // end internal while loop on characters
1391
1392#if DEBUG_INTER
1393snprintf( string , 128 , "\n[ksh] %s : complete <%s> command", __FUNCTION__, cmd );
1394display_string( string );
1395#endif
1396
1397        // block interactive thread if KSH loose TXT ownership
1398        if ( sem_wait( &semaphore ) )
1399        {
1400            printf("\n[ksh error] cannot found semafore\n" );
1401            exit( 1 );
1402        }
1403
1404        // display prompt for next command
1405        printf("\n[ksh] ");
1406
1407        }  // end external while loop on commands
1408
1409}  // end interactive()
1410
1411////////////////
1412int main( void )
1413{
1414    unsigned int cxy;             // owner cluster identifier for this KSH process
1415    unsigned int lid;             // core identifier for this KSH main thread
1416    int          status;          // child process termination status
1417    int          child_pid;       // child process identifier
1418    int          parent_pid;      // parent process identifier (i.e. this process)
1419    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1420
1421    // initialize log buffer
1422        memset( &log_entries , 0, sizeof(log_entries));
1423        ptw   = 0;
1424        ptr   = 0;
1425
1426    // get KSH process pid and core
1427    parent_pid = getpid();
1428    get_core( &cxy , &lid );
1429
1430#if DEBUG_MAIN
1431printf("\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1432#endif
1433   
1434    // initializes the semaphore used to synchronize with interactive thread
1435    if ( sem_init( &semaphore , 0 , 1 ) )
1436    {
1437        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1438        exit( 1 ); 
1439    }
1440
1441#if DEBUG_MAIN
1442printf("\n[ksh] main initialized semaphore\n" ); 
1443#endif
1444   
1445    // initialize interactive thread attributes
1446    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1447    attr.cxy        = cxy;
1448
1449    // lauch the interactive thread
1450    pthread_create( &trdid,
1451                    &attr,
1452                    &interactive,   // entry function
1453                    NULL ); 
1454#if DEBUG_MAIN
1455printf("\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1456#endif
1457
1458    // signal INIT process
1459    kill( 1 , SIGCONT );
1460   
1461    // enter infinite loop monitoring children processes termination
1462    while( 1 )
1463    {
1464        // wait children termination
1465        child_pid = wait( &status );
1466
1467#if DEBUG_MAIN
1468if( WIFEXITED  (status) ) printf("\n[ksh] child process %x exit\n"   , child_pid );
1469if( WIFSIGNALED(status) ) printf("\n[ksh] child process %x killed\n" , child_pid );
1470if( WIFSTOPPED (status) ) printf("\n[ksh] child process %x stopped\n", child_pid );
1471#endif
1472
1473        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1474        is_fg( parent_pid , &is_owner );
1475        if( is_owner ) sem_post( &semaphore );
1476    }
1477}  // end main()
1478
1479
Note: See TracBrowser for help on using the repository browser.