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

Last change on this file since 676 was 676, checked in by alain, 3 years ago

Introduce chat application to test the named pipes.

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