/////////////////////////////////////////////////////////////////////////////////////// // File : shell.c // Date : july 2015 // authors : Clément Guérin and Alain Greiner /////////////////////////////////////////////////////////////////////////////////////// // Simple shell for the GIET_VM. /////////////////////////////////////////////////////////////////////////////////////// #include "stdio.h" #include "stdlib.h" #include "malloc.h" #include "string.h" #define BUF_SIZE (256) // buffer for one command #define MAX_ARGS (32) // max number of arguments in a command #define FIFO_SIZE (1024) // FIFO depth for recursive ls struct command_t { char *name; char *desc; void (*fn)(int, char**); }; //////////////////////////////////////////////////////////////////////////////// // Shell Commands //////////////////////////////////////////////////////////////////////////////// struct command_t cmd[]; /////////////////////////////////////////// static void cmd_help(int argc, char** argv) { int i; giet_tty_printf("available commands:\n"); for (i = 0; cmd[i].name; i++) { giet_tty_printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc ); } } /////////////////////////////////////////// static void cmd_time(int argc, char** argv) { giet_tty_printf(" cycle = %d\n", giet_proctime()); } ///////////////////////////////////////// static void cmd_ls(int argc, char** argv) { fat_dirent_t entry; unsigned int recursive; char* paths[FIFO_SIZE]; unsigned int ptr = 0; unsigned int ptw = 0; // analyse arguments if (argc == 2) { // allocate a buffer for root directory // pathname, and push it in FIFO paths[ptw] = malloc( strlen(argv[1]) ); strcpy( paths[ptw] , argv[1] ); ptw = (ptw + 1) % FIFO_SIZE; // not recursive recursive = 0; } else if ( (argc == 3) && (strcmp( argv[1] , "-r" ) == 0) ) { // allocate a buffer for root directory // pathname, and push it in FIFO paths[ptw] = malloc( strlen(argv[2]) ); strcpy( paths[ptw] , argv[2] ); ptw = (ptw + 1) % FIFO_SIZE; // recursive recursive = 1; } else { giet_tty_printf(" usage : ls [-r] pathname\n"); return; } // loop on registered directories do { // open directory int fd = giet_fat_opendir( paths[ptr] ); if (fd < 0) { giet_tty_printf(" error : cannot open %s\n", paths[ptr] ); return; } // display directory pathname giet_tty_printf("*** %s ***\n", paths[ptr] ); // loop on directory entries while (giet_fat_readdir(fd, &entry) == 0) { // display entry if ( entry.is_dir ) giet_tty_printf("dir "); else giet_tty_printf("file"); giet_tty_printf(" | size = %d \t| cluster = %x \t| %s\n", entry.size, entry.cluster, entry.name ); // allocate a buffer for subdirectory pathname // and push it in FIFO if required if ( entry.is_dir && recursive && ( strcmp( entry.name , "." ) != 0 ) && ( strcmp( entry.name , ".." ) != 0 ) ) { // check FIFO full if ( ((ptr - ptw) % FIFO_SIZE) == 1 ) { giet_tty_printf(" sorry, not enough memory for recursive ls\n"); return; } unsigned int length = strlen(paths[ptr]) + strlen(entry.name) + 2; paths[ptw] = malloc( length ); if ( strcmp( paths[ptr] , "/" ) == 0 ) { snprintf( paths[ptw] , length , "/%s" , entry.name ); } else { snprintf( paths[ptw] , length , "%s/%s" , paths[ptr] , entry.name ); } ptw = (ptw + 1) % FIFO_SIZE; } } // end loop on entries // close directory giet_fat_closedir(fd); // release the directory pathname buffer // and pop it from FIFO free( paths[ptr] ); ptr = (ptr + 1) % FIFO_SIZE; } while ( ptr != ptw ); } // end cmd_ls() //////////////////////////////////////////// static void cmd_mkdir(int argc, char** argv) { if (argc < 2) { giet_tty_printf(" usage : mkdir pathname\n"); return; } int ret = giet_fat_mkdir(argv[1]); if (ret < 0) { giet_tty_printf(" error : cannot create directory %s / err = %d\n", argv[1], ret); } } ///////////////////////////////////////// static void cmd_cp(int argc, char** argv) { if (argc < 3) { giet_tty_printf(" usage : cp src_pathname dst_pathname>\n"); return; } char buf[1024]; int src_fd = -1; int dst_fd = -1; fat_file_info_t info; int size; int i; src_fd = giet_fat_open( argv[1] , O_RDONLY ); if (src_fd < 0) { giet_tty_printf(" error : cannot open %s / err = %d\n", argv[1], src_fd); goto exit; } giet_fat_file_info(src_fd, &info); if (info.is_dir) { giet_tty_printf(" error : %s is a directory\n", argv[1] ); goto exit; } size = info.size; dst_fd = giet_fat_open( argv[2] , O_CREAT | O_TRUNC); if (dst_fd < 0) { giet_tty_printf(" error : cannot open %s / err = %d\n", argv[2], dst_fd); goto exit; } giet_fat_file_info(dst_fd, &info); if (info.is_dir) { giet_tty_printf(" error : %s is a directory\n", argv[2] ); // TODO goto exit; } i = 0; while (i < size) { int len = (size - i < 1024 ? size - i : 1024); int wlen; len = giet_fat_read(src_fd, &buf, len); wlen = giet_fat_write(dst_fd, &buf, len); if (wlen != len) { giet_tty_printf(" error : cannot write on device\n"); goto exit; } i += len; } exit: if (src_fd >= 0) giet_fat_close(src_fd); if (dst_fd >= 0) giet_fat_close(dst_fd); } ///////////////////////////////////////// static void cmd_rm(int argc, char **argv) { if (argc < 2) { giet_tty_printf(" usage : rm pathname\n"); return; } int ret = giet_fat_remove(argv[1], 0); if (ret < 0) { giet_tty_printf(" error : cannot remove %s / err = %d\n", argv[1], ret ); } } //////////////////////////////////////////// static void cmd_rmdir(int argc, char **argv) { if (argc < 2) { giet_tty_printf(" usage : rmdir pathname\n"); return; } int ret = giet_fat_remove(argv[1], 1); if (ret < 0) { giet_tty_printf(" error : cannot remove %s / err = %d\n", argv[1], ret ); } } ///////////////////////////////////////// static void cmd_mv(int argc, char **argv) { if (argc < 3) { giet_tty_printf(" usage : %s src_pathname dst_pathname\n", argv[0]); return; } int ret = giet_fat_rename(argv[1], argv[2]); if (ret < 0) { giet_tty_printf("error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret ); } } /////////////////////////////////////////// static void cmd_exec(int argc, char **argv) { if (argc < 2) { giet_tty_printf(" usage : %s vspace_name\n", argv[0]); return; } int ret = giet_exec_application(argv[1]); if ( ret == -1 ) { giet_tty_printf(" error : %s not found\n", argv[1] ); } } /////////////////////////////////////////// static void cmd_kill(int argc, char **argv) { if (argc < 2) { giet_tty_printf(" usage : %s vspace_name\n", argv[0]); return; } int ret = giet_kill_application(argv[1]); if ( ret == -1 ) { giet_tty_printf(" error : %s not found\n", argv[1] ); } if ( ret == -2 ) { giet_tty_printf(" error : %s cannot be killed\n", argv[1] ); } } ///////////////////////////////////////// static void cmd_ps(int argc, char** argv) { if (argc == 1) { giet_applications_status( NULL ); } else { giet_applications_status( argv[1] ); } } //////////////////////////////////////////// static void cmd_pause(int argc, char** argv) { if (argc < 3) { giet_tty_printf(" usage : %s vspace_name thread_name\n", argv[0] ); return; } giet_pthread_control( THREAD_CMD_PAUSE , argv[1] , argv[2] ); } ///////////////////////////////////////////// static void cmd_resume(int argc, char** argv) { if (argc < 3) { giet_tty_printf(" usage : %s vspace_name thread_name\n", argv[0] ); return; } giet_pthread_control( THREAD_CMD_RESUME , argv[1] , argv[2] ); } ///////////////////////////////////////////// static void cmd_context(int argc, char** argv) { if (argc < 3) { giet_tty_printf(" usage : %s vspace_name thread_name\n", argv[0] ); return; } giet_pthread_control( THREAD_CMD_CONTEXT , argv[1] , argv[2] ); } ///////////////////////////////////////////// static void cmd_cat(int argc, char** argv) { if (argc != 2) { giet_tty_printf(" usage : cat pathname \n"); return; } unsigned int x,y,p; // processor coordinates unsigned int fd; // file descriptor fat_file_info_t info; // file info unsigned int size; // buffer size (file_size + 1) unsigned int bytes; // number of bytes to be mapped char* buf = NULL; // temporary buffer // get processor coordinates giet_proc_xyp( &x , &y , &p ); // open the file to display fd = giet_fat_open( argv[1] , 0 ); if (fd < 0) { giet_tty_printf(" error : cannot open %s\n", argv[1]); goto exit; } // get file size giet_fat_file_info( fd, &info ); if ( info.is_dir ) { giet_tty_printf(" error : %s is a directory\n", argv[1] ); goto exit; } size = info.size; // extend size to 4 Kbytes boundary if required if ( (size+1) & 0xFFF) bytes = (size & 0xFFFFF000) + 0x1000; else bytes = size + 1; // map local buffer to Cache_file buf = giet_fat_mmap( NULL, bytes, MAP_PROT_READ | MAP_PROT_WRITE, MAP_SHARED, fd, 0 ); if ( buf == NULL ) { giet_tty_printf(" error : cannot map %s\n", argv[1] ); goto exit; } // set terminating '0' buf[size] = 0; // display the file content giet_tty_printf("%s", buf ); exit: if ( fd >= 0 ) giet_fat_close( fd ); if ( buf != NULL ) giet_fat_munmap( buf , bytes ); } /////////////////////////////////////////// static void cmd_dump(int argc, char** argv) { if ((argc == 2) && (strcmp( argv[1] , "-bs" ) == 0)) { giet_fat_dump( DUMP_BS , NULL , 0 ); } else if ((argc == 2) && (strcmp( argv[1] , "-fs" ) == 0)) { giet_fat_dump( DUMP_FS , NULL , 0 ); } else if ((argc == 3) && (strcmp( argv[1] , "-fat" ) == 0)) { giet_fat_dump( DUMP_FAT , NULL , atoi( argv[2] ) ); } else if ((argc == 4) && (strcmp( argv[1] , "-file" ) == 0)) { giet_fat_dump( DUMP_FILE , argv[2] , atoi( argv[3] ) ); } else if ((argc == 4) && (strcmp( argv[1] , "-dir" ) == 0)) { giet_fat_dump( DUMP_DIR , argv[2] , atoi( argv[3] ) ); } else { giet_tty_printf(" usage : dump [-bs] [-fs] [-fat block] " "[-file pathname block] [-dir pathname block]\n"); return; } } //////////////////////////////////////////////////////////////////// struct command_t cmd[] = { { "cat", "display file content", cmd_cat }, { "context", "display a thread context", cmd_context }, { "cp", "replicate a file in file system", cmd_cp }, { "dump", "display content of disk sector", cmd_dump }, { "exec", "start an application", cmd_exec }, { "help", "list available commands", cmd_help }, { "kill", "kill an application (all threads)", cmd_kill }, { "ls", "list content of a directory", cmd_ls }, { "mkdir", "create a new directory", cmd_mkdir }, { "mv", "move a file in file system", cmd_mv }, { "pause", "pause a thread", cmd_pause }, { "ps", "list all mapped applications status", cmd_ps }, { "resume", "resume a thread", cmd_resume }, { "rm", "remove a file from file system", cmd_rm }, { "rmdir", "remove a directory from file system", cmd_rmdir }, { "time", "return current date", cmd_time }, { NULL, NULL, NULL } }; // shell /////////////////////////////////////////////////////////////////// // This function analyses one command (with arguments) /////////////////////////////////////////////////////////////////// static void parse(char *buf) { int argc = 0; char* argv[MAX_ARGS]; int i; int len = strlen(buf); // build argc/argv for (i = 0; i < len; i++) { if (buf[i] == ' ') { buf[i] = '\0'; } else if (i == 0 || buf[i - 1] == '\0') { if (argc < MAX_ARGS) { argv[argc] = &buf[i]; argc++; } } } if (argc > 0) { int found = 0; // try to match typed command with built-ins for (i = 0; cmd[i].name; i++) { if (strcmp(argv[0], cmd[i].name) == 0) { // invoke cmd[i].fn(argc, argv); found = 1; break; } } if (!found) { giet_tty_printf("undefined command %s\n", argv[0]); } } } //////////////////// static void prompt() { giet_tty_printf("# "); } ////////////////////////////////////////// __attribute__ ((constructor)) void main() ////////////////////////////////////////// { char c; char buf[BUF_SIZE]; int count = 0; // get a private TTY giet_tty_alloc( 0 ); giet_tty_printf( "~~~ shell ~~~\n\n" ); // heap initialisation unsigned int x_id; // x cluster coordinate unsigned int y_id; // y cluster coordinate unsigned int p_id; // local processor index giet_proc_xyp( &x_id , &y_id , &p_id ); heap_init( x_id , y_id ); // display first prompt prompt(); while (1) { giet_tty_getc(&c); switch (c) { case '\b': // backspace if (count > 0) { giet_tty_printf("\b \b"); count--; } break; case '\n': // new line giet_tty_printf("\n"); if (count > 0) { buf[count] = '\0'; parse((char*)&buf); } prompt(); count = 0; break; case '\t': // tabulation // do nothing break; case '\03': // ^C giet_tty_printf("^C\n"); prompt(); count = 0; break; default: // regular character if (count < sizeof(buf) - 1) { giet_tty_printf("%c", c); buf[count] = c; count++; } } } } // end main() // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4