vmm: refactor cpuid vmexit handling (XCC)
[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, (char*)&rsp->header, 
198                            sizeof(syscall_rsp_header_t), rsp->payload_len);
199         if (written < 0)
200                 error(fd, "Problems writing the syscall response header...");   
201 }
202
203 void write_syscall_rsp_payload(int fd, syscall_rsp_t* rsp) 
204 {
205         if(rsp->payload_len == 0)
206                 return;
207
208         int written = write_syscall_server(fd, rsp->payload, rsp->payload_len, 0);
209         if (written < 0)
210                 error(fd, "Problems writing the syscall response payload...");  
211         if (written < rsp->payload_len)
212                 error(fd, "Problems writing all bytes in the response payload...");     
213 }
214
215 char* sandbox_file_name(char* name, uint32_t len) {
216         char* new_name = malloc(len + sizeof(SANDBOX_DIR) - 1);
217         if (new_name == NULL) 
218                 perror("No free memory!");
219         sprintf(new_name, "%s%s", SANDBOX_DIR, name);
220         printf("%s\n", new_name);
221         return new_name;
222 }
223
224 void handle_open(syscall_req_t* req, syscall_rsp_t* rsp)
225 {
226         char* name = sandbox_file_name(req->payload, req->payload_len);
227         open_subheader_t* o = &req->header.subheader.open;      
228         int native_flags = translate_flags(o->flags);
229         int native_mode = translate_mode(o->mode);
230         rsp->header.return_val = open(name, native_flags, native_mode);
231         free(name);
232 }
233
234 void handle_close(syscall_req_t* req, syscall_rsp_t* rsp)
235 {
236         close_subheader_t* c = &req->header.subheader.close;    
237         rsp->header.return_val = close(c->fd);
238 }
239
240 void handle_read(syscall_req_t* req, syscall_rsp_t* rsp)
241 {
242         read_subheader_t* r = &req->header.subheader.read;      
243         rsp->payload = malloc(r->len);
244         if (rsp->payload == NULL) 
245                 perror("No free memory!");
246         rsp->header.return_val = read(r->fd, rsp->payload, r->len);
247         if(rsp->header.return_val >= 0)
248                 rsp->payload_len = rsp->header.return_val;
249 }
250
251 void handle_write(syscall_req_t* req, syscall_rsp_t* rsp)
252 {
253         write_subheader_t* w = &req->header.subheader.write;    
254         rsp->header.return_val = write(w->fd, req->payload, w->len);
255 }
256
257 void handle_link(syscall_req_t* req, syscall_rsp_t* rsp)
258 {
259         link_subheader_t* l = &req->header.subheader.link;      
260         char* old_name = sandbox_file_name(req->payload, l->old_len);
261         char* new_name = sandbox_file_name(req->payload + l->old_len, l->new_len);
262         rsp->header.return_val = link(old_name, new_name); 
263         free(old_name);
264         free(new_name);
265 }
266
267 void handle_unlink(syscall_req_t* req, syscall_rsp_t* rsp)
268 {
269         char* name = sandbox_file_name(req->payload, req->payload_len);
270         rsp->header.return_val = unlink(name); 
271         free(name);
272 }
273
274 void handle_lseek(syscall_req_t* req, syscall_rsp_t* rsp)
275 {
276         lseek_subheader_t* l = &req->header.subheader.lseek;    
277         int native_whence = translate_whence(l->dir); 
278         rsp->header.return_val = lseek(l->fd, l->ptr, native_whence);
279 }
280
281 void handle_fstat(syscall_req_t* req, syscall_rsp_t* rsp)
282 {
283         struct stat native_struct;
284         fstat_subheader_t* f = &req->header.subheader.fstat;    
285         rsp->payload = malloc(sizeof(newlib_stat_t));
286         if (rsp->payload == NULL) 
287                 perror("No free memory!");
288         rsp->header.return_val = fstat(f->fd, &native_struct); 
289         if(rsp->header.return_val >= 0)
290                 rsp->payload_len = sizeof(newlib_stat_t);
291         
292         translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
293 }
294
295 void handle_isatty(syscall_req_t* req, syscall_rsp_t* rsp)
296 {
297         isatty_subheader_t* i = &req->header.subheader.isatty;  
298         rsp->header.return_val = isatty(i->fd); 
299 }
300
301 void handle_stat(syscall_req_t* req, syscall_rsp_t* rsp)
302 {
303         struct stat native_struct;
304         rsp->payload = malloc(sizeof(newlib_stat_t));
305         if (rsp->payload == NULL) 
306                 perror("No free memory!");
307         rsp->header.return_val = stat(req->payload, &native_struct); 
308         if(rsp->header.return_val >= 0)
309                 rsp->payload_len = sizeof(newlib_stat_t);
310
311         translate_stat(&native_struct, (newlib_stat_t*)(rsp->payload));
312 }
313