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

Last change on this file was 796, checked in by alain, 9 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.