Added function bodies for open, close, read, and write, as well as supporting functio...
[akaros.git] / user / parlib / src / parlib.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 <lib.h>
9 #include <parlib.h>
10
11 /* environ
12  * A pointer to a list of environment variables and their values. 
13  * For a minimal environment, this empty list is adequate.
14  */
15 char *__env[1] = { 0 };
16 char **environ = __env;
17 extern env_t* env;
18
19 /* _exit()
20  * Exit a program without cleaning up files. 
21  * If your system doesn't provide this, it is best to avoid linking 
22  * with subroutines that require it (exit, system).
23  */
24 void _exit() 
25 {
26         sys_env_destroy(env->env_id);
27 }
28     
29 /* close()
30  * Close a file. 
31  */
32 int close(int file) 
33 {
34         // Allocate a new buffer of proper size
35         byte *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
36         if(out_msg == NULL)
37                 return -1;
38
39         byte *out_msg_pos = out_msg;
40
41         // Fill the buffer
42         *((syscall_id *)out_msg_pos) = CLOSE_ID;
43         out_msg_pos += sizeof(syscall_id);
44
45         *((int*)out_msg_pos) = file;
46         out_msg_pos += sizeof(int);
47
48
49         // Send message
50         byte *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
51
52         free(out_msg);
53
54         if (result != NULL) {
55                 // Read result
56                 int return_val;
57                 return_val = *((int *) result);
58                 free(result);
59                 return return_val;
60         } else {
61                 return -1;
62         }
63 }
64
65 /* execve()
66  * Transfer control to a new process. 
67  * Minimal implementation (for a system without processes).
68  */
69
70 int execve(char *name, char **argv, char **env) 
71 {
72         errno = ENOMEM;
73         return -1;
74 }
75
76 /* fork()
77  * Create a new process. 
78  * Minimal implementation (for a system without processes).
79  */
80 int fork(void) 
81 {
82         errno = EAGAIN;
83     return -1;
84 }
85
86 /* fstat()
87  * Status of an open file. 
88  * For consistency with other minimal implementations in these stubs, 
89  * all files are regarded as character special devices. 
90  * The sys/stat.h header file required is distributed in the include 
91  * subdirectory for the newlib C library.
92  */
93 int fstat(int file, struct stat *st) 
94 {
95         st->st_mode = S_IFCHR;
96         return 0;
97 }
98
99 /* getpid()
100  * Process-ID; this is sometimes used to generate strings unlikely to 
101  * conflict with other processes. Minimal implementation, for a system 
102  * without processes.
103  */
104 int getpid(void) 
105 {
106         return env->env_id;
107 }
108
109 /* isatty()
110  * Query whether output stream is a terminal. 
111  * For consistency with the other minimal implementations, 
112  * which only support output to stdout, this minimal 
113  * implementation is suggested.
114  */
115 int isatty(int file) 
116 {
117         return 1;
118 }
119
120 /* kill()
121  * Send a signal. 
122  * Minimal implementation.
123  */
124 int kill(int pid, int sig) 
125 {
126         errno = EINVAL;
127     return -1;
128 }
129
130 /* link()
131  * Establish a new name for an existing file. 
132  * Minimal implementation.
133  */
134 int link(char *old, char *new) 
135 {
136         errno = EMLINK;
137         return -1;
138 }
139
140 /* lseek()
141  * Set position in a file. 
142  * Minimal implementation.
143  */
144 int lseek(int file, int ptr, int dir) 
145 {
146         return 0;
147 }
148
149 /* __sseek64()
150  * Set position in a file. 
151  * Minimal implementation.
152  */
153 int __sseek64(int file, int ptr, int dir) 
154 {
155         return 0;
156 }
157
158 /* open()
159  * Open a file. 
160  */
161 int open(const char *name, int flags, int mode) 
162 {
163         int s_len = strlen(name) + 1; // Null terminator
164         int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
165
166         // Allocate a new buffer of proper size
167         byte *out_msg = malloc(out_msg_len);
168         byte *out_msg_pos = out_msg;
169
170         if (out_msg == NULL)
171                 return -1;
172
173         // Fill the buffer
174         *((syscall_id*)out_msg_pos) = OPEN_ID;
175         out_msg_pos += sizeof(syscall_id);
176
177         *((int*)out_msg_pos) = flags;
178         out_msg_pos += sizeof(int);
179
180         *((int*)out_msg_pos) = mode;
181         out_msg_pos += sizeof(int);
182
183         *((int*)out_msg_pos) = s_len;
184         out_msg_pos += sizeof(int);
185
186         memcpy(out_msg_pos, name, s_len);
187
188         // Send message
189         byte *result = send_message(out_msg, out_msg_len);
190
191         free(out_msg);
192
193         // Read result
194         int return_val;
195
196         if (result != NULL) {
197                 return_val = *((int *)result);
198                 free(result);
199         } else {
200                 return_val = -1;
201         }
202
203         return return_val;
204 }
205
206 /* read()
207  * Read from a file. 
208  */
209 int read(int file, char *ptr, int len) 
210 {
211         // Allocate a new buffer of proper size
212         byte *out_msg = (byte*)malloc(READ_MESSAGE_FIXED_SIZE);
213         if (out_msg == NULL)
214                 return -1;
215
216         byte *out_msg_pos = out_msg;
217
218         // Fill the buffer
219         *((syscall_id*)out_msg_pos) = READ_ID;
220         out_msg_pos += sizeof(syscall_id);
221
222         *((int *)out_msg_pos) = file;
223         out_msg_pos += sizeof(int);
224
225         *((int *)out_msg_pos) = len;
226         out_msg_pos += sizeof(int);
227
228         // Send message
229         byte *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
230
231         free(out_msg);
232
233         // Read result
234         int return_val;
235
236         if (result != NULL) {
237                 return_val = *((int *)result);
238                 memcpy(ptr, ((int *)result) + 1, return_val);
239                 free(result);
240         } else {
241                 return_val = -1;
242         }
243
244         return return_val;
245 }
246
247 /* Read len bytes from the given channel to the buffer.
248  * If peek is 0, will wait indefinitely until that much data is read.
249  * If peek is 1, if no data is available, will return immediately.
250  *              However once some data is available, it will block until the entire amount is available.
251  */
252 int read_from_channel(byte * buf, int len, int peek)
253 {
254         // TODO: NEED TO IMPLIMENT A TIMEOUT
255         //                      Also, watch out for CONNECTION TERMINATED
256         // TODO: Add a #define for peek / no peek. Don't know why I didnt do this from the start?
257         int total_read = 0;
258
259         int just_read = sys_serial_read(buf, len);
260
261
262         if (just_read < 0) return just_read;
263         if (just_read == 0 && peek) return just_read;
264
265         total_read += just_read;
266
267         while (total_read != len) {
268                 just_read = read(buf + total_read, len - total_read);
269
270                 if (just_read == -1) return -1;
271                 total_read += just_read;
272         }
273
274         return total_read;
275 }
276
277 /* sbrk()
278  * Increase program data space. 
279  * As malloc and related functions depend on this, it is 
280  * useful to have a working implementation. 
281  * The following suffices for a standalone system; it exploits the 
282  * symbol _end automatically defined by the GNU linker.
283  */
284 caddr_t sbrk(int incr) 
285 {
286 /*
287         extern char _end;               // Defined by the linker
288         static char *heap_end;
289         char *prev_heap_end;
290
291         if (heap_end == 0) {
292                 heap_end = &_end;
293         }
294         prev_heap_end = heap_end;
295         if (heap_end + incr > stack_ptr) {
296                 write (1, "Heap and stack collision\n", 25);
297                 abort ();
298         }
299       
300         heap_end += incr;
301         return (caddr_t) prev_heap_end;
302 */
303         errno = ENOMEM;
304         return (void*)-1;
305 }
306
307 /* send_message()
308  * Write the message defined in buffer out across the channel, and wait for a response.
309  * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
310  */
311 byte *send_message(byte *message, int len)
312 {
313
314         syscall_id this_call_id = *((syscall_id*)message);
315
316         if (write_to_channel(message, len) != len)
317                 return NULL;
318
319         int response_value;
320
321         // Pull the response from the server out of the channel.
322         if (read_from_channel((char*)&response_value, sizeof(int), 0) == -1) return NULL;
323
324         byte* return_msg;
325
326         // TODO: Make these sizes an array we index into, and only have this code once.
327         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
328         // TODO: Default clause with error handling.
329         switch (this_call_id) {
330                 case OPEN_ID:
331                         if ((return_msg = (byte*)malloc(OPEN_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
332                                 return NULL;
333
334                         break;
335
336                 case CLOSE_ID:
337                         if ((return_msg = (byte*)malloc(CLOSE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
338                                 return NULL;
339
340                         break;
341
342                 case READ_ID:
343                         if ((return_msg = (byte*)malloc(READ_RETURN_MESSAGE_FIXED_SIZE + response_value)) == NULL)
344                                 return NULL;
345
346
347                         if ((read_from_channel(return_msg + sizeof(int), response_value, 0)) == -1)
348                                 return NULL;
349
350                         break;
351
352                 case WRITE_ID:
353                         if ((return_msg = (byte*)malloc(WRITE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
354                                 return NULL;
355
356                         break;
357
358
359                 case LSEEK_ID:
360                         if ((return_msg = (byte*)malloc(LSEEK_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
361                                 return NULL;
362
363                         break;
364
365                 case ISATTY_ID:
366                         if ((return_msg = (byte*)malloc(ISATTY_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
367                                 return NULL;
368
369                         break;
370
371                 case UNLINK_ID:
372                         if ((return_msg = (byte*)malloc(UNLINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
373                                 return NULL;
374
375
376                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
377                                 return NULL;
378
379                         break;
380
381                 case LINK_ID:
382                         if ((return_msg = (byte*)malloc(LINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
383                                 return NULL;
384
385
386                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
387                                 return NULL;
388
389                         break;
390
391                 case FSTAT_ID:
392                         if ((return_msg = (byte*)malloc(FSTAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
393                                 return NULL;
394
395                         if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
396                                 return NULL;
397
398                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
399                                 return NULL;
400
401                         break;
402
403                 case STAT_ID:
404                         if ((return_msg = (byte*)malloc(STAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
405                                 return NULL;
406
407                         if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
408                                 return NULL;
409
410                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
411                                 return NULL;
412
413                         break;
414         }
415
416         memcpy(return_msg, &response_value, sizeof(int));
417
418         return return_msg;
419 }
420
421
422 /* stat()
423  * Status of a file (by name). 
424  * Minimal implementation.
425  */
426 int stat(char *file, struct stat *st) 
427 {
428         st->st_mode = S_IFCHR;
429         return 0;
430 }
431
432 /* times()
433  * Timing information for current process. 
434  * Minimal implementation.
435  */
436 int times(struct tms *buf) 
437 {
438         return -1;
439 }
440
441 /* unlink()
442  * Remove a file's directory entry. 
443  * Minimal implementation.
444  */
445 int unlink(char *name) 
446 {
447         errno = ENOENT;
448         return -1;
449 }
450
451 /* wait()
452  * Wait for a child process. 
453  * Minimal implementation.
454  */
455 int wait(int *status) 
456 {
457         errno = ECHILD;
458         return -1;
459 }
460
461 /* write()
462  * Write to a file. 
463  */
464 int write(int file, char *ptr, int len) {
465         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
466
467         // Allocate a new buffer of proper size
468         byte *out_msg = malloc(out_msg_len);
469         byte *out_msg_pos = out_msg;
470
471         // Fill the buffer
472         *((syscall_id*)out_msg_pos) = WRITE_ID;
473         out_msg_pos += sizeof(syscall_id);
474
475         *((int*)out_msg_pos) = file;
476         out_msg_pos += sizeof(int);
477
478         *((int*)out_msg_pos) = len;
479         out_msg_pos += sizeof(int);
480
481         memcpy(out_msg_pos, ptr, len);
482
483         // Send message
484         byte *result = send_message(out_msg, out_msg_len);
485
486         free(out_msg);
487
488         // Read result
489         int return_val;
490
491         if (result != NULL) {
492                 return_val = *((int *)result);
493                 free(result);
494         } else {
495                 return_val = -1;
496         }
497
498         return return_val;
499 }
500
501
502 /* write_to_channel()
503  * Send a message out over the channel, defined by msg, of length len
504  */
505 int write_to_channel(byte * msg, int len)
506 {
507         return sys_serial_write((char*)msg, len);
508 }
509
510 /* __swrite64()
511  * Write to a file. 
512  */
513 int __swrite64(int file, char *ptr, int len) {
514         return 0;
515 }