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