Fixed how errno is handled with isatty()
[akaros.git] / user / parlib / src / newlib_backend.c
1 /* See COPYRIGHT for copyright information. */
2 /* Kevin Klues <klueska@cs.berkeley.edu>        */
3
4 #ifdef __DEPUTY__
5 #pragma nodeputy
6 #endif
7
8 #include <parlib.h>
9 #include <unistd.h>
10 #include <newlib_backend.h>
11 #include <string.h>
12 #include <malloc.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <debug.h>
16
17 #define debug_in_out(...) // debug(__VA_ARGS__)  
18 #define debug_write_check(fmt, ...) // debug(fmt, __VA_ARGS__)
19
20 /* environ
21  * A pointer to a list of environment variables and their values. 
22  * For a minimal environment, this empty list is adequate.
23  */
24 char *__env[1] = { 0 };
25 char **environ = __env;
26 extern env_t* env;
27
28 /* _exit()
29  * Exit a program without cleaning up files. 
30  * If your system doesn't provide this, it is best to avoid linking 
31  * with subroutines that require it (exit, system).
32  */
33 void _exit(int __status) _ATTRIBUTE ((noreturn))
34 {
35         sys_env_destroy(env->env_id);
36         while(1); //Should never get here...
37 }
38     
39 /* close()
40  * Close a file. 
41  */
42 int close(int file) {
43         debug_in_out("CLOSE\n");
44
45         // If trying to close stdin/out/err just return
46         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
47                                    || (file == STDOUT_FILENO))
48                 return 0;
49
50         // Allocate a new buffer of proper size
51         char *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
52         if (out_msg == NULL)
53                 return -1;
54
55         char *out_msg_pos = out_msg;
56
57         // Fill the buffer
58         *((syscall_id_t *)out_msg_pos) = CLOSE_ID;
59         out_msg_pos += sizeof(syscall_id_t);
60
61         *((int*)out_msg_pos) = file;
62         out_msg_pos += sizeof(int);
63
64
65         // Send message
66         char *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
67
68         free(out_msg);
69
70         int return_val;
71
72         if (result != NULL) {
73                 // Read result
74                 return_val = *((int *) result);
75                 if (return_val == -1) errno = *(((int *)result) + 1);
76                 free(result);
77         } else {
78                 errno = ECHANNEL;
79                 return_val = -1;
80         }
81         
82         return return_val;
83 }
84
85 /* execve()
86  * Transfer control to a new process. 
87  * Minimal implementation (for a system without processes).
88  */
89
90 int execve(char *name, char **argv, char **env) 
91 {
92         debug_in_out("EXECVE\n");
93         errno = ENOMEM;
94         return -1;
95 }
96
97 /* fork()
98  * Create a new process. 
99  * Minimal implementation (for a system without processes).
100  */
101 int fork(void) 
102 {
103         debug_in_out("FORK\n");
104         errno = EAGAIN;
105     return -1;
106 }
107
108 /* fstat()
109  * Status of an open file. 
110  * For consistency with other minimal implementations in these stubs, 
111  * all files are regarded as character special devices. 
112  * The sys/stat.h header file required is distributed in the include 
113  * subdirectory for the newlib C library.
114  */
115 int fstat(int file, struct stat *st) 
116 {
117         debug_in_out("FSTAT\n");        
118
119         st->st_mode = S_IFCHR;
120         
121         // stdout hack
122 //      if (file == 1)
123 //              st->st_mode = 8592;
124 //      return 0;
125
126
127         // Allocate a new buffer of proper size
128         char *out_msg = malloc(FSTAT_MESSAGE_FIXED_SIZE);
129         if(out_msg == NULL)
130                 return -1;
131         char *out_msg_pos = out_msg;
132
133         // Fill the buffer
134         *((syscall_id_t *)out_msg_pos) = FSTAT_ID;
135         out_msg_pos += sizeof(syscall_id_t);
136
137         *((int*)out_msg_pos) = file;
138         out_msg_pos += sizeof(int);
139
140         // Send message
141         char *result = send_message(out_msg, FSTAT_MESSAGE_FIXED_SIZE);
142
143         free(out_msg);
144
145         // Read result
146         int return_val;
147
148         if (result != NULL) {
149                 return_val = *((int *)result);
150                 if (return_val == -1)
151                         errno = *(((char *)result) + 
152                                        sizeof(int) + sizeof(struct stat));
153                 else
154                         memcpy(st, ((int *)result) + 1, sizeof(struct stat));
155                 free(result);
156         } else {
157                 errno = ECHANNEL;
158                 return_val = -1;
159         }
160
161         return return_val;
162 }
163
164 /* getpid()
165  * Process-ID; this is sometimes used to generate strings unlikely to 
166  * conflict with other processes. Minimal implementation, for a system 
167  * without processes.
168  */
169 int getpid(void) 
170 {
171         return env->env_id;
172 }
173
174 /* isatty()
175  * Query whether output stream is a terminal. 
176  * For consistency with the other minimal implementations, 
177  * which only support output to stdout, this minimal 
178  * implementation is suggested.
179  */
180 int isatty(int file) 
181 {
182         debug_in_out("ISATTY\n");
183
184         // Cheap hack to avoid sending serial comm for stuff we know
185 //      if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
186 //                                 || (STDERR_FILENO == file))
187 //              return 1;
188
189         
190         // Allocate a new buffer of proper size
191         char *out_msg = malloc(ISATTY_MESSAGE_FIXED_SIZE);
192         if(out_msg == NULL)
193                 return -1;
194         char *out_msg_pos = out_msg;
195
196         // Fill the buffer
197         *((syscall_id_t *)out_msg_pos) = ISATTY_ID;
198         out_msg_pos += sizeof(syscall_id_t);
199
200         *((int*)out_msg_pos) = file;
201         out_msg_pos += sizeof(int);
202
203         // Send message
204         char *result = send_message(out_msg, ISATTY_MESSAGE_FIXED_SIZE);
205
206         free(out_msg);
207
208         int return_val;
209
210         if (result != NULL) {
211                 // Read result
212                 return_val = *((int *) result);
213                 if (return_val == 0) errno = *(((int *)result) + 1);
214                 free(result);
215         } else {
216                 errno = ECHANNEL;
217                 return_val = 0;
218         }
219         
220         return return_val;
221 }
222
223 /* kill()
224  * Send a signal. 
225  * Minimal implementation.
226  */
227 int kill(int pid, int sig) 
228 {
229         debug_in_out("KILL\n");
230         errno = EINVAL;
231     return -1;
232 }
233
234 /* link()
235  * Establish a new name for an existing file. 
236  * Minimal implementation.
237  */
238 int link(char *old, char *new) 
239 {
240         debug_in_out("LINK\n");
241         
242         int s_len_old = strlen(old) + 1; // Null terminator
243         int s_len_new = strlen(new) + 1; // Null terminator
244
245         int out_msg_len = LINK_MESSAGE_FIXED_SIZE + s_len_old + s_len_new;
246
247         // Allocate a new buffer of proper size
248         char *out_msg = malloc(out_msg_len);
249         char *out_msg_pos = out_msg;
250
251         if (out_msg == NULL)
252                 return -1;
253
254         // Fill the buffer
255         *((syscall_id_t *)out_msg_pos) = LINK_ID;
256         out_msg_pos += sizeof(syscall_id_t);
257
258         *((int*)out_msg_pos) = s_len_old;
259         out_msg_pos += sizeof(int);
260
261         *((int*)out_msg_pos) = s_len_new;
262         out_msg_pos += sizeof(int);
263
264         memcpy(out_msg_pos, old, s_len_old);
265         out_msg_pos += s_len_old;
266
267         memcpy(out_msg_pos, new, s_len_new);
268
269         // Send message
270         char *result = send_message(out_msg, out_msg_len);
271
272         free(out_msg);
273
274         // Read result
275         int return_val;
276
277         if (result != NULL) {
278                 return_val = *((int *)result);
279                 if (return_val == -1) errno = *(((int *)result) + 1);
280                 free(result);
281         } else {
282                 errno = ECHANNEL;
283                 return_val = -1;
284         }
285
286         return return_val;
287 }
288
289 /* lseek()
290  * Set position in a file. 
291  * Minimal implementation.
292  */
293 off_t lseek(int file, off_t ptr, int dir) 
294 {
295         debug_in_out("LSEEK\n");        
296         
297         // Allocate a new buffer of proper size
298         char *out_msg = malloc(LSEEK_MESSAGE_FIXED_SIZE);
299         if(out_msg == NULL)
300                 return -1;
301         char *out_msg_pos = out_msg;
302
303         // Fill the buffer
304         *((syscall_id_t *)out_msg_pos) = LSEEK_ID;
305         out_msg_pos += sizeof(syscall_id_t);
306
307         *((int*)out_msg_pos) = file;
308         out_msg_pos += sizeof(int);
309
310         *((int*)out_msg_pos) = ptr;
311         out_msg_pos += sizeof(int);
312
313         *((int*)out_msg_pos) = dir;
314         out_msg_pos += sizeof(int);
315
316         // Send message
317         char *result = send_message(out_msg, LSEEK_MESSAGE_FIXED_SIZE);
318
319         free(out_msg);
320
321         int return_val;
322
323         if (result != NULL) {
324                 // Read result
325                 return_val = *((int *) result);
326                 if (return_val == -1) errno = *(((int *)result) + 1);
327                 free(result);
328         } else {
329                 errno = ECHANNEL;
330                 return_val = -1;
331         }
332
333         return return_val;
334 }
335
336 /* open()
337  * Open a file. 
338  */
339 int open(const char *name, int flags, int mode) 
340 {
341         debug_in_out("OPEN\n");
342
343         int s_len = strlen(name) + 1; // Null terminator
344         int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
345
346         // Allocate a new buffer of proper size
347         char *out_msg = malloc(out_msg_len);
348         char *out_msg_pos = out_msg;
349
350         if (out_msg == NULL)
351                 return -1;
352
353         // Fill the buffer
354         *((syscall_id_t *)out_msg_pos) = OPEN_ID;
355         out_msg_pos += sizeof(syscall_id_t);
356
357         *((int*)out_msg_pos) = flags;
358         out_msg_pos += sizeof(int);
359
360         *((int*)out_msg_pos) = mode;
361         out_msg_pos += sizeof(int);
362
363         *((int*)out_msg_pos) = s_len;
364         out_msg_pos += sizeof(int);
365
366         memcpy(out_msg_pos, name, s_len);
367
368         // Send message
369         char *result = send_message(out_msg, out_msg_len);
370
371         free(out_msg);
372
373         // Read result
374         int return_val;
375
376         if (result != NULL) {
377                 return_val = *((int *)result);
378                 if (return_val == -1) errno = *(((int *)result) + 1);
379                 free(result);
380         } else {
381                 errno = ECHANNEL;
382                 return_val = -1;
383         }
384
385         return return_val;
386 }
387
388 /* read()
389  * Read from a file. 
390  */
391 ssize_t read(int file, void *ptr, size_t len) 
392 {
393         debug_in_out("READ\n");
394
395         if (file == STDIN_FILENO) {
396                 for(int i=0; i<len; i++)        
397                         ((uint8_t*)ptr)[i] = sys_cgetc();
398                 return len;
399         }
400
401         // Allocate a new buffer of proper size
402         char *out_msg = (char*)malloc(READ_MESSAGE_FIXED_SIZE);
403         if (out_msg == NULL)
404                 return -1;
405
406         char *out_msg_pos = out_msg;
407
408         // Fill the buffer
409         *((syscall_id_t *)out_msg_pos) = READ_ID;
410         out_msg_pos += sizeof(syscall_id_t);
411
412         *((int *)out_msg_pos) = file;
413         out_msg_pos += sizeof(int);
414
415         *((int *)out_msg_pos) = len;
416         out_msg_pos += sizeof(int);
417
418         // Send message
419         char *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
420
421         free(out_msg);
422
423         // Read result
424         int return_val;
425
426         if (result != NULL) {
427                 return_val = *((int *)result);
428                 if (return_val > 0)
429                         memcpy(ptr, ((int *)result) + 1, return_val);
430                 else 
431                         errno = *(((int *)result) + 1);
432
433                 free(result);
434         } else {
435                 errno = ECHANNEL;
436                 return_val = -1;
437         }
438
439         return return_val;
440 }
441
442 /* Read len bytes from the given channel to the buffer.
443  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
444  * If peek is PEEK, if no data is available, will return immediately.
445  *              However once some data is available, 
446  *                      will block until the entire amount is available.
447  */
448 int read_from_channel(char * buf, int len, int peek)
449 {
450         // TODO: NEED TO IMPLIMENT A TIMEOUT
451         //                      Also, watch out for CONNECTION TERMINATED
452         int total_read = 0;
453
454         int just_read = sys_serial_read(buf, len);
455
456
457         if (just_read < 0) return just_read;
458         if (just_read == 0 && peek) return just_read;
459
460         total_read += just_read;
461
462         while (total_read != len) {
463                 just_read = sys_serial_read(buf + total_read, len - total_read);
464
465                 if (just_read == -1) return -1;
466                 total_read += just_read;
467         }
468
469         return total_read;
470 }
471
472 /* sbrk()
473  * Increase program data space. 
474  * As malloc and related functions depend on this, it is 
475  * useful to have a working implementation. 
476  * The following suffices for a standalone system; it exploits the 
477  * symbol _end automatically defined by the GNU linker.
478  */
479 void* sbrk(ptrdiff_t incr) 
480 {
481         debug_in_out("SBRK\n");
482         debug_in_out("\tincr: %u\n", incr);     
483
484         #define HEAP_SIZE 8192
485         static uint8_t array[HEAP_SIZE];
486         static uint8_t* heap_end = array;
487         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
488
489         uint8_t* prev_heap_end; 
490
491         prev_heap_end = heap_end;
492         if (heap_end + incr > stack_ptr) {
493                 errno = ENOMEM;
494                 return (void*)-1;
495         }
496      
497         heap_end += incr;
498         debug_in_out("\treturning: %u\n", prev_heap_end);
499         return (caddr_t) prev_heap_end;
500 }
501
502 /* send_message()
503  * Write the message in buffer out on the channel, and wait for a response.
504  * Caller is responsible for management of buffer passed in and buffer returned.
505  */
506 char *send_message(char *message, int len)
507 {
508         syscall_id_t this_call_id = *((syscall_id_t*)message);
509
510         if (write_to_channel(message, len) != len)
511                 return NULL;
512
513         int response_value;
514
515         // Pull the response from the server out of the channel.
516         if (read_from_channel( (char*)&response_value, 
517                                sizeof(int), 
518                                NO_PEEK) == -1) 
519                 return NULL;
520
521         char* return_msg = NULL;
522         char* errno_pos = NULL;
523         int extra_space = (response_value == -1) ? sizeof(int) : 0;
524
525         // TODO: Make these sizes an array we index into, and only have this code once.
526         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
527         // TODO: Default clause with error handling.
528         switch (this_call_id) {
529                 case ISATTY_ID:
530                         // This case must be at the top! Else extra space will be wrong at times 
531                         // ISATTY is special, 0 signifies error, not -1. Annoying.
532                         extra_space = (response_value == 0) ? sizeof(int) : 0;
533                 case OPEN_ID:           
534                 case CLOSE_ID:
535                 case WRITE_ID:  
536                 case LSEEK_ID:
537                 case UNLINK_ID:
538                 case LINK_ID:
539                         return_msg = (char*)malloc(sizeof(int) + extra_space);
540                         if (return_msg == NULL)
541                                 return NULL;
542
543                         errno_pos = return_msg + sizeof(int);
544                         if (extra_space && (-1 == read_from_channel(errno_pos,
545                                                                     sizeof(int), 
546                                                                     NO_PEEK))) {
547                                 free(return_msg);
548                                 return NULL;
549                         }
550
551                         break;
552
553                 case STAT_ID:
554                 case FSTAT_ID:
555                         return_msg = (char*)malloc(sizeof(int) 
556                                                     + sizeof(struct stat)
557                                                     + extra_space);
558                         if (return_msg == NULL)
559                                 return NULL;
560
561                         if (-1 == read_from_channel(return_msg + sizeof(int),
562                                                     sizeof(struct stat), 
563                                                     NO_PEEK)) {
564                                 free(return_msg);
565                                 return NULL;
566                         }
567
568                         errno_pos = return_msg + sizeof(int) 
569                                                + sizeof(struct stat);
570
571                         if (extra_space && (-1 == read_from_channel(errno_pos,
572                                                                     sizeof(int), 
573                                                                     NO_PEEK))) {
574                                 free(return_msg);
575                                 return NULL;
576                         }
577
578                         break;
579                 
580                 case READ_ID:
581                         if (response_value > 0)
582                                 extra_space = response_value;
583                         else
584                                 extra_space = extra_space;
585
586                         return_msg = (char*)malloc(sizeof(int) + extra_space);
587
588                         if (return_msg == NULL)
589                                 return NULL;
590
591                         if (-1 == read_from_channel(return_msg + sizeof(int),
592                                                     extra_space,
593                                                     NO_PEEK)) {
594                                 free(return_msg);
595                                 return NULL;
596                         }
597
598                         break;
599
600         }
601
602         // Copy response value in place
603         memcpy(return_msg, &response_value, sizeof(int));
604
605         return return_msg;
606 }
607
608
609 /* stat()
610  * Status of a file (by name). 
611  * Minimal implementation.
612  */
613 int stat(char *file, struct stat *st) 
614 {
615         debug_in_out("STAT\n");
616         
617         int s_len = strlen(file) + 1; // Null terminator
618         int out_msg_len = STAT_MESSAGE_FIXED_SIZE + s_len;
619
620         // Allocate a new buffer of proper size
621         char *out_msg = malloc(out_msg_len);
622         char *out_msg_pos = out_msg;
623
624         if (out_msg == NULL)
625                 return -1;
626
627         // Fill the buffer
628         *((syscall_id_t *)out_msg_pos) = STAT_ID;
629         out_msg_pos += sizeof(syscall_id_t);
630
631         *((int*)out_msg_pos) = s_len;
632         out_msg_pos += sizeof(int);
633
634         memcpy(out_msg_pos, file, s_len);
635
636         // Send message
637         char *result = send_message(out_msg, out_msg_len);
638
639         free(out_msg);
640
641         // Read result
642         int return_val;
643
644         if (result != NULL) {
645                 return_val = *((int *)result);
646
647                 if (return_val == -1)
648                         errno = *(((char *)result) + sizeof(int) 
649                                                    + sizeof(struct stat));
650                 else
651                         memcpy(st, ((int *)result) + 1, sizeof(struct stat));
652
653                 free(result);
654
655         } else {
656                 errno = ECHANNEL;
657                 return_val = -1;
658         }
659
660         return return_val;
661 }
662
663 /* times()
664  * Timing information for current process. 
665  * Minimal implementation.
666  */
667 int times(struct tms *buf) 
668 {
669         debug_in_out("TIMES");
670         return -1;
671 }
672
673 /* unlink()
674  * Remove a file's directory entry. 
675  * Minimal implementation.
676  */
677 int unlink(char *name) 
678 {
679         debug_in_out("UNLINK\n");
680         
681         int s_len = strlen(name) + 1; // Null terminator
682         int out_msg_len = UNLINK_MESSAGE_FIXED_SIZE + s_len;
683
684         // Allocate a new buffer of proper size
685         char *out_msg = malloc(out_msg_len);
686         char *out_msg_pos = out_msg;
687
688         if (out_msg == NULL)
689                 return -1;
690
691         // Fill the buffer
692         *((syscall_id_t *)out_msg_pos) = UNLINK_ID;
693         out_msg_pos += sizeof(syscall_id_t);
694
695         *((int*)out_msg_pos) = s_len;
696         out_msg_pos += sizeof(int);
697
698         memcpy(out_msg_pos, name, s_len);
699
700         // Send message
701         char *result = send_message(out_msg, out_msg_len);
702
703         free(out_msg);
704
705         // Read result
706         int return_val;
707
708         if (result != NULL) {
709                 return_val = *((int *)result);
710                 if (return_val == -1) errno = *(((int *)result) + 1);
711                 free(result);
712         } else {
713                 errno = ECHANNEL;
714                 return_val = -1;
715         }
716         return return_val;
717 }
718
719 /* wait()
720  * Wait for a child process. 
721  * Minimal implementation.
722  */
723 int wait(int *status) 
724 {
725         debug_in_out("WAIT\n");
726         errno = ECHILD;
727         return -1;
728 }
729
730 /* write()
731  * Write to a file. 
732  */
733 ssize_t write(int file, void *ptr, size_t len) {
734         
735         debug_in_out("WRITE\n");        
736         debug_in_out("\tFILE: %u\n", file);
737
738         debug_write_check("Writing len: %d\n", len);
739
740         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
741                                    || (file == STDOUT_FILENO))
742                 return sys_cputs(ptr, len);
743         
744         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
745
746         // Allocate a new buffer of proper size
747         char *out_msg = malloc(out_msg_len);
748         char *out_msg_pos = out_msg;
749
750         // Fill the buffer
751         *((syscall_id_t *)out_msg_pos) = WRITE_ID;
752         out_msg_pos += sizeof(syscall_id_t);
753
754         *((int*)out_msg_pos) = file;
755         out_msg_pos += sizeof(int);
756
757         *((int*)out_msg_pos) = len;
758         out_msg_pos += sizeof(int);
759
760         memcpy(out_msg_pos, ptr, len);
761
762         // Send message
763         char *result = send_message(out_msg, out_msg_len);
764
765         free(out_msg);
766
767         // Read result
768         int return_val;
769
770         if (result != NULL) {
771                 return_val = *((int *)result);
772                 if (return_val == -1) errno = *(((int *)result) + 1);
773                 free(result);
774         } else {
775                 errno = ECHANNEL;
776                 return_val = -1;
777         }
778
779         return return_val;
780 }
781
782
783 /* write_to_channel()
784  * Send a message out over the channel, defined by msg, of length len
785  */
786 int write_to_channel(char * msg, int len)
787 {
788         return sys_serial_write((char*)msg, len);
789 }
790