source: soft/giet_vm/applications/shell/shell.c @ 796

Last change on this file since 796 was 796, checked in by alain, 10 years ago

Introduce support for the DEL character in in the shell lexical analyser.

File size: 22.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////
2// File    : shell.c   
3// Date    : july 2015
4// authors : Clément Guérin and Alain Greiner
5///////////////////////////////////////////////////////////////////////////////////////
6// Simple shell for the GIET_VM.
7///////////////////////////////////////////////////////////////////////////////////////
8
9#include "stdio.h"
10#include "stdlib.h"
11#include "malloc.h"
12#include "string.h"
13
14#define MAX_SIZE    (128)        // max number of characters in one command
15#define LOG_DEPTH   (128)        // max number of commands in log
16#define MAX_ARGS    (32)         // max number of arguments in a command
17#define FIFO_SIZE   (1024)       // FIFO depth for recursive ls
18
19////////////////////////////////////////////////////////////////////////////////
20//       Global Variables
21////////////////////////////////////////////////////////////////////////////////
22
23char         log_buf[LOG_DEPTH][MAX_SIZE];   // registered command strings
24unsigned int log_count[LOG_DEPTH];           // registered command lengths
25unsigned int ptw;                            // write pointer in log
26unsigned int ptr;                            // read pointer in log
27
28struct command_t
29{
30    char *name;
31    char *desc;
32    void (*fn)(int, char**);
33};
34
35// this array initialised afer commands definition
36struct command_t cmd[];
37
38////////////////////////////////////////////////////////////////////////////////
39//       Shell  Commands
40////////////////////////////////////////////////////////////////////////////////
41
42/////////////////////////////////////////////
43static void cmd_cat(int argc, char** argv)
44{
45    if (argc != 2)
46    {
47        giet_tty_printf("  usage : cat pathname \n");
48        return;
49    }
50
51    unsigned int     x,y,p;          // processor coordinates
52    unsigned int     fd;             // file descriptor
53    fat_file_info_t  info;           // file info
54    unsigned int     size;           // buffer size (file_size + 1)
55    unsigned int     bytes;          // number of bytes to be mapped 
56    char*            buf = NULL;     // temporary buffer
57
58    // get processor coordinates
59    giet_proc_xyp( &x , &y , &p );
60   
61    // open the file to display   
62    fd = giet_fat_open( argv[1] , 0 );
63    if (fd < 0)
64    {
65        giet_tty_printf("  error : cannot open %s\n", argv[1]);
66        goto exit;
67    }
68
69    // get file size
70    giet_fat_file_info( fd, &info );
71    if ( info.is_dir )
72    {
73        giet_tty_printf("  error : %s is a directory\n", argv[1] );
74        goto exit;
75    }
76    size = info.size; 
77
78    // extend size to 4 Kbytes boundary if required
79    if ( (size+1) & 0xFFF)  bytes = (size & 0xFFFFF000) + 0x1000;
80    else                    bytes = size + 1;
81
82    // map local buffer to Cache_file
83    buf = giet_fat_mmap( NULL,
84                         bytes,
85                         MAP_PROT_READ | MAP_PROT_WRITE, 
86                         MAP_SHARED,
87                         fd,
88                         0 ); 
89    if ( buf == NULL )
90    {
91        giet_tty_printf("  error : cannot map %s\n", argv[1] );
92        goto exit;
93    }
94
95    // set terminating '0'
96    buf[size] = 0;
97
98    // display the file content
99    giet_tty_printf("%s", buf );
100
101exit:
102    if ( fd >= 0 )     giet_fat_close( fd );
103    if ( buf != NULL ) giet_fat_munmap( buf , bytes );
104}  // end cmd_cat()
105
106/////////////////////////////////////////////
107static void cmd_context(int argc, char** argv)
108{
109    if (argc < 3)
110    {
111        giet_tty_printf("  usage : %s vspace_name thread_name\n", argv[0] );
112        return;
113    }
114
115    giet_pthread_control( THREAD_CMD_CONTEXT , argv[1] , argv[2] );
116}  // end cmd_context()
117
118/////////////////////////////////////////
119static void cmd_cp(int argc, char** argv)
120{
121    if (argc < 3)
122    {
123        giet_tty_printf("  usage : cp src_pathname dst_pathname>\n");
124        return;
125    }
126
127    char buf[1024];
128    int src_fd = -1;
129    int dst_fd = -1;
130    fat_file_info_t info;
131    int size;
132    int i;
133
134    src_fd = giet_fat_open( argv[1] , O_RDONLY );
135    if (src_fd < 0)
136    {
137        giet_tty_printf("  error : cannot open %s / err = %d\n", argv[1], src_fd);
138        goto exit;
139    }
140
141    giet_fat_file_info(src_fd, &info);
142
143    if (info.is_dir)
144    {
145        giet_tty_printf("  error : %s is a directory\n", argv[1] );
146        goto exit;
147    }
148
149    size = info.size;
150
151    dst_fd = giet_fat_open( argv[2] , O_CREAT | O_TRUNC);
152
153    if (dst_fd < 0)
154    {
155        giet_tty_printf("  error : cannot open %s / err = %d\n", argv[2], dst_fd);
156        goto exit;
157    }
158
159    giet_fat_file_info(dst_fd, &info);
160
161    if (info.is_dir)
162    {
163        giet_tty_printf("  error : %s is a directory\n", argv[2] );  // TODO
164        goto exit;
165    }
166
167    i = 0;
168    while (i < size)
169    {
170        int len = (size - i < 1024 ? size - i : 1024);
171        int wlen;
172
173        len = giet_fat_read(src_fd, &buf, len);
174        wlen = giet_fat_write(dst_fd, &buf, len);
175        if (wlen != len)
176        {
177            giet_tty_printf("  error : cannot write on device\n");
178            goto exit;
179        }
180        i += len;
181    }
182
183exit:
184    if (src_fd >= 0)
185        giet_fat_close(src_fd);
186    if (dst_fd >= 0)
187        giet_fat_close(dst_fd);
188}  // end cmd_cp()
189
190///////////////////////////////////////////
191static void cmd_dump(int argc, char** argv)
192{
193    if ((argc == 2) && (strcmp( argv[1] , "-bs" ) == 0))
194    {
195        giet_fat_dump( DUMP_BS , NULL , 0 );
196    }
197    else if ((argc == 2) && (strcmp( argv[1] , "-fs" ) == 0))
198    {
199        giet_fat_dump( DUMP_FS , NULL , 0 );
200    }
201    else if ((argc == 3) && (strcmp( argv[1] , "-fat" ) == 0))
202    {
203        giet_fat_dump( DUMP_FAT , NULL , atoi( argv[2] ) );
204    }
205    else if ((argc == 4) && (strcmp( argv[1] , "-file" ) == 0))
206    {
207        giet_fat_dump( DUMP_FILE , argv[2] , atoi( argv[3] ) );
208    }
209    else if ((argc == 4) && (strcmp( argv[1] , "-dir" ) == 0))
210    {
211        giet_fat_dump( DUMP_DIR , argv[2] , atoi( argv[3] ) );
212    }
213    else
214    {
215        giet_tty_printf("  usage : dump [-bs] [-fs] [-fat block] "
216                        "[-file pathname block] [-dir pathname block]\n");
217        return;
218    }
219}  // end cmd_dump()
220
221///////////////////////////////////////////
222static void cmd_exec(int argc, char **argv)
223{
224    if (argc < 2)
225    {
226        giet_tty_printf("  usage : %s vspace_name\n", argv[0]);
227        return;
228    }
229
230    int ret = giet_exec_application(argv[1]);
231    if ( ret == -1 )
232    {
233        giet_tty_printf("  error : %s not found\n", argv[1] );
234    }
235}  // end cmd_exec()
236
237///////////////////////////////////////////
238static void cmd_help(int argc, char** argv)
239{
240    int i;
241
242    giet_tty_printf("available commands:\n");
243
244    for (i = 0; cmd[i].name; i++)
245    {
246        giet_tty_printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc );
247    }
248}  // end cmd_help()
249
250///////////////////////////////////////////
251static void cmd_kill(int argc, char **argv)
252{
253    if (argc < 2)
254    {
255        giet_tty_printf("  usage : %s vspace_name\n", argv[0]);
256        return;
257    }
258
259    int ret = giet_kill_application(argv[1]);
260    if ( ret == -1 )
261    {
262        giet_tty_printf("  error : %s not found\n", argv[1] );
263    }
264    if ( ret == -2 )
265    {
266        giet_tty_printf("  error : %s cannot be killed\n", argv[1] );
267    }
268}  // end cmd_kill()
269
270///////////////////////////////////////////
271static void cmd_log( int argc, char** argv)
272{
273    giet_tty_printf("--- registered commands ---\n");
274    unsigned int i;
275    for ( i = 0 ; i < LOG_DEPTH ; i++ )
276    {
277        giet_tty_printf(" - %d\t: %s\n", i , &log_buf[i][0] );
278    }
279}  // end cmd_log()
280
281/////////////////////////////////////////
282static void cmd_ls(int argc, char** argv)
283{
284    fat_dirent_t    entry;
285    unsigned int    recursive;
286    char*           paths[FIFO_SIZE];
287    unsigned int    ptr = 0;
288    unsigned int    ptw = 0;
289
290    // analyse arguments
291    if (argc == 2)
292    {
293        // allocate a buffer for root directory
294        // pathname, and push it in FIFO
295        paths[ptw] = malloc( strlen(argv[1]) );
296        strcpy( paths[ptw] , argv[1] );
297        ptw = (ptw + 1) % FIFO_SIZE;
298
299        // not recursive
300        recursive = 0;
301    }
302    else if ( (argc == 3) && (strcmp( argv[1] , "-r" ) == 0) )
303    {
304        // allocate a buffer for root directory
305        // pathname, and push it in FIFO
306        paths[ptw] = malloc( strlen(argv[2]) );
307        strcpy( paths[ptw] , argv[2] );
308        ptw = (ptw + 1) % FIFO_SIZE;
309
310        // recursive
311        recursive = 1;
312    }
313    else
314    {
315        giet_tty_printf("  usage : ls [-r] pathname\n");
316        return;
317    }
318
319    // loop on registered directories
320    do
321    {
322        // open directory
323        int fd  = giet_fat_opendir( paths[ptr] );
324        if (fd < 0)
325        {
326            giet_tty_printf("  error : cannot open %s\n", paths[ptr] );
327            return;
328        }
329
330        // display directory pathname
331        giet_tty_printf("--- %s ---\n", paths[ptr] );
332
333        // loop on directory entries
334        while (giet_fat_readdir(fd, &entry) == 0)
335        {
336            // display entry
337            if ( entry.is_dir ) giet_tty_printf("dir ");
338            else                giet_tty_printf("file");
339            giet_tty_printf(" | size = %d \t| cluster = %x \t| %s\n",
340                            entry.size, entry.cluster, entry.name );
341
342            // allocate a buffer for subdirectory pathname
343            // and push it in FIFO if required
344            if ( entry.is_dir && recursive && 
345                 ( strcmp( entry.name , "." ) != 0 ) && 
346                 ( strcmp( entry.name , ".." ) != 0 ) )
347            {
348                // check FIFO full
349                if ( ((ptr - ptw) % FIFO_SIZE) == 1 )
350                {
351                    giet_tty_printf("   sorry, not enough memory for recursive ls\n");
352                    return;
353                }
354
355                unsigned int length = strlen(paths[ptr]) + strlen(entry.name) + 2;
356                paths[ptw] = malloc( length );
357                if ( strcmp( paths[ptr] , "/" ) == 0 )
358                {
359                    snprintf( paths[ptw] , length , "/%s" , entry.name );
360                }
361                else
362                {
363                    snprintf( paths[ptw] , length , "%s/%s" , paths[ptr] , entry.name );
364                }
365                ptw = (ptw + 1) % FIFO_SIZE;   
366            }
367        }  // end loop on entries
368
369        // close directory
370        giet_fat_closedir(fd);
371
372        // release the directory pathname buffer
373        // and pop it from FIFO
374        free( paths[ptr] );
375        ptr = (ptr + 1) % FIFO_SIZE;
376
377    } while ( ptr != ptw );
378
379}  // end cmd_ls()
380
381////////////////////////////////////////////
382static void cmd_mkdir(int argc, char** argv)
383{
384    if (argc < 2)
385    {
386        giet_tty_printf("  usage : mkdir pathname\n");
387        return;
388    }
389
390    int ret = giet_fat_mkdir(argv[1]);
391
392    if (ret < 0)
393    {
394        giet_tty_printf("  error : cannot create directory %s / err = %d\n", argv[1], ret);
395    }
396}  // end cmd_mkdir()
397
398/////////////////////////////////////////
399static void cmd_mv(int argc, char **argv)
400{
401    if (argc < 3)
402    {
403        giet_tty_printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
404        return;
405    }
406
407    int ret = giet_fat_rename(argv[1], argv[2]);
408    if (ret < 0)
409    {
410        giet_tty_printf("error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret );
411    }
412}  // end cmd_mv()
413
414////////////////////////////////////////////
415static void cmd_pause(int argc, char** argv)
416{
417    if (argc < 3)
418    {
419        giet_tty_printf("  usage : %s vspace_name thread_name\n", argv[0] );
420        return;
421    }
422
423    giet_pthread_control( THREAD_CMD_PAUSE , argv[1] , argv[2] );
424}  // end cmd_pause()
425
426/////////////////////////////////////////
427static void cmd_ps(int argc, char** argv)
428{
429    if (argc == 1)
430    {
431        giet_applications_status( NULL );
432    }
433    else
434    {
435        giet_applications_status( argv[1] );
436    }
437}  // end cmd_ps()
438
439/////////////////////////////////////////////
440static void cmd_resume(int argc, char** argv)
441{
442    if (argc < 3)
443    {
444        giet_tty_printf("  usage : %s vspace_name thread_name\n", argv[0] );
445        return;
446    }
447
448    giet_pthread_control( THREAD_CMD_RESUME , argv[1] , argv[2] );
449}  // end cmd_resume()
450
451/////////////////////////////////////////
452static void cmd_rm(int argc, char **argv)
453{
454    if (argc < 2)
455    {
456        giet_tty_printf("  usage : rm pathname\n");
457        return;
458    }
459
460    int ret = giet_fat_remove(argv[1], 0);
461
462    if (ret < 0)
463    {
464        giet_tty_printf("  error : cannot remove %s / err = %d\n", argv[1], ret );
465    }
466}  // end cmd_rm()
467
468////////////////////////////////////////////
469static void cmd_rmdir(int argc, char **argv)
470{
471    if (argc < 2)
472    {
473        giet_tty_printf("  usage : rmdir pathname\n");
474        return;
475    }
476
477    int ret = giet_fat_remove(argv[1], 1);
478    if (ret < 0)
479    {
480        giet_tty_printf("  error : cannot remove %s / err = %d\n", argv[1], ret );
481    }
482}  // end cmd_rmdir()
483
484///////////////////////////////////////////
485static void cmd_time(int argc, char** argv)
486{
487    giet_tty_printf(" cycle = %d\n", giet_proctime());
488}
489
490
491/////////////////////////////////////////////////////////////////////////////////////
492struct command_t cmd[] =
493{
494    { "cat",        "display file content",                 cmd_cat },
495    { "context",    "display a thread context",             cmd_context },
496    { "cp",         "replicate a file in file system",      cmd_cp },
497    { "dump",       "display content of disk sector",       cmd_dump },
498    { "exec",       "start an application",                 cmd_exec },
499    { "help",       "list available commands",              cmd_help },
500    { "kill",       "kill an application (all threads)",    cmd_kill },
501    { "log",        "list registered commands",             cmd_log },
502    { "ls",         "list directory entries",               cmd_ls },
503    { "mkdir",      "create a new directory",               cmd_mkdir },
504    { "mv",         "move a file in file system",           cmd_mv },
505    { "pause",      "pause a thread",                       cmd_pause },
506    { "ps",         "list all mapped applications status",  cmd_ps },
507    { "resume",     "resume a thread",                      cmd_resume },
508    { "rm",         "remove a file from file system",       cmd_rm },
509    { "rmdir",      "remove a directory from file system",  cmd_rmdir },
510    { "time",       "return current date",                  cmd_time },
511    { NULL,         NULL,                                   NULL }
512};
513/////////////////////////////////////////////////////////////////////////////////////
514
515
516
517
518///////////////////////////////////////////////////////////////////
519// This function analyses one command (with arguments)
520///////////////////////////////////////////////////////////////////
521static void parse(char *buf)
522{
523    int argc = 0;
524    char* argv[MAX_ARGS];
525    int i;
526    int len = strlen(buf);
527
528    // build argc/argv
529    for (i = 0; i < len; i++)
530    {
531        if (buf[i] == ' ')
532        {
533            buf[i] = '\0';
534        }
535        else if (i == 0 || buf[i - 1] == '\0')
536        {
537            if (argc < MAX_ARGS)
538            {
539                argv[argc] = &buf[i];
540                argc++;
541            }
542        }
543    }
544
545    if (argc > 0)
546    {
547        int found = 0;
548
549        // try to match typed command with built-ins
550        for (i = 0; cmd[i].name; i++)
551        {
552            if (strcmp(argv[0], cmd[i].name) == 0)
553            {
554                // invoke
555                cmd[i].fn(argc, argv);
556                found = 1;
557                break;
558            }
559        }
560
561        if (!found)
562        {
563            giet_tty_printf("\n  undefined command %s\n", argv[0]);
564        }
565    }
566} // end parse()
567
568//////////////////////////////////////////
569__attribute__ ((constructor)) void main()
570//////////////////////////////////////////
571{
572    char         c;                              // read character
573    char         buf[MAX_SIZE];                  // buffer for one command
574    unsigned int count = 0;                      // pointer in buf
575    unsigned int i , j;                          // indexes for loops
576
577    enum fsm_states
578    {
579        NORMAL,
580        ESCAPE,
581        BRAKET,
582    };
583
584    // get a private TTY
585    giet_tty_alloc( 0 );
586    giet_tty_printf( "~~~ shell ~~~\n\n" );
587
588    // log_buf initialisation
589    ptw = 0;
590    ptr = 0;
591    for ( i = 0 ; i < LOG_DEPTH ; i++ )
592    {
593        for ( j = 0 ; j < MAX_SIZE ; j++ )
594        {
595            log_buf[i][j] = 0;
596        }
597    }
598
599    // heap initialisation
600    unsigned int x_id;                          // x cluster coordinate
601    unsigned int y_id;                          // y cluster coordinate
602    unsigned int p_id;                          // local processor index
603    giet_proc_xyp( &x_id , &y_id , &p_id );
604    heap_init( x_id , y_id );
605
606    // command buffer initialisation
607    for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
608    count = 0;
609
610    // display first prompt
611    giet_tty_printf("# ");
612
613    // This lexical analyser writes one command line in the buf buffer.
614    // It is implemented as a 3 states FSM to handle the following sequences:
615    // - ESC [ A : up arrow
616    // - ESC [ B : down arrow
617    // - ESC [ C : right arrow
618    // - ESC [ D : left arrow
619    // The thee states have the following semantic:
620    // - NORMAL : no (ESC) character has been found
621    // - ESCAPE : the character (ESC) has been found
622    // - BRAKET : the wo characters (ESC,[) have been found
623    unsigned int state = NORMAL;
624
625    while (1)
626    {
627        giet_tty_getc(&c);
628
629        switch ( state )
630        {
631            case NORMAL:
632            { 
633                if ( (c == '\b') || (c == 0x7F) )  // backspace => remove one character
634                {
635                    if (count > 0)
636                    {
637                        giet_tty_printf("\b \b");
638                        count--;
639                    }
640                }
641                else if ( c == '\n' )     // new line => call parser to execute command
642                {
643                    if (count > 0)
644                    {
645                        // complete commande
646                        buf[count] = '\0';
647
648                        // register command in log arrays       
649                        strcpy( &log_buf[ptw][0] , buf );
650                        log_count[ptw] = count;
651                        ptw = (ptw + 1) % LOG_DEPTH;
652                        ptr = ptw;
653
654                        // execute command
655                        giet_tty_printf("\n");
656                        parse((char*)&buf);
657
658                        // reinitialise buffer and display prompt
659                        for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
660                        count = 0;
661                        giet_tty_printf("# ");
662                    }
663                }
664                else if ( c == '\t' )    // tabulation => do nothing
665                {
666                }
667                else if ( c == 0x1B )    // ESC => start an escape sequence
668                {
669                    state = ESCAPE;
670                }
671                else if ( c == 0x03 )    // ^C  => cancel current command
672                {
673                    for ( i = 0 ; i < count ; i++ ) giet_tty_printf("\b \b");
674                    for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;
675                    count = 0;
676                }
677                else                     // register character in command buffer
678                {
679                    if (count < sizeof(buf) - 1)
680                    {
681                        giet_tty_printf("%c", c);
682                        buf[count] = c;
683                        count++;
684                    }
685                }
686                break;
687            }
688            case ESCAPE:
689            {
690                if ( c == '[' )        //  valid sequence => continue
691                {
692                    state = BRAKET;
693                }
694                else                   // invalid sequence => do nothing
695                {
696                    state = NORMAL;
697                }
698                break;
699            }
700            case BRAKET:
701            {
702                if      ( c == 'D' )   // valid  LEFT sequence => move buf pointer left
703                {
704                    if ( count > 0 )
705                    {
706                        giet_tty_printf("\b");
707                        count--;
708                    }
709
710                    // get next user char
711                    state = NORMAL;
712                }
713                else if ( c == 'C' )   // valid  RIGHT sequence => move buf pointer right
714                {
715                    if ( count < sizeof(buf) - 1)
716                    {
717                        giet_tty_printf("%c", buf[count] );
718                        count++;
719                    }
720
721                    // get next user char
722                    state = NORMAL;
723                }
724                else if ( c == 'A' )   // valid  UP sequence => move log pointer backward
725                {
726                    // cancel current command
727                    for ( i = 0 ; i < count ; i++ ) giet_tty_printf("\b \b");
728                    count = 0;
729
730                    // copy log command into buf
731                    ptr = (ptr - 1) % LOG_DEPTH;
732                    strcpy( buf , &log_buf[ptr][0] );
733                    count = log_count[ptr];
734
735                    // display log command
736                    giet_tty_printf( "%s" , buf );
737
738                    // get next user char
739                    state = NORMAL;
740                }
741                else if ( c == 'B' )   // valid  DOWN sequence => move log pointer forward
742                {
743                    // cancel current command
744                    for ( i = 0 ; i < count ; i++ ) giet_tty_printf("\b \b");
745                    count = 0;
746
747                    // copy log command into buf
748                    ptr = (ptr + 1) % LOG_DEPTH;
749                    strcpy( buf , &log_buf[ptr][0] );
750                    count = log_count[ptr];
751
752                    // display log command
753                    giet_tty_printf( "%s" , buf );
754
755                    // get next user char
756                    state = NORMAL;
757                }
758                else                   // other character => do nothing
759                {
760                    // get next user char
761                    state = NORMAL;
762                }
763                break;
764            }
765        }  // end switch on state 
766    }  // end while
767}  // end main()
768
769// Local Variables:
770// tab-width: 4
771// c-basic-offset: 4
772// c-file-offsets:((innamespace . 0)(inline-open . 0))
773// indent-tabs-mode: nil
774// End:
775// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
776
Note: See TracBrowser for help on using the repository browser.