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

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

Fix several bugs in vfs.c, fatfs.c, and devfs.c to support
the <.> and <..> directory entries.

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