1/** 2 * \file 3 * \brief fish - Shell commands 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich, 13 * Attn: Systems Group. 14 */ 15 16#define _USE_XOPEN 17 18#include <stdlib.h> 19#include <stdio.h> 20#include <string.h> 21#include <inttypes.h> 22#include <barrelfish/barrelfish.h> 23#include <barrelfish/dispatch.h> 24#include <barrelfish_kpi/init.h> 25#include <barrelfish/debug.h> 26#include <barrelfish/monitor_client.h> 27#include <barrelfish/nameservice_client.h> 28#include <barrelfish/spawn_client.h> 29#include <barrelfish/terminal.h> 30#include <term/client/client_blocking.h> 31#include <trace/trace.h> 32#include <trace_definitions/trace_defs.h> 33#include <skb/skb.h> 34#include <vfs/vfs.h> 35#include <vfs/vfs_path.h> 36#include <if/pixels_defs.h> 37 38#include <if/octopus_defs.h> 39#include <octopus/getset.h> // for oct_read TODO 40#include <octopus/trigger.h> // for NOP_TRIGGER 41#include <octopus/init.h> // oct_init 42 43#include <linenoise/linenoise.h> 44 45#include "fish.h" 46 47#define MAX_LINE 512 48#define BOOTSCRIPT_NAME "/init.fish" 49 50#define ENTRIES(array) (sizeof(array) / sizeof(array[0])) 51 52extern char **environ; 53static struct cmd *find_command(const char *name); 54static int makeargs(char *cmdline, char *argv[]); 55 56typedef int (*Command)(int argc, char *argv[]); 57 58static int spawnpixels(int argc, char *argv[]); 59 60struct cmd { 61 const char *name; 62 Command cmd; 63 const char *usage; 64}; 65 66static char *cwd; 67 68static struct capref inheritcn_cap; 69 70static int help(int argc, char *argv[]); 71 72static int execute_program(coreid_t coreid, int argc, char *argv[], 73 struct capref *ret_domain_cap) 74{ 75 vfs_handle_t vh; 76 errval_t err; 77 78 // if the name contains a directory separator, assume it is relative to PWD 79 char *prog = argv[0]; 80 if (strchr(argv[0], VFS_PATH_SEP) != NULL) { 81 prog = vfs_path_mkabsolute(cwd, argv[0]); 82 83 // check it exists 84 err = vfs_open(prog, &vh); 85 if (err_is_fail(err)) { 86 printf("%s: file not found: %s\n", prog, err_getstring(err)); 87 free(prog); 88 return EXIT_FAILURE; 89 } 90 vfs_close(vh); 91 } 92 93 assert(ret_domain_cap != NULL); 94 95 argv[argc] = NULL; 96 err = spawn_program_with_caps(coreid, prog, argv, NULL, inheritcn_cap, 97 NULL_CAP, SPAWN_FLAGS_NEW_DOMAIN, ret_domain_cap); 98 99 if (prog != argv[0]) { 100 free(prog); 101 } 102 103 if (err_is_fail(err)) { 104 printf("%s: error spawning: %s\n", argv[0], err_getstring(err)); 105 DEBUG_ERR(err, "Spawning Error\n"); 106 return EXIT_FAILURE; 107 } 108 109 return EXIT_SUCCESS; 110} 111 112static int quit(int argc, char *argv[]) 113{ 114 exit(EXIT_SUCCESS); 115 assert(!"exit() returned"); 116 return 255; 117} 118 119static int print_cspace(int argc, char *argv[]) 120{ 121 debug_my_cspace(); 122 return EXIT_SUCCESS; 123} 124 125static int dump_caps(int argc, char *argv[]) { 126 errval_t err; 127 if (argc > 1) { 128 domainid_t domain = strtol(argv[1], NULL, 10); 129 err = spawn_dump_capabilities_compat(domain); 130 } else { 131 dispatcher_handle_t handle = curdispatcher(); 132 struct capref dcb = get_dispatcher_generic(handle)->dcb_cap; 133 err = invoke_dispatcher_dump_capabilities(dcb); 134 } 135 if (err_is_fail(err)) { 136 printf("%s: error dumping capabilities: %s\n", argv[0], err_getstring(err)); 137 DEBUG_ERR(err, "Error\n"); 138 return EXIT_FAILURE; 139 } 140 141 142 return EXIT_SUCCESS; 143} 144 145struct humanreadable { 146 double num; 147 const char *suffix; 148}; 149static struct humanreadable humanify(size_t bytes) 150{ 151 static const char *units[] = {"B", "kB", "MB", "GB", "TB"}; 152 double size = bytes; 153 int i = 0; 154 for (; size > 1024; size /= 1024, i++); 155 return (struct humanreadable){ .num = size, .suffix = units[i] }; 156} 157 158static int measure_pmap_res(int argc, char *argv[]) { 159 errval_t err; 160 struct pmap *p = get_current_pmap(); 161 struct pmap_res_info resbuf; 162 err = p->f.measure_res(p, &resbuf); 163 assert(err_is_ok(err)); 164 struct humanreadable hf; 165 hf = humanify(resbuf.vnode_used); 166 printf("slab bytes in use: %.2lf%s\n", hf.num, hf.suffix); 167 hf = humanify(resbuf.vnode_free); 168 printf("slab bytes free: %.2lf%s\n", hf.num, hf.suffix); 169 printf("capability slots in use: %zu\n", resbuf.slots_used); 170 171 return EXIT_SUCCESS; 172} 173 174static int setenvcmd(int argc, char *argv[]) 175{ 176 if (argc <= 1) { 177 printf("Usage: %s [name=value]...\n", argv[0]); 178 return EXIT_FAILURE; 179 } 180 181 for (int i=1; i < argc; i++) { 182 char *sep = strchr(argv[i], '='); 183 char *value = ""; 184 if (sep != NULL) { 185 *sep = '\0'; // XXX: modify arg inplace 186 value = sep + 1; 187 } 188 int r = setenv(argv[i], value, 1); 189 if (r != 0) { 190 fprintf(stderr, "Error: setenv(%s, %s) failed\n", argv[i], value); 191 return r; 192 } 193 } 194 195 return EXIT_SUCCESS; 196} 197 198static int printenv(int argc, char *argv[]) 199{ 200 if (argc <= 1) { 201 for (int i=0; environ[i] != NULL; i++) { 202 printf("%s\n", environ[i]); 203 } 204 } else { 205 for (int i = 1; i < argc; i++) { 206 char *val = getenv(argv[i]); 207 if (val) { 208 printf("%s\n", val); 209 } 210 } 211 } 212 213 return EXIT_SUCCESS; 214} 215 216static bool pixels_started = false; 217static bool pixels_inited = false; 218static int pixels_connected = 0; 219#define NUM_PIXELS 16 220static struct pixels_binding my_pixels_bindings[NUM_PIXELS]; 221 222static int acks = 0; 223 224static void pixels_ack(struct pixels_binding *cl) 225{ 226 acks--; 227} 228 229static struct pixels_rx_vtbl pixels_vtbl = { 230 .ack = pixels_ack 231}; 232 233static void my_pixels_bind_cb(void *st, errval_t err, struct pixels_binding *b) 234{ 235 struct pixels_binding *pb = (struct pixels_binding *)st; 236 237 if (err_is_fail(err)) { 238 USER_PANIC_ERR(err, "bind failed"); 239 } 240 241 pb->rx_vtbl = pixels_vtbl; 242 pixels_connected++; 243} 244 245static void pixels_init(void) 246{ 247 // ensure pixels is up 248 if (!pixels_started) { 249 printf("Starting pixels...\n"); 250 spawnpixels(0, NULL); 251 } 252 253 pixels_connected = 0; 254 255 for (int core = 0; core < NUM_PIXELS; core ++) { 256 char name[16]; 257 iref_t serv_iref; 258 errval_t err; 259 260 sprintf(name, "pixels.%d", core); 261 262 /* Connect to the server */ 263 err = nameservice_blocking_lookup(name, &serv_iref); 264 if (err_is_fail(err)) { 265 DEBUG_ERR(err, "failed to lookup server"); 266 exit(EXIT_FAILURE); 267 } 268 269 if (serv_iref == 0) { 270 DEBUG_ERR(err, "failed to get a valid iref back from lookup"); 271 exit(EXIT_FAILURE); 272 } 273 274 err = pixels_bind(serv_iref, 275 my_pixels_bind_cb, 276 &my_pixels_bindings[core], 277 get_default_waitset(), 278 IDC_BIND_FLAGS_DEFAULT); 279 if (err_is_fail(err)) { 280 DEBUG_ERR(err, "bind request to pixels server failed immediately"); 281 exit(EXIT_FAILURE); 282 } 283 } 284 285 while (pixels_connected < NUM_PIXELS) 286 messages_wait_and_handle_next(); 287 288 printf("connected to pixels server\n"); 289 pixels_inited = true; 290} 291 292static const char *scroller = "Barrelfish posse in full effect!!! "; 293 294static char c64map(char c) { 295 if ('A' <= c && c <= 'Z') { 296 return 65 + c-'A'; 297 } else if ('a' <= c && c <= 'z') { 298 return 1 + c-'a'; 299 } else if (c == ' ') { 300 return 32; 301 } else if (c == '!') { 302 return 33; 303 } 304 else {return 32;} 305} 306 307extern const char font[]; 308 309#define RENDER_WIDTH 48 310#define PIXEL_WIDTH 100000 311#define FRAMES 10 312 313static int demo(int argc, char *argv[]) 314{ 315 int core; 316 int pixwidth = PIXEL_WIDTH; 317 int frames = FRAMES; 318 319 if (!pixels_inited) pixels_init(); 320 321 if (argc == 3) { 322 pixwidth = atoi(argv[1]); 323 frames = atoi(argv[2]); 324 } 325 int width = 8 * strlen(scroller); 326 327 for (int x = 0; x < width - RENDER_WIDTH; x++) { 328 329 // Repeat each frame a few times to slow down scrolling! 330 for (int f = 0; f < frames; f++) { 331 trace_event(TRACE_SUBSYS_BENCH, TRACE_EVENT_BENCH_PCBENCH, 1); 332 for(int i = 0; i < RENDER_WIDTH; i++) { 333 334 int xpos = (x + i)%width; 335 char ascii = scroller[xpos >> 3]; 336 char c64char = c64map(ascii); 337 int xsub = xpos & 7; 338 339 acks = 0; 340 for (core = 0 ;core < 8; core++) { 341 unsigned char bits = font[c64char*8 + (7-core)]; 342 343 if (bits & (1<<(7-xsub)) ) { 344 345 my_pixels_bindings[core+2].tx_vtbl.display(&my_pixels_bindings[core+2], NOP_CONT, pixwidth); 346 acks++; 347 } 348 } 349 350 uint64_t now = rdtsc(); 351 352 while (acks) { 353 messages_wait_and_handle_next(); 354 } 355 while (rdtsc() - now < pixwidth) ; 356 } 357 358 trace_event(TRACE_SUBSYS_BENCH, TRACE_EVENT_BENCH_PCBENCH, 0); 359 } 360 } 361 return EXIT_SUCCESS; 362} 363 364static int oncore(int argc, char *argv[]) 365{ 366 if(argc < 3) { 367 printf("Usage: %s <core id> <program> [args]\n", argv[0]); 368 return EXIT_FAILURE; 369 } 370 371 int core = atoi(argv[1]); 372 373 argc -= 2; 374 argv += 2; 375 376 struct capref domain_cap; 377 int ret = execute_program(core, argc, argv, &domain_cap); 378 379 // TODO: do something with domain_id 380 381 return ret; 382} 383 384static int spawnpixels(int argc, char *argv[]) 385{ 386 errval_t err; 387 388 /* Spawn on all cores */ 389 char *spawnargv[] = {"pixels", NULL}; 390 err = spawn_program_on_all_cores(true, spawnargv[0], spawnargv, NULL, 391 SPAWN_FLAGS_DEFAULT, NULL, NULL); 392 if (err_is_fail(err)) { 393 USER_PANIC_ERR(err, "error spawning other core"); 394 } 395 pixels_started = true; 396 printf("Done\n"); 397 398 return EXIT_SUCCESS; 399} 400 401static int ps(int argc, char *argv[]) 402{ 403 domainid_t *domains; 404 size_t len; 405 errval_t err; 406 407 err = spawn_get_domain_list(true, &domains, &len); 408 if (err_is_fail(err)) { 409 DEBUG_ERR(err, "spawn_get_domain_list"); 410 return EXIT_FAILURE; 411 } 412 413 printf("DOMAINID\tSTAT\tCOMMAND\n"); 414 for(size_t i = 0; i < len; i++) { 415 struct spawn_ps_entry pse; 416 char *argbuf, status; 417 size_t arglen; 418 errval_t reterr; 419 420 err = spawn_get_status(domains[i], &pse, &argbuf, &arglen, &reterr); 421 if (err_is_fail(err)) { 422 DEBUG_ERR(err, "spawn_get_status"); 423 return EXIT_FAILURE; 424 } 425 if(err_is_fail(reterr)) { 426 if(err_no(reterr) == SPAWN_ERR_DOMAIN_NOTFOUND) { 427 return reterr; 428 } 429 DEBUG_ERR(err, "status"); 430 return EXIT_FAILURE; 431 } 432 433 switch(pse.status) { 434 case 0: 435 status = 'N'; 436 break; 437 438 case 1: 439 status = 'R'; 440 break; 441 442 case 2: 443 status = 'S'; 444 break; 445 446 case 3: 447 status = 'S'; 448 break; 449 450 default: 451 status = '?'; 452 break; 453 } 454 455 printf("%-8u\t%c\t", domains[i], status); 456 size_t pos = 0; 457 for(int p = 0; pos < arglen && p < MAX_CMDLINE_ARGS;) { 458 printf("%s ", &argbuf[pos]); 459 char *end = memchr(&argbuf[pos], '\0', arglen - pos); 460 assert(end != NULL); 461 pos = end - argbuf + 1; 462 } 463 printf("\n"); 464 465 free(argbuf); 466 } 467 468 free(domains); 469 return EXIT_SUCCESS; 470} 471 472static int skb(int argc, char *argv[]) 473{ 474 static bool init = false; 475 476 if(argc < 2) { 477 printf("Usage: %s <program>\n", argv[0]); 478 return EXIT_FAILURE; 479 } 480 481 if(!init) { 482 skb_client_connect(); 483 init = true; 484 } 485 486 char *result = NULL, *str_err = NULL; 487 int32_t int_err; 488 489 skb_evaluate(argv[1], &result, &str_err, &int_err); 490 491 if (int_err != 0 || (str_err != NULL && str_err[0] != '\0')) { 492 printf("SKB error returned: %"PRIu32" %s\n", int_err, str_err); 493 } else { 494 printf("SKB returned: %s\n", result); 495 } 496 497 free(result); 498 free(str_err); 499 500 return EXIT_SUCCESS; 501} 502 503static int mount(int argc, char *argv[]) 504{ 505 if (argc != 3) { 506 printf("Usage: %s MOUNTPOINT URI\n", argv[0]); 507 return EXIT_FAILURE; 508 } 509 510 char *path = vfs_path_mkabsolute(cwd, argv[1]); 511 errval_t err = vfs_mount(path, argv[2]); 512 free(path); 513 if (err_is_fail(err)) { 514 DEBUG_ERR(err, "in vfs_mount %s %s", argv[1], argv[2]); 515 return EXIT_FAILURE; 516 } 517 return EXIT_SUCCESS; 518} 519 520static int cat(int argc, char *argv[]) 521{ 522 if(argc < 2) { 523 printf("Usage: %s [file...]\n", argv[0]); 524 return EXIT_FAILURE; 525 } 526 527 uint8_t buf[1024]; 528 size_t size; 529 vfs_handle_t vh; 530 errval_t err; 531 int ret = EXIT_SUCCESS; 532 533 for (int i = 1; i < argc; i++) { 534 char *path = vfs_path_mkabsolute(cwd, argv[i]); 535 err = vfs_open(path, &vh); 536 free(path); 537 if (err_is_fail(err)) { 538 printf("%s: file not found\n", argv[i]); 539 ret = EXIT_FAILURE; 540 continue; 541 } 542 543 do { 544 err = vfs_read(vh, buf, sizeof(buf), &size); 545 if (err_is_fail(err)) { 546 // XXX: Close any files that might be open 547 DEBUG_ERR(err, "error reading file"); 548 return EXIT_FAILURE; 549 } 550 551 fwrite(buf, 1, size, stdout); 552 } while(size > 0); 553 554 err = vfs_close(vh); 555 if (err_is_fail(err)) { 556 DEBUG_ERR(err, "in vfs_close"); 557 } 558 } 559 560 return ret; 561} 562 563#define LINE_SIZE 16 564static int hd(int argc, char *argv[]) 565{ 566 if(argc < 2) { 567 printf("Usage: %s [file...]\n", argv[0]); 568 return EXIT_FAILURE; 569 } 570 571 uint8_t buf[1024]; 572 size_t size; 573 vfs_handle_t vh; 574 errval_t err; 575 int ret = EXIT_SUCCESS; 576 577 for (int i = 1; i < argc; i++) { 578 char *path = vfs_path_mkabsolute(cwd, argv[i]); 579 err = vfs_open(path, &vh); 580 free(path); 581 if (err_is_fail(err)) { 582 printf("%s: file not found\n", argv[i]); 583 ret = EXIT_FAILURE; 584 continue; 585 } 586 587 printf("Contents of %s\n", argv[i]); 588 int k=0; 589 do { 590 err = vfs_read(vh, buf, sizeof(buf), &size); 591 if (err_is_fail(err)) { 592 // XXX: Close any files that might be open 593 DEBUG_ERR(err, "error reading file"); 594 return EXIT_FAILURE; 595 } 596 597 for (int j = k%LINE_SIZE; j < size; j++) { 598 if (j % LINE_SIZE == 0) { 599 printf("%08X: ", k+j); 600 } 601 printf("%02x%s", buf[j], (j+1)%LINE_SIZE == 0 ? "\n" : " "); 602 } 603 k+=size; 604 } while(size > 0); 605 if (k%LINE_SIZE) { 606 printf("\n"); 607 } 608 609 err = vfs_close(vh); 610 if (err_is_fail(err)) { 611 DEBUG_ERR(err, "in vfs_close"); 612 } 613 } 614 615 return ret; 616} 617 618static int cat2(int argc, char *argv[]) 619{ 620 errval_t err; 621 char *path; 622 int ret; 623 624 if(argc < 3) { 625 printf("Usage: %s [input-files...] output-file\n", argv[0]); 626 return EXIT_FAILURE; 627 } 628 629 /* Open output file creating it if it does not exist */ 630 path = vfs_path_mkabsolute(cwd, argv[argc - 1]); 631 vfs_handle_t output_vh; 632 err = vfs_create(path, &output_vh); 633 free(path); 634 if (err_is_fail(err)) { 635 DEBUG_ERR(err, "error opening output file"); 636 return EXIT_FAILURE; 637 } 638 639 /* Open input files, read buffer and write to output file */ 640 for (int i = 1; i < argc - 1; i++) { 641 uint8_t buf[1024]; 642 size_t size; 643 vfs_handle_t input_vh; 644 path = vfs_path_mkabsolute(cwd, argv[i]); 645 err = vfs_open(path, &input_vh); 646 free(path); 647 if (err_is_fail(err)) { 648 printf("%s: file not found\n", argv[i]); 649 ret = EXIT_FAILURE; 650 continue; 651 } 652 653 do { 654 err = vfs_read(input_vh, buf, sizeof(buf), &size); 655 if (err_is_fail(err)) { 656 // XXX: Close any files that might be open 657 DEBUG_ERR(err, "error reading file"); 658 return EXIT_FAILURE; 659 } 660 661 size_t output_size; 662 err = vfs_write(output_vh, buf, size, &output_size); 663 if (err_is_fail(err)) { 664 // XXX: Close any files that might be open 665 DEBUG_ERR(err, "error writing to output file"); 666 return EXIT_FAILURE; 667 } 668 if (output_size != size) { 669 printf("Wanted to write %zu but only wrote %zu, aborting\n", 670 size, output_size); 671 // XXX: Close any files that might be open 672 return EXIT_FAILURE; 673 } 674 } while(size > 0); 675 676 err = vfs_close(input_vh); 677 if (err_is_fail(err)) { 678 DEBUG_ERR(err, "in vfs_close"); 679 } 680 } 681 682 err = vfs_close(output_vh); 683 if (err_is_fail(err)) { 684 DEBUG_ERR(err, "in vfs_close"); 685 } 686 return ret; 687} 688 689static int cp(int argc, char *argv[]) 690{ 691 if (argc != 3) { 692 printf("Usage: %s src dest\n", argv[0]); 693 return EXIT_FAILURE; 694 } 695 696 static uint8_t buf[32768]; 697 size_t rsize, wsize; 698 vfs_handle_t src = NULL, dst = NULL; 699 errval_t err; 700 int ret = EXIT_SUCCESS; 701 702 char *path = vfs_path_mkabsolute(cwd, argv[1]); 703 err = vfs_open(path, &src); 704 free(path); 705 if (err_is_fail(err)) { 706 printf("%s: %s\n", argv[1], err_getstring(err)); 707 return EXIT_FAILURE; 708 } 709 710 path = vfs_path_mkabsolute(cwd, argv[2]); 711 err = vfs_create(path, &dst); 712 free(path); 713 if (err_is_fail(err)) { 714 printf("%s: %s\n", argv[2], err_getstring(err)); 715 ret = EXIT_FAILURE; 716 goto out; 717 } 718 719 err = vfs_truncate(dst, 0); 720 if (err_is_fail(err)) { 721 printf("truncate %s: %s\n", argv[2], err_getstring(err)); 722 ret = EXIT_FAILURE; 723 goto out; 724 } 725 726 do { 727 err = vfs_read(src, buf, sizeof(buf), &rsize); 728 if (err_is_fail(err)) { 729 DEBUG_ERR(err, "error reading file"); 730 ret = EXIT_FAILURE; 731 goto out; 732 } 733 734 size_t wpos = 0; 735 while (wpos < rsize) { 736 err = vfs_write(dst, &buf[wpos], rsize - wpos, &wsize); 737 if (err_is_fail(err) || wsize == 0) { 738 DEBUG_ERR(err, "error writing file"); 739 ret = EXIT_FAILURE; 740 goto out; 741 } 742 wpos += wsize; 743 } 744 } while(rsize > 0); 745 746out: 747 if (src != NULL) { 748 err = vfs_close(src); 749 if (err_is_fail(err)) { 750 DEBUG_ERR(err, "in vfs_close"); 751 } 752 } 753 754 if (dst != NULL) { 755 err = vfs_close(dst); 756 if (err_is_fail(err)) { 757 DEBUG_ERR(err, "in vfs_close"); 758 } 759 } 760 761 return ret; 762} 763 764static int dd(int argc, char *argv[]) 765{ 766 // parse options 767 char *source = NULL; 768 char *target = NULL; 769 770 vfs_handle_t source_vh = NULL; 771 vfs_handle_t target_vh = NULL; 772 773 size_t blocksize = 512; 774 size_t count = 0; 775 size_t skip = 0; 776 size_t seek = 0; 777 778 size_t rsize = 0; 779 size_t wsize = 0; 780 size_t blocks_written = 0; 781 782 size_t total_bytes_read = 0; 783 size_t total_bytes_written = 0; 784 785 size_t progress = 0; 786 787 errval_t err; 788 int ret = EXIT_SUCCESS; 789 790 for (int i = 1; i < argc; i++) 791 { 792 if (!strncmp(argv[i], "bs=", 3)) 793 blocksize = atoi(argv[i] + 3); 794 795 else if (!strncmp(argv[i], "count=", 6)) 796 count = atoi(argv[i] + 6); 797 798 else if (!strncmp(argv[i], "skip=", 5)) 799 skip = atoi(argv[i] + 5); 800 801 else if (!strncmp(argv[i], "seek=", 5)) 802 seek = atoi(argv[i] + 5); 803 804 else if (!strncmp(argv[i], "if=", 3)) 805 source = (argv[i] + 3); 806 807 else if (!strncmp(argv[i], "of=", 3)) 808 target = (argv[i] + 3); 809 else if (!strncmp(argv[i], "progress", 8)) 810 progress = 1; 811 } 812 813 size_t one_per_cent = (blocksize * count) / 100; 814 815 printf("from: %s to: %s bs=%zd count=%zd seek=%zd skip=%zd\n", source, target, blocksize, count, seek, skip); 816 817 if (source != NULL) 818 { 819 char *path = vfs_path_mkabsolute(cwd, source); 820 err = vfs_open(path, &source_vh); 821 free(path); 822 if (err_is_fail(err)) { 823 printf("%s: %s\n", source, err_getstring(err)); 824 return EXIT_FAILURE; 825 } 826 827 if (skip != 0) 828 { 829 // TODO: skip 830 } 831 } 832 833 if (target != NULL) 834 { 835 char *path = vfs_path_mkabsolute(cwd, target); 836 err = vfs_create(path, &target_vh); 837 free(path); 838 if (err_is_fail(err)) { 839 // close source handle 840 if (source_vh != NULL) 841 vfs_close(source_vh); 842 printf("%s: %s\n", target, err_getstring(err)); 843 return EXIT_FAILURE; 844 } 845 846 if (seek != 0) 847 { 848 // TODO: seek 849 } 850 } 851 852 uint8_t * buffer = malloc(blocksize); 853 854#if defined(__x86_64__) || defined(__i386__) 855 uint64_t tscperms; 856 err = sys_debug_get_tsc_per_ms(&tscperms); 857 assert(err_is_ok(err)); 858 859 //printf("ticks per millisec: %" PRIu64 "\n", tscperms); 860 uint64_t start = rdtsc(); 861#endif 862 863 if (buffer == NULL) 864 { 865 ret = EXIT_FAILURE; 866 printf("failed to allocate buffer of size %zd\n", blocksize); 867 goto out; 868 } 869 870 do 871 { 872 //printf("copying block\n"); 873 size_t read_bytes = 0; 874 do { 875 err = vfs_read(source_vh, buffer, blocksize, &rsize); 876 if (err_is_fail(err)) { 877 DEBUG_ERR(err, "error reading file"); 878 ret = EXIT_FAILURE; 879 goto out; 880 } 881 882 total_bytes_read += rsize; 883 read_bytes += rsize; 884 885 size_t wpos = 0; 886 while (wpos < rsize) { 887 if (wpos > 0) 888 printf("was unable to write the whole chunk of size %zd. Now at pos: %zd of buffer\n", rsize, wpos); 889 890 err = vfs_write(target_vh, &buffer[wpos], rsize - wpos, &wsize); 891 if (err_is_fail(err) || wsize == 0) { 892 DEBUG_ERR(err, "error writing file"); 893 ret = EXIT_FAILURE; 894 goto out; 895 } 896 wpos += wsize; 897 total_bytes_written += wsize; 898 } 899 } while(read_bytes < blocksize); 900 901 blocks_written++; 902 903 if (progress && one_per_cent && total_bytes_written % one_per_cent == 0) { 904 printf("."); 905 } 906 907 //printf("block successfully copied. read: %zd. blocks written: %zd\n", rsize, blocks_written); 908 } while (rsize > 0 && !(count > 0 && blocks_written >= count)); 909 910 if (progress) printf("\n"); 911 912out: 913 if (buffer != NULL) 914 free(buffer); 915 916 if (source_vh != NULL) { 917 err = vfs_close(source_vh); 918 if (err_is_fail(err)) { 919 DEBUG_ERR(err, "in vfs_close"); 920 } 921 } 922 923 if (target_vh != NULL) { 924 err = vfs_close(target_vh); 925 if (err_is_fail(err)) { 926 DEBUG_ERR(err, "in vfs_close"); 927 } 928 } 929 930#if defined(__x86_64__) || defined(__i386__) 931 uint64_t stop = rdtsc(); 932 uint64_t elapsed_msecs = ((stop - start) / tscperms); 933 double elapsed_secs = (double)elapsed_msecs/1000.0; 934 935 printf("start: %" PRIu64 " stop: %" PRIu64 "\n", start, stop); 936 937 double kbps = ((double)total_bytes_written / 1024.0) / elapsed_secs; 938 939 printf("%zd bytes read. %zd bytes written. %f s, %f kB/s\n", total_bytes_read, total_bytes_written, elapsed_secs, kbps); 940#else 941 printf("%zd bytes read. %zd bytes written.\n", total_bytes_read, total_bytes_written); 942#endif 943 944 return ret; 945} 946 947static int touch(int argc, char *argv[]) 948{ 949 if(argc < 2) { 950 printf("Usage: %s [file...]\n", argv[0]); 951 return EXIT_FAILURE; 952 } 953 954 vfs_handle_t vh; 955 errval_t err; 956 int ret = EXIT_SUCCESS; 957 958 for (int i = 1; i < argc; i++) { 959 char *path = vfs_path_mkabsolute(cwd, argv[i]); 960 err = vfs_create(path, &vh); 961 free(path); 962 if (err_is_fail(err)) { 963 printf("%s: %s\n", argv[i], err_getstring(err)); 964 DEBUG_ERR(err, "vfs_create failed"); 965 ret = EXIT_FAILURE; 966 continue; 967 } 968 969 err = vfs_close(vh); 970 if (err_is_fail(err)) { 971 DEBUG_ERR(err, "in vfs_close"); 972 } 973 } 974 975 return ret; 976} 977 978static char vfs_type_char(enum vfs_filetype type) 979{ 980 switch(type) { 981 case VFS_FILE: 982 return '-'; 983 case VFS_DIRECTORY: 984 return 'd'; 985 default: 986 return '?'; 987 } 988} 989 990static int ls(int argc, char *argv[]) 991{ 992 errval_t err; 993 int ret = EXIT_SUCCESS; 994 995 // XXX: cheat and assume we have some extra space wherever argv lives 996 if (argc <= 1) { 997 argv[1] = cwd; 998 argc = 2; 999 } 1000 1001 for (int i = 1; i < argc; i++) { 1002 vfs_handle_t vh; 1003 char *path = vfs_path_mkabsolute(cwd, argv[i]); 1004 err = vfs_opendir(path, &vh); 1005 free(path); 1006 if (err_is_fail(err)) { 1007 DEBUG_ERR(err, "in vfs_opendir %s", argv[i]); 1008 printf("%s: not found\n", argv[i]); 1009 ret = EXIT_FAILURE; 1010 continue; 1011 } 1012 1013 if (i > 1) { 1014 printf("\n"); 1015 } 1016 printf("%s:\n", argv[i]); 1017 1018 do { 1019 struct vfs_fileinfo info; 1020 char *name; 1021 err = vfs_dir_read_next(vh, &name, &info); 1022 if (err_is_ok(err)) { 1023 printf("%8zu %c %s\n", info.size, vfs_type_char(info.type), 1024 name); 1025 free(name); 1026 } 1027 } while(err_is_ok(err)); 1028 1029 err = vfs_closedir(vh); 1030 if (err_is_fail(err)) { 1031 DEBUG_ERR(err, "in vfs_closedir"); 1032 } 1033 } 1034 1035 return ret; 1036} 1037 1038static int mkdir(int argc, char *argv[]) 1039{ 1040 if(argc != 2) { 1041 printf("Usage: %s dir\n", argv[0]); 1042 return EXIT_FAILURE; 1043 } 1044 1045 char *path = vfs_path_mkabsolute(cwd, argv[1]); 1046 errval_t err = vfs_mkdir(path); 1047 free(path); 1048 if (err_is_fail(err)) { 1049 printf("%s\n", err_getstring(err)); 1050 return EXIT_FAILURE; 1051 } else { 1052 return EXIT_SUCCESS; 1053 } 1054} 1055 1056static int rmdir(int argc, char *argv[]) 1057{ 1058 if(argc != 2) { 1059 printf("Usage: %s dir\n", argv[0]); 1060 return EXIT_FAILURE; 1061 } 1062 1063 char *path = vfs_path_mkabsolute(cwd, argv[1]); 1064 errval_t err = vfs_rmdir(path); 1065 free(path); 1066 if (err_is_fail(err)) { 1067 printf("%s\n", err_getstring(err)); 1068 return EXIT_FAILURE; 1069 } else { 1070 return EXIT_SUCCESS; 1071 } 1072} 1073 1074static int rm(int argc, char *argv[]) 1075{ 1076 if(argc < 2) { 1077 printf("Usage: %s file...\n", argv[0]); 1078 return EXIT_FAILURE; 1079 } 1080 1081 int ret = EXIT_SUCCESS; 1082 1083 for (int i = 1; i < argc; i++) { 1084 char *path = vfs_path_mkabsolute(cwd, argv[i]); 1085 errval_t err = vfs_remove(path); 1086 free(path); 1087 if (err_is_fail(err)) { 1088 printf("%s: %s\n", argv[i], err_getstring(err)); 1089 ret = EXIT_FAILURE; 1090 } 1091 } 1092 1093 return ret; 1094} 1095 1096static int cd(int argc, char *argv[]) 1097{ 1098 errval_t err; 1099 1100 if (argc != 2) { 1101 printf("Usage: %s DIR\n", argv[0]); 1102 return EXIT_FAILURE; 1103 } 1104 1105 char *newcwd = vfs_path_mkabsolute(cwd, argv[1]); 1106 1107 // ensure directory exists, by attempting to open it 1108 vfs_handle_t dh; 1109 err = vfs_opendir(newcwd, &dh); 1110 if (err_is_fail(err)) { 1111 printf("cd to %s (-> %s) failed: %s\n", 1112 argv[1], newcwd, err_getstring(err)); 1113 free(newcwd); 1114 return EXIT_FAILURE; 1115 } 1116 vfs_closedir(dh); 1117 1118 // ok! 1119 free(cwd); 1120 cwd = newcwd; 1121 1122 return EXIT_SUCCESS; 1123} 1124 1125static int pwd(int argc, char *argv[]) 1126{ 1127 printf("%s\n", cwd); 1128 return EXIT_SUCCESS; 1129} 1130 1131static int mnfs(int argc, char *argv[]) 1132{ 1133 char *args1[2] = { "mkdir", "/nfs" }; 1134 mkdir(2, args1); 1135 char *args2[3] = { "mount", "/nfs", "nfs://10.110.4.4/local/nfs" }; 1136 return mount(3, args2); 1137} 1138 1139/// Open file(s) with a list of commands and execute them 1140static int src(int argc, char *argv[]) 1141{ 1142 if (argc < 2) { 1143 printf("Usage: %s file...\n", argv[0]); 1144 } 1145 1146 int ret = EXIT_SUCCESS; 1147 for (int i = 1; i < argc; i++) { 1148 char *path = vfs_path_mkabsolute(cwd, argv[i]); 1149 FILE *f = fopen(path, "r"); 1150 if (!f) { 1151 printf("File %s not found\n", path); 1152 ret = EXIT_FAILURE; 1153 continue; 1154 } 1155 printf("Executing file %s\n", path); 1156 1157 // Read one line at a time, make args out of it and execute it 1158 while (true) { 1159 char buf[1024] = "\0"; 1160 char *p = fgets(buf, 1024, f); 1161 if (!p) { 1162 break; 1163 } 1164 1165 char *q = strrchr(p, '\n'); 1166 *q = '\0'; 1167 char *cmdstr = strdup(p); 1168 char *cmd_argv[64]; 1169 int cmd_argc = makeargs(cmdstr, cmd_argv); 1170 if (cmd_argc == 0) { 1171 continue; 1172 } 1173 1174 struct cmd *cmd = find_command(cmd_argv[0]); 1175 if (!cmd) { 1176 } else { 1177 printf("running command: %s\n", p); 1178 int r = cmd->cmd(cmd_argc, cmd_argv); 1179 if (r != 0) { 1180 printf("running command %s failed errorcode %d\n", p, r); 1181 } 1182 } 1183 free(cmdstr); 1184 } 1185 free(path); 1186 } 1187 return ret; 1188} 1189 1190static int freecmd(int argc, char *argv[]) 1191{ 1192 struct mem_binding *mc = get_mem_client(); 1193 assert(mc != NULL); 1194 errval_t err; 1195 genpaddr_t available, total; 1196 1197 err = ram_available(&available, &total); 1198 if(err_is_fail(err)) { 1199 DEBUG_ERR(err, "available"); 1200 return EXIT_FAILURE; 1201 } 1202 1203 printf("Free memory: %" PRIuGENPADDR " bytes\n", available); 1204 printf("Total memory: %" PRIuGENPADDR " bytes\n", total); 1205 1206 return EXIT_SUCCESS; 1207} 1208 1209static int nproc(int argc, char* argv[]) { 1210 errval_t err; 1211 size_t count = 0; 1212 char** names = NULL; 1213 1214 static char* spawnds = "r'spawn.[0-9]+' { iref: _ }"; 1215 oct_init(); 1216 1217 struct octopus_get_names_response__rx_args reply; 1218 struct octopus_binding *r = get_octopus_binding(); 1219 err = r->rpc_tx_vtbl.get_names(r, spawnds, NOP_TRIGGER, reply.output, 1220 &reply.tid, &reply.error_code); 1221 if (err_is_fail(err) || err_is_fail(reply.error_code)) { 1222 DEBUG_ERR(err, "get_names failed"); 1223 goto out; 1224 } 1225 1226 err = oct_parse_names(reply.output, &names, &count); 1227 if (err_is_fail(err)) { 1228 DEBUG_ERR(err, "parse_names failed."); 1229 goto out; 1230 } 1231 1232out: 1233 oct_free_names(names, count); 1234 1235 printf("%zx\n", count); 1236 return EXIT_SUCCESS; 1237} 1238 1239 1240static struct cmd commands[] = { 1241 {"help", help, "Output usage information about given shell command"}, 1242 {"print_cspace", print_cspace, "Debug print-out of my cspace"}, 1243 {"quit", quit, "Quit the shell"}, 1244 {"nproc", nproc, "Get amount of cores in system."}, 1245 {"ps", ps, "List running processes"}, 1246 {"demo", demo, "Run barrelfish demo"}, 1247 {"pixels", spawnpixels, "Spawn pixels on all cores"}, 1248 {"mnfs", mnfs, "Mount script for NFS on emmentaler"}, 1249 {"oncore", oncore, "Start program on specified core"}, 1250 {"reset", reset, "Reset machine"}, 1251 {"poweroff", poweroff, "Power down machine"}, 1252 {"skb", skb, "Send command to system knowledge base"}, 1253 {"mount", mount, "Mount file system"}, 1254 {"ls", ls, "List directory contents"}, 1255 {"cd", cd, "Change working directory"}, 1256 {"pwd", pwd, "Print current working directory"}, 1257 {"touch", touch, "Create an empty file"}, 1258 {"cat", cat, "Print the contents of file(s)"}, 1259 {"hd", hd, "Print the contents of file(s) as hexdump"}, 1260 {"cat2", cat2, "Print the contents of file(s) into another file"}, 1261 {"dd", dd, "copy stuff"}, 1262 {"cp", cp, "Copy files"}, 1263 {"rm", rm, "Remove files"}, 1264 {"mkdir", mkdir, "Create a new directory"}, 1265 {"rmdir", rmdir, "Remove an existing directory"}, 1266 {"setenv", setenvcmd, "Set environment variables"}, 1267 {"src", src, "Execute the list of commands in a file"}, 1268 {"printenv", printenv, "Display environment variables"}, 1269 {"free", freecmd, "Display amount of free memory in the system"}, 1270 {"dump_caps", dump_caps, "Display cspace debug information"}, 1271 {"measure_pmap_res", measure_pmap_res, "Display pmap resource usage for shell"}, 1272}; 1273 1274static struct cmd *find_command(const char *name) 1275{ 1276 for(int i = 0; i < ENTRIES(commands); i++) { 1277 struct cmd *cmd = &commands[i]; 1278 1279 if(strcmp(name, cmd->name) == 0) { 1280 return cmd; 1281 } 1282 } 1283 1284 return NULL; 1285} 1286 1287static int help(int argc, char *argv[]) 1288{ 1289 struct cmd *cmd; 1290 1291 if (argc == 1) { 1292 printf("available commands:\n"); 1293 for (int i=0; i < ENTRIES(commands); i++) { 1294 printf("%-15s", commands[i].name); 1295 if (((i + 1) % 5) == 0) { 1296 printf("\n"); 1297 } 1298 } 1299 printf("\n"); 1300 return EXIT_SUCCESS; 1301 } 1302 1303 if ((cmd = find_command(argv[1])) != NULL) { 1304 printf("%s: %s\n", argv[1], cmd->usage); 1305 return EXIT_SUCCESS; 1306 } else { 1307 printf("%s: %s: command not found\n", argv[0], argv[1]); 1308 return EXIT_FAILURE; 1309 } 1310} 1311 1312static int makeargs(char *cmdline, char *argv[]) 1313{ 1314 char *p = cmdline; 1315 bool inquote = false; 1316 int argc = 0; 1317 1318 if (p == NULL) { 1319 return 0; 1320 } 1321 1322 while (*p == ' ') { 1323 p++; 1324 } 1325 1326 if (*p == '\0') { 1327 return 0; 1328 } 1329 1330 for(argv[argc++] = p; *p != '\0'; p++) { 1331 if (*p == '"') { 1332 inquote = !inquote; 1333 *p = ' '; // mega-kludge! 1334 } else if (*p == ' ' && !inquote) { 1335 *p++ = '\0'; 1336 // Skip any redundant whitespace 1337 while(*p == ' ') { 1338 p++; 1339 } 1340 if (*p != '\0') { 1341 argv[argc++] = p; 1342 if (*p == '"') { 1343 inquote = true; 1344 *p = ' '; // mega-kludge 1345 } 1346 } 1347 } 1348 } 1349 1350 return argc; 1351} 1352 1353static uint8_t wait_domain_id(struct capref domainid) 1354{ 1355 uint8_t exitcode; 1356 errval_t err = spawn_wait(domainid, &exitcode, false); 1357 if (err_is_fail(err)) { 1358 USER_PANIC_ERR(err, "spawn_wait"); 1359 } 1360 return exitcode; 1361} 1362 1363static void runbootscript(void) 1364{ 1365 char cmdstr[1024]; 1366 snprintf(cmdstr, 1024,"sh %s", BOOTSCRIPT_NAME); 1367 char *cmd_argv[64]; 1368 int cmd_argc = makeargs(cmdstr, cmd_argv); 1369 int ret = src(cmd_argc, cmd_argv); 1370 if (ret != 0) { 1371 snprintf(cmdstr, 1024, "help"); 1372 cmd_argc = makeargs(cmdstr, cmd_argv); 1373 help(cmd_argc, cmd_argv); 1374 } 1375} 1376 1377 1378int main(int argc, const char *argv[]) 1379{ 1380 int exitcode = 0; 1381 bool is_bootscript = true; 1382 coreid_t my_core_id = disp_get_core_id(); 1383 1384 vfs_init(); 1385 1386 for (int i = 1; i < argc; i++) { 1387 if (strcmp(argv[i], "nobootscript") == 0) { 1388 is_bootscript = false; 1389 } 1390 } 1391 1392 cwd = strdup("/"); 1393 1394 printf("fish v0.2 -- pleased to meet you!\n"); 1395 1396 // run canned pre-boot commands 1397 if (is_bootscript) { 1398 runbootscript(); 1399 } 1400 1401 struct terminal_state *ts = get_terminal_state(); 1402 term_client_blocking_config(&ts->client, TerminalConfig_CTRLC, false); 1403 linenoiseHistorySetMaxLen(1024); 1404 1405 // Create inherit CNode to pass session cap to programs spawned from fish 1406 errval_t err; 1407 err = alloc_inheritcn_with_caps(&inheritcn_cap, NULL_CAP, cap_sessionid, NULL_CAP); 1408 if (err_is_fail(err)) { 1409 USER_PANIC_ERR(err, "Error allocating inherit CNode with session cap."); 1410 } 1411 1412 for (;;) { 1413 char* input = NULL; 1414 int cmd_argc; 1415 char *cmd_argv[64]; // Support a max of 64 cmd args 1416 struct cmd *cmd; 1417 1418 input = linenoise("> "); 1419 if (input == NULL || input[0] == '\0') { 1420 continue; 1421 } 1422 1423 linenoiseHistoryAdd(input); /* Add to the history. */ 1424 linenoiseHistorySave("history.txt"); /* Save the history on disk. */ 1425 cmd_argc = makeargs(input, cmd_argv); 1426 1427 /* check for trailing '&' (== run in background) */ 1428 bool wait = true; 1429 if (cmd_argc > 0) { 1430 size_t len = strlen(cmd_argv[cmd_argc - 1]); 1431 if (len > 0 && cmd_argv[cmd_argc - 1][len - 1] == '&') { 1432 wait = false; 1433 // remove '&' character from args 1434 if (len == 1) { 1435 cmd_argc--; 1436 } else { 1437 cmd_argv[cmd_argc - 1][len - 1] = '\0'; 1438 } 1439 } 1440 } 1441 1442 if (cmd_argc == 0) { 1443 continue; 1444 } else if ((cmd = find_command(cmd_argv[0])) != NULL) { 1445 exitcode = cmd->cmd(cmd_argc, cmd_argv); 1446 } else { 1447 // Try loading a program off disk if VFS is initialized 1448 struct capref domain_cap; 1449 exitcode = execute_program(my_core_id, cmd_argc, cmd_argv, &domain_cap); 1450 1451 // wait if it succeeds 1452 if (exitcode == 0 && wait) { 1453 exitcode = wait_domain_id(domain_cap); 1454 char exitstr[128]; 1455 snprintf(exitstr, 128, "%u", exitcode); 1456 int r = setenv("EXITCODE", exitstr, 1); 1457 assert(r == 0); 1458 } 1459 } 1460 1461 free(input); 1462 } 1463} 1464