Functonal webserver with supporting code changes. WIP COMMIT
[akaros.git] / user / parlib / src / i386 / newlib_backend.c
1 /* See COPYRIGHT for copyright information. */
2
3 /** @file
4  * @brief Backend file for newlib functionality
5  *
6  * This file is responsible for defining the syscalls needed by newlib to 
7  * impliment the newlib library
8  * *
9  * @author Paul Pearce <pearce@eecs.berkeley.edu>
10  * @author Kevin Klues <klueska@cs.berkeley.edu>
11  *
12  */
13
14 #include <parlib.h>
15 #include <unistd.h>
16 #include <newlib_backend.h>
17 #include <string.h>
18 #include <malloc.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <debug.h>
22 #include <sys/times.h>
23 #include <assert.h>
24 #include <dirent.h>
25
26 /* These are stubs for newlib syscalls that 
27    exist on the sparc platform, but not x86.
28
29    Paul TODO: Ship or do locally?
30 */
31
32 DIR *opendir (const char *name) { assert(0); }
33 struct dirent *readdir (DIR *d) { assert(0); }
34 void rewinddir (DIR *d) { assert(0); }
35 int closedir (DIR *d) { assert(0); }
36 int access (const char *name, int mode) { return 0; }
37 int gettimeofday(struct timeval* tp, void* tzp) { return 0; }
38
39 /* environ
40  * A pointer to a list of environment variables and their values. 
41  * For a minimal environment, this empty list is adequate.
42  */
43 /* These are defined inside of newlib.
44 char *__env[1] = { 0 };
45 char **environ = __env;
46 */
47
48 /* _exit()
49  * Exit a program without cleaning up files. 
50  * If your system doesn't provide this, it is best to avoid linking 
51  * with subroutines that require it (exit, system).
52  */
53 void _exit(int __status)
54 {
55         sys_proc_destroy(sys_getpid(),__status); // TODO: can run getpid and cache it
56         while(1); //Should never get here...
57 }
58     
59 /* close()
60  * Close a file. 
61  */
62 int close(int file) {
63         close_subheader_t msg;
64         debug_in_out("CLOSE\n");
65
66         // If trying to close stdin/out/err just return
67         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
68                                    || (file == STDOUT_FILENO))
69                 return 0;
70         
71         msg.id = CLOSE_ID;
72         msg.fd = file;
73         
74         // Send message
75         response_t *result = send_message((char*)&msg, sizeof(close_subheader_t),CLOSE_ID);
76
77         int return_val;
78
79         if (result == NULL) {
80                 errno = ECHANNEL;
81                 return_val = -1;
82         } else {
83                 // Read result
84                 return_val = result->ret;
85                 if (return_val == -1) errno = result->err;
86                 free(result);
87         }
88         
89         return return_val;
90 }
91
92 /* execve()
93  * Transfer control to a new process. 
94  * Minimal implementation (for a system without processes).
95  */
96
97 int execve(const char *name, char * const argv[], char * const env[]) 
98 {
99         debug_in_out("EXECVE\n");
100         errno = ENOMEM;
101         return -1;
102 }
103
104 /* fork()
105  * Create a new process. 
106  * Minimal implementation (for a system without processes).
107  */
108 pid_t fork(void) 
109 {
110         debug_in_out("FORK\n");
111         errno = EAGAIN;
112     return -1;
113 }
114
115 /* fstat()
116  * Status of an open file. 
117  * For consistency with other minimal implementations in these stubs, 
118  * all files are regarded as character special devices. 
119  * The sys/stat.h msg file required is distributed in the include 
120  * subdirectory for the newlib C library.
121  */
122 int fstat(int file, struct stat *st) 
123 {
124         fstat_subheader_t msg;
125         debug_in_out("FSTAT\n");        
126
127         // Kevin added this. I believe its needed for the serial branch
128         // Not used with the stdout hack. Review for removing stdout hack.
129         //st->st_mode = S_IFCHR;
130         
131         // stdout hack
132         if (file == 1) {
133                 st->st_mode = 8592;
134                 return 0;
135         }
136         
137         msg.id = FSTAT_ID;
138         msg.fd = file;
139
140         // Send message
141         response_t *result = send_message((char*)&msg, sizeof(fstat_subheader_t),FSTAT_ID);
142
143         // Read result
144         int return_val;
145
146         if (result == NULL) {
147                 errno = ECHANNEL;
148                 return_val = -1;
149         } else {
150                 return_val = result->ret;
151                 if (return_val == -1)
152                         errno = result->err;
153                 else
154                         memcpy(st, result->buf, sizeof(struct stat));
155                         
156                 free(result);
157         }
158
159         return return_val;
160 }
161
162 /* getpid()
163  * Process-ID; this is sometimes used to generate strings unlikely to 
164  * conflict with other processes. Minimal implementation, for a system 
165  * without processes.
166  */
167 pid_t getpid(void) 
168 {
169         return sys_getpid(); // TODO: can run getpid and cache it
170 }
171
172 /* isatty()
173  * Query whether output stream is a terminal. 
174  * For consistency with the other minimal implementations, 
175  * which only support output to stdout, this minimal 
176  * implementation is suggested.
177  */
178 int isatty(int file) 
179 {
180         isatty_subheader_t msg;
181         debug_in_out("ISATTY\n");
182
183         // Cheap hack to avoid sending serial comm for stuff we know
184         if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
185                                || (STDERR_FILENO == file))
186                 return 1;
187         
188         msg.id = ISATTY_ID;
189         msg.fd = file;
190
191         // Send message
192         response_t *result = send_message((char*)&msg, sizeof(isatty_subheader_t),ISATTY_ID);
193
194         int return_val; 
195
196         // Note: Ret val of 0 defined to be an error, not < 0. Go figure.
197         if (result == NULL) {
198                 errno = ECHANNEL;
199                 return_val = 0;
200         } else {
201                 // Read result
202                 return_val = result->ret;
203                 if (return_val == 0) errno = result->err;
204                 free(result);
205         } 
206         
207         return return_val;
208 }
209
210 /* kill()
211  * Send a signal. 
212  * Minimal implementation.
213  */
214 int kill(int pid, int sig) 
215 {
216         debug_in_out("KILL\n");
217         errno = EINVAL;
218     return -1;
219 }
220
221 /* link()
222  * Establish a new name for an existing file. 
223  * Minimal implementation.
224  */
225 int link(const char *old, const char *new) 
226 {
227         link_subheader_t *msg;
228         response_t *result;
229         debug_in_out("LINK\n");
230         
231         int s_len_old = strlen(old) + 1; // Null terminator
232         int s_len_new = strlen(new) + 1; // Null terminator
233
234         msg = malloc(sizeof(link_subheader_t) + s_len_old + s_len_new);
235         if (msg == NULL)
236                 return -1;
237         
238         msg->id = LINK_ID;
239         msg->old_len = s_len_old;
240         msg->new_len = s_len_new;
241         msg->total_len = s_len_old + s_len_new;
242         
243         memcpy(msg->buf, old, s_len_old - 1);
244         msg->buf[s_len_old - 1] = '\0';
245         memcpy(msg->buf + s_len_old, new, s_len_new - 1);
246         msg->buf[s_len_old + s_len_new - 1] = '\0';
247
248         // Send message
249         result =
250                 send_message((char *CT(sizeof(link_subheader_t)+s_len_old+s_len_new))TC(msg),
251                          sizeof(link_subheader_t) + msg->total_len,LINK_ID);
252
253         free(msg);
254
255         // Read result
256         int return_val;
257
258         if (result == NULL) {
259                 errno = ECHANNEL;
260                 return_val = -1;
261         } else {
262                 return_val = result->ret;
263                 if (return_val == -1) errno = result->err;
264                 free(result);
265         }
266
267         return return_val;
268 }
269
270 /* lseek()
271  * Set position in a file. 
272  * Minimal implementation.
273  */
274 off_t lseek(int file, off_t ptr, int dir) 
275 {
276         lseek_subheader_t msg;
277         debug_in_out("LSEEK\n");        
278         
279         msg.id = LSEEK_ID;
280         msg.fd = file;
281         msg.ptr = ptr;
282         msg.dir = dir;
283
284         // Send message
285         response_t *result = send_message((char*)&msg, sizeof(lseek_subheader_t),LSEEK_ID);
286
287         int return_val;
288
289         if (result == NULL) {
290                 errno = ECHANNEL;
291                 return_val = -1;
292         } else {
293                 // Read result
294                 return_val = result->ret;
295                 if (return_val == -1) errno = result->err;
296                 free(result);
297         }
298
299         return return_val;
300 }
301
302 /* open()
303  * Open a file. 
304  */
305 int open(const char *name, int flags, int mode) 
306 {
307         open_subheader_t *msg;
308         debug_in_out("OPEN\n");
309
310         int s_len = strlen(name) + 1; // Null terminator
311
312         msg = malloc(sizeof(open_subheader_t) + s_len);
313         if (msg == NULL)
314                 return -1;
315
316         msg->id = OPEN_ID;
317         msg->flags = flags;
318         msg->mode = mode;
319         msg->len = s_len;
320
321         memcpy(msg->buf, name, s_len - 1);
322         msg->buf[s_len - 1] = '\0';
323
324         // Send message
325         response_t *result =
326                 send_message((char *CT(sizeof(open_subheader_t)+s_len))TC(msg),
327                          sizeof(open_subheader_t) + s_len,OPEN_ID);
328
329         free(msg);
330
331         // Read result
332         int return_val;
333
334         if (result == NULL) {
335                 errno = ECHANNEL;
336                 return_val = -1;
337         } else {
338                 return_val = result->ret;
339                 if (return_val == -1) errno = result->err;
340                 free(result);
341         } 
342
343         return return_val;
344 }
345
346 /* read()
347  * Read from a file. 
348  */
349 ssize_t read(int file, void *ptr, size_t len) 
350 {
351         read_subheader_t msg;
352         uint8_t *CT(len) _ptr = ptr;
353         debug_in_out("READ\n");
354
355         // Console hack.
356         if (file == STDIN_FILENO) {
357                 for(int i=0; i<len; i++)        
358                         _ptr[i] = (uint8_t)sys_cgetc();
359                 return len;
360         }
361         
362         msg.id = READ_ID;
363         msg.fd = file;
364         msg.len = len;
365         
366         // Send message
367         response_t *result = send_message((char*)&msg, sizeof(read_subheader_t),READ_ID);
368
369         // Read result
370         int return_val;
371
372         if (result == NULL) {
373                 errno = ECHANNEL;
374                 return_val = -1;
375         } else {
376                 return_val = result->ret;
377                 if (return_val < 0)
378                         errno = result->err;
379                 else
380                         memcpy(_ptr, result->buf, return_val);
381
382                 free(result);
383         }
384
385         return return_val;
386 }
387
388 /* Read len bytes from the given channel to the buffer.
389  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
390  * If peek is PEEK, if no data is available, will return immediately.
391  *              However once some data is available, 
392  *                      will block until the entire amount is available.
393  */
394 int read_from_channel(char * buf, int len, int peek)
395 {
396         // TODO: NEED TO IMPLIMENT A TIMEOUT
397         //                      Also, watch out for CONNECTION TERMINATED
398         int total_read = 0;
399
400         #ifdef __NETWORK__
401                 printf("PAUL BROKE ME FIX SYS ETH READ\n");
402                 int just_read = 0;
403                 //int just_read = sys_eth_read(buf, len);
404         #else
405                 int just_read = sys_serial_read(buf, len);
406         #endif
407
408         if (just_read < 0) return just_read;
409         if (just_read == 0 && peek) return just_read;
410
411         total_read += just_read;
412
413         while (total_read != len) {
414                 
415                 #ifdef __NETWORK__
416                         printf("PAUL BROKE ME. FIX SYS ETH READ\n");
417                         //just_read = sys_eth_read(buf + total_read, len - total_read);
418                 #else
419                         just_read = sys_serial_read(buf + total_read, len - total_read);
420                 #endif
421         
422                 if (just_read == -1) return -1;
423                 total_read += just_read;
424         }
425
426         return total_read;
427 }
428
429 int read_response_from_channel(response_t *response) 
430 {
431         return read_from_channel(       (char*CT(sizeof(response_t))) TC(response), 
432                                                 sizeof(response_t), 
433                                                                 NO_PEEK);
434 }
435
436 int read_buffer_from_channel(char *buf, int len) 
437 {
438         return read_from_channel(       buf, 
439                                                 len, 
440                                                                 NO_PEEK);
441 }
442
443 /* send_message()
444  * Write the message in buffer out on the channel, and wait for a response.
445  * Caller is responsible for management of buffer passed in and buffer returned.
446  */
447 response_t *send_message(char *msg, int len, syscall_id_t this_call_id)
448 {
449         if (write_to_channel(msg, len) != len)
450                 return NULL;
451
452         int ret_value, buffer_size;
453         
454         response_t temp_response;
455         response_t *return_response = NULL;
456
457         // Pull the response from the server out of the channel.
458         if (read_response_from_channel( &temp_response ) == -1) 
459                 return NULL;
460
461         ret_value = temp_response.ret;
462         
463         char* buffer = NULL;
464
465         if (   this_call_id == READ_ID 
466             || this_call_id == FSTAT_ID 
467             || this_call_id == STAT_ID)
468         {
469                 if (ret_value < 0)
470                         buffer_size = 0;
471                 else {
472                         if(this_call_id == READ_ID) 
473                                 buffer_size = ret_value;
474                         else
475                                 buffer_size = sizeof(struct stat);
476                 }
477                         
478                 return_response = malloc(sizeof(response_t) + buffer_size);
479
480                 if (return_response == NULL)
481                         return NULL;
482                 
483                 if (read_buffer_from_channel(return_response->buf, buffer_size) == -1) {
484                         free(return_response);
485                         return NULL;
486                 }
487         } 
488         else 
489         {
490                         
491                 return_response = malloc(sizeof(response_t));
492                 
493                 if (return_response == NULL)
494                         return NULL;
495         }
496
497         *return_response = temp_response;
498
499         return return_response;
500 }
501
502
503 /* stat()
504  * Status of a file (by name). 
505  * Minimal implementation.
506  */
507 int stat(const char *file, struct stat *st) 
508 {
509         stat_subheader_t *msg;
510         debug_in_out("STAT\n");
511         
512         int s_len = strlen(file) + 1; // Null terminator
513
514         // Allocate a new buffer of proper size and pack
515         msg = malloc(sizeof(stat_subheader_t) + s_len);
516         if (msg == NULL)
517                 return -1;
518         
519         msg->id = STAT_ID;
520         msg->len = s_len;
521
522         memcpy(msg->buf, file, s_len - 1);
523         msg->buf[s_len - 1] = '\0';
524
525         // Send message
526         response_t *result =
527                 send_message((char *CT(sizeof(stat_subheader_t) + s_len))TC(msg),
528                              sizeof(stat_subheader_t) + s_len, STAT_ID);
529
530         free(msg);
531
532         // Read result
533         int return_val;
534
535         if (result == NULL) {
536                 errno = ECHANNEL;
537                 return_val = -1;
538         } else {
539                 return_val = result->ret;
540
541                 if (return_val == -1)
542                         errno = result->err;
543                 else
544                         memcpy(st, result->buf, sizeof(struct stat));
545
546                 free(result);
547
548         }
549
550         return return_val;
551 }
552
553 /* times()
554  * Timing information for current process. 
555  * Minimal implementation.
556  */
557 clock_t times(struct tms *buf) 
558 {
559         debug_in_out("TIMES");
560         return -1;
561 }
562
563 /* unlink()
564  * Remove a file's directory entry. 
565  * Minimal implementation.
566  */
567 int unlink(const char *name) 
568 {
569         unlink_subheader_t *msg;
570         debug_in_out("UNLINK\n");
571         
572         int s_len = strlen(name) + 1; // Null terminator
573
574         // Allocate a new buffer of proper size and pack
575         msg = malloc(sizeof(unlink_subheader_t) + s_len);
576         if (msg == NULL)
577                 return -1;
578         
579         msg->id = UNLINK_ID;
580         msg->len = s_len;
581         
582         memcpy(msg->buf, name, s_len - 1);
583         msg->buf[s_len - 1] = '\0';
584
585         // Send message
586         response_t *result =
587                 send_message((char *CT(sizeof(unlink_subheader_t) + s_len))TC(msg),
588                              sizeof(unlink_subheader_t) + s_len,UNLINK_ID);
589
590         free(msg);
591
592         // Read result
593         int return_val;
594
595         if (result == NULL) {
596                 errno = ECHANNEL;
597                 return_val = -1;
598         } else {
599                 return_val = result->ret;
600                 if (return_val == -1) errno = result->err;
601                 free(result);
602         } 
603         
604         return return_val;
605 }
606
607 /* wait()
608  * Wait for a child process. 
609  * Minimal implementation.
610  */
611 int wait(int *status) 
612 {
613         debug_in_out("WAIT\n");
614         errno = ECHILD;
615         return -1;
616 }
617
618 /* write()
619  * Write to a file. 
620  */
621 ssize_t write(int file, const void *ptr, size_t len)
622 {
623         write_subheader_t *msg;
624         debug_in_out("WRITE\n");        
625         debug_in_out("\tFILE: %u\n", file);
626
627         debug_write_check("Writing len: %d\n", len);
628
629         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
630                                    || (file == STDOUT_FILENO))
631                 return sys_cputs(ptr, len);
632         
633         // Allocate a new buffer of proper size and pack
634         msg = malloc(sizeof(write_subheader_t) + len);
635         if (msg == NULL)
636                 return -1;
637         
638         msg->id = WRITE_ID;
639         msg->fd = file;
640         msg->len = len;
641
642         memcpy(msg->buf, ptr, len);
643
644         // Send message
645         response_t *result =
646                 send_message((char *CT(sizeof(write_subheader_t) + len))TC(msg),
647                              sizeof(write_subheader_t) + len,WRITE_ID);
648
649         free(msg);
650
651         // Read result
652         int return_val;
653
654         if (result == NULL) {
655                 errno = ECHANNEL;
656                 return_val = -1;
657         } else {
658                 return_val = result->ret;
659                 if (return_val == -1) errno = result->err;
660                 free(result);
661         } 
662
663         return return_val;
664 }
665
666
667 /* write_to_channel()
668  * Send a message out over the channel, defined by msg, of length len
669  */
670 int write_to_channel(char * msg, int len)
671 {
672         #ifdef __NETWORK__
673                 return sys_eth_write(msg, len);
674         #else
675                 return sys_serial_write(msg, len);
676         #endif
677 }