25ed62b8b053b9759cbe31124f5ddc9740dc33f0
[akaros.git] / tools / syscall_server / syscall_server.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <stdio.h>
6 #include <sys/stat.h>
7 #include <malloc.h>
8 #include <termios.h>
9 #include <strings.h>
10 #include "syscall_server.h"
11
12 #define debug(...) printf(__VA_ARGS__)  
13
14 int main()
15 {
16         run_server();
17         return 0;
18 }
19
20 // Poll for incoming messages and send responses. 
21 void run_server() 
22 {
23         // Struct for reading the syscall over the channel
24         syscall_req_t syscall_req;
25         syscall_rsp_t syscall_rsp;
26         
27         int fd_read, fd_write;
28         int ret = init_syscall_server(&fd_read, &fd_write);
29         if(ret < 0)
30                 error(ret, "Could not open file desciptors for communication\n");
31
32         printf("Server started....");
33         // Continuously read in data from the channel socket
34         while(1) {
35                 syscall_req.payload_len = 0;
36                 syscall_req.payload = NULL;
37                 syscall_rsp.payload_len = 0;
38                 syscall_rsp.payload = NULL;
39         
40                 debug("\nWaiting for syscall...\n");
41                 read_syscall_req(fd_read, &syscall_req);        
42
43                 debug("Processing syscall: %d\n", syscall_req.header.id);
44                 handle_syscall(&syscall_req, &syscall_rsp);
45
46                 debug("Writing response: %d\n", syscall_req.header.id);
47                 write_syscall_rsp(fd_write, &syscall_rsp);
48
49                 if(syscall_req.payload != NULL)
50                         free(syscall_req.payload);
51                 if(syscall_rsp.payload != NULL)
52                         free(syscall_rsp.payload);
53         }
54 }
55
56 void read_syscall_req(int fd, syscall_req_t* req) 
57 {
58         read_syscall_req_header(fd, req);
59         set_syscall_req_payload_len(req);
60         read_syscall_req_payload(fd, req);
61 }
62
63 void set_syscall_req_payload_len(syscall_req_t* req)
64 {
65         switch(req->header.id) {
66                 case OPEN_ID:
67                         req->payload_len = req->header.subheader.open.len;
68                         break;
69                 case WRITE_ID:
70                         req->payload_len = req->header.subheader.write.len;
71                         break;
72                 case LINK_ID:
73                         req->payload_len = req->header.subheader.link.old_len
74                                            + req->header.subheader.link.new_len;
75                         break;
76                 case UNLINK_ID:
77                         req->payload_len = req->header.subheader.unlink.len;
78                         break;
79                 case STAT_ID:
80                         req->payload_len = req->header.subheader.stat.len;
81                         break;
82         }
83 }
84
85 void read_syscall_req_header(int fd, syscall_req_t* req) 
86 {
87         // Try to read the syscall id from the socket.
88         // If no data available, spin until there is
89         int bytes_read = 0;
90         bytes_read = read_from_channel(fd, &req->header, sizeof(req->header.id), 0);
91
92         // If no data, or the ID we got is bad, terminate process.
93         uint32_t id = req->header.id;
94         if ((bytes_read < 0) || (id < 0) || (id > NUM_SYSCALLS)) {
95                 perror("Problems reading the id from the channel...");
96         }
97
98         // Otherwise, start grabbing the rest of the data
99         bytes_read = read_from_channel(fd, &req->header.subheader, 
100                                   sizeof(req->header.subheader) , 0);
101         if(bytes_read < 0)
102                 error(fd, "Problems reading header from the channel...");
103 }
104
105 void read_syscall_req_payload(int fd, syscall_req_t* req) {
106         if (req->payload_len == 0)
107                 return;
108                 
109         req->payload = malloc(req->payload_len);
110         if (req->payload == NULL) 
111                 error(fd, "No free memory!");
112
113         int bytes_read = read_from_channel(fd, req->payload, req->payload_len, 0);
114         if (bytes_read < 0)
115                 error(fd, "Problems reading payload from channel");
116 }
117
118 // Read len bytes from the given socket to the buffer.
119 // If peek is 0, will wait indefinitely until that much data is read.
120 // If peek is 1, if no data is available, will return immediately.
121 int read_from_channel(int fd, void* buf, int len, int peek) 
122 {
123         int total_read = 0;
124         int just_read = read_syscall_server(fd, buf, len);
125
126         if (just_read < 0) return just_read;
127         if (just_read == 0 && peek) return just_read;
128
129         total_read += just_read;
130
131         while (total_read != len) {
132                 just_read = read_syscall_server(fd, buf + total_read, len - total_read);
133                 if (just_read < 0) return just_read;
134                 total_read += just_read;
135         }
136         return total_read;
137 }
138
139 // Send CONNECTION_TERMINATED over the FD (if possible)
140 void error(int fd, const char* s)
141 {
142         fprintf(stderr, "Error: FD: %i\n",fd);
143         perror(s);
144     fprintf(stderr, "Sending CONNECTION_TERMINATED.... \n");
145         close(fd);
146         exit(-1);
147 }
148
149 void handle_syscall(syscall_req_t* req, syscall_rsp_t* rsp)
150 {
151         switch (req->header.id) {
152                 case OPEN_ID:
153                         handle_open(req, rsp);
154                         break;
155                 case CLOSE_ID:
156                         handle_close(req, rsp);
157                         break;
158                 case READ_ID:
159                         handle_read(req, rsp);
160                         break;
161                 case WRITE_ID:
162                         handle_write(req, rsp);
163                         break;
164                 case LINK_ID:
165                         handle_link(req, rsp);
166                         break;
167                 case UNLINK_ID:
168                         handle_unlink(req, rsp);
169                         break;
170                 case LSEEK_ID:
171                         handle_lseek(req, rsp);
172                         break;
173                 case FSTAT_ID:
174                         handle_fstat(req, rsp);
175                         break;
176                 case ISATTY_ID:
177                         handle_isatty(req, rsp);
178                         break;
179                 case STAT_ID:
180                         handle_stat(req, rsp);
181                         break;
182                 default:
183                         error(-1, "Illegal syscall, should never be here...");
184         }
185         
186         rsp->header.return_errno = errno;
187 }
188
189 void write_syscall_rsp(int fd, syscall_rsp_t* rsp) 
190 {
191         write_syscall_rsp_header(fd, rsp);
192         write_syscall_rsp_payload(fd, rsp);
193 }
194
195 void write_syscall_rsp_header(int fd, syscall_rsp_t* rsp) 
196 {
197         int written = write_syscall_server(fd, &rsp->header, sizeof(syscall_rsp_header_t), rsp->payload_len);
198         if (written < 0)
199                 error(fd, "Problems writing the syscall response header...");   
200 }
201
202 void write_syscall_rsp_payload(int fd, syscall_rsp_t* rsp) 
203 {
204         if(rsp->payload_len == 0)
205                 return;
206
207         int written = write_syscall_server(fd, rsp->payload, rsp->payload_len, 0);
208         if (written < 0)
209                 error(fd, "Problems writing the syscall response payload...");  
210         if (written < rsp->payload_len)
211                 error(fd, "Problems writing all bytes in the response payload...");     
212 }
213
214 char* sandbox_file_name(char* name, uint32_t len) {
215         char* new_name = malloc(len + strnlen(SANDBOX_DIR));
216         sprintf(new_name, "%s%s", SANDBOX_DIR, name);
217         printf("%s\n", new_name);
218         return new_name;
219 }
220
221 void handle_open(syscall_req_t* req, syscall_rsp_t* rsp)
222 {
223         char* name = sandbox_file_name(req->payload, req->payload_len);
224         open_subheader_t* o = &req->header.subheader.open;      
225         int native_flags = translate_flags(o->flags);
226         int native_mode = translate_mode(o->mode);
227         rsp->header.return_val = open(name, native_flags, native_mode);
228         free(name);
229 }
230
231 void handle_close(syscall_req_t* req, syscall_rsp_t* rsp)
232 {
233         close_subheader_t* c = &req->header.subheader.close;    
234         rsp->header.return_val = close(c->fd);
235 }
236
237 void handle_read(syscall_req_t* req, syscall_rsp_t* rsp)
238 {
239         read_subheader_t* r = &req->header.subheader.read;      
240         rsp->payload = malloc(r->len);
241         rsp->header.return_val = read(r->fd, rsp->payload, r->len);
242         if(rsp->header.return_val >= 0)
243                 rsp->payload_len = rsp->header.return_val;
244 }
245
246 void handle_write(syscall_req_t* req, syscall_rsp_t* rsp)
247 {
248         write_subheader_t* w = &req->header.subheader.write;    
249         rsp->header.return_val = write(w->fd, req->payload, w->len);
250 }
251
252 void handle_link(syscall_req_t* req, syscall_rsp_t* rsp)
253 {
254         link_subheader_t* l = &req->header.subheader.link;      
255         char* old_name = sandbox_file_name(req->payload, l->old_len);
256         char* new_name = sandbox_file_name(req->payload + l->old_len, l->new_len);
257         rsp->header.return_val = link(old_name, new_name); 
258         free(old_name);
259         free(new_name);
260 }
261
262 void handle_unlink(syscall_req_t* req, syscall_rsp_t* rsp)
263 {
264         char* name = sandbox_file_name(req->payload, req->payload_len);
265         rsp->header.return_val = unlink(name); 
266         free(name);
267 }
268
269 void handle_lseek(syscall_req_t* req, syscall_rsp_t* rsp)
270 {
271         lseek_subheader_t* l = &req->header.subheader.lseek;    
272         int native_whence = translate_whence(l->dir); 
273         rsp->header.return_val = lseek(l->fd, l->ptr, native_whence);
274 }
275
276 void handle_fstat(syscall_req_t* req, syscall_rsp_t* rsp)
277 {
278         struct stat native_struct;
279         fstat_subheader_t* f = &req->header.subheader.fstat;    
280         rsp->payload = malloc(sizeof(newlib_stat_t));
281         rsp->header.return_val = fstat(f->fd, &native_struct); 
282         if(rsp->header.return_val >= 0)
283                 rsp->payload_len = sizeof(newlib_stat_t);
284         
285         translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
286 }
287
288 void handle_isatty(syscall_req_t* req, syscall_rsp_t* rsp)
289 {
290         isatty_subheader_t* i = &req->header.subheader.isatty;  
291         rsp->header.return_val = isatty(i->fd); 
292 }
293
294 void handle_stat(syscall_req_t* req, syscall_rsp_t* rsp)
295 {
296         struct stat native_struct;
297         rsp->payload = malloc(sizeof(newlib_stat_t));
298         rsp->header.return_val = stat(req->payload, &native_struct); 
299         if(rsp->header.return_val >= 0)
300                 rsp->payload_len = sizeof(newlib_stat_t);
301
302         translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
303 }
304