* hostio.c: Don't include errno.h.
[external/binutils.git] / gdb / gdbserver / hostio.c
1 /* Host file transfer support for gdbserver.
2    Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3
4    Contributed by CodeSourcery.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    Boston, MA 02110-1301, USA.  */
22
23 #include "server.h"
24 #include "gdb/fileio.h"
25
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <unistd.h>
29
30 extern int remote_debug;
31
32 struct fd_list
33 {
34   int fd;
35   struct fd_list *next;
36 };
37
38 static struct fd_list *open_fds;
39
40 static int
41 safe_fromhex (char a, int *nibble)
42 {
43   if (a >= '0' && a <= '9')
44     *nibble = a - '0';
45   else if (a >= 'a' && a <= 'f')
46     *nibble = a - 'a' + 10;
47   else if (a >= 'A' && a <= 'F')
48     *nibble = a - 'A' + 10;
49   else
50     return -1;
51
52   return 0;
53 }
54
55 static int
56 require_filename (char **pp, char *filename)
57 {
58   int count;
59   char *p;
60
61   p = *pp;
62   count = 0;
63
64   while (*p && *p != ',')
65     {
66       int nib1, nib2;
67
68       /* Don't allow overflow.  */
69       if (count >= PATH_MAX - 1)
70         return -1;
71
72       if (safe_fromhex (p[0], &nib1)
73           || safe_fromhex (p[1], &nib2))
74         return -1;
75
76       filename[count++] = nib1 * 16 + nib2;
77       p += 2;
78     }
79
80   filename[count] = '\0';
81   *pp = p;
82   return 0;
83 }
84
85 static int
86 require_int (char **pp, int *value)
87 {
88   char *p;
89   int count;
90
91   p = *pp;
92   *value = 0;
93   count = 0;
94
95   while (*p && *p != ',')
96     {
97       int nib;
98
99       /* Don't allow overflow.  */
100       if (count >= 7)
101         return -1;
102
103       if (safe_fromhex (p[0], &nib))
104         return -1;
105       *value = *value * 16 + nib;
106       p++;
107       count++;
108     }
109
110   *pp = p;
111   return 0;
112 }
113
114 static int
115 require_data (char *p, int p_len, char **data, int *data_len)
116 {
117   int input_index, output_index, escaped;
118
119   *data = malloc (p_len);
120
121   output_index = 0;
122   escaped = 0;
123   for (input_index = 0; input_index < p_len; input_index++)
124     {
125       char b = p[input_index];
126
127       if (escaped)
128         {
129           (*data)[output_index++] = b ^ 0x20;
130           escaped = 0;
131         }
132       else if (b == '}')
133         escaped = 1;
134       else
135         (*data)[output_index++] = b;
136     }
137
138   if (escaped)
139     return -1;
140
141   *data_len = output_index;
142   return 0;
143 }
144
145 static int
146 require_comma (char **pp)
147 {
148   if (**pp == ',')
149     {
150       (*pp)++;
151       return 0;
152     }
153   else
154     return -1;
155 }
156
157 static int
158 require_end (char *p)
159 {
160   if (*p == '\0')
161     return 0;
162   else
163     return -1;
164 }
165
166 static int
167 require_valid_fd (int fd)
168 {
169   struct fd_list *fd_ptr;
170
171   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
172     if (fd_ptr->fd == fd)
173       return 0;
174
175   return -1;
176 }
177
178 /* Fill in own_buf with the last hostio error packet, however it
179    suitable for the target.  */
180 static void
181 hostio_error (char *own_buf)
182 {
183   the_target->hostio_last_error (own_buf);
184 }
185
186 static void
187 hostio_packet_error (char *own_buf)
188 {
189   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
190 }
191
192 static void
193 hostio_reply (char *own_buf, int result)
194 {
195   sprintf (own_buf, "F%x", result);
196 }
197
198 static int
199 hostio_reply_with_data (char *own_buf, char *buffer, int len,
200                         int *new_packet_len)
201 {
202   int input_index, output_index, out_maxlen;
203
204   sprintf (own_buf, "F%x;", len);
205   output_index = strlen (own_buf);
206
207   out_maxlen = PBUFSIZ;
208
209   for (input_index = 0; input_index < len; input_index++)
210     {
211       char b = buffer[input_index];
212
213       if (b == '$' || b == '#' || b == '}' || b == '*')
214         {
215           /* These must be escaped.  */
216           if (output_index + 2 > out_maxlen)
217             break;
218           own_buf[output_index++] = '}';
219           own_buf[output_index++] = b ^ 0x20;
220         }
221       else
222         {
223           if (output_index + 1 > out_maxlen)
224             break;
225           own_buf[output_index++] = b;
226         }
227     }
228
229   *new_packet_len = output_index;
230   return input_index;
231 }
232
233 static int
234 fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
235 {
236   int open_flags = 0;
237
238   if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
239     return -1;
240
241   if (fileio_open_flags & FILEIO_O_CREAT)
242     open_flags |= O_CREAT;
243   if (fileio_open_flags & FILEIO_O_EXCL)
244     open_flags |= O_EXCL;
245   if (fileio_open_flags & FILEIO_O_TRUNC)
246     open_flags |= O_TRUNC;
247   if (fileio_open_flags & FILEIO_O_APPEND)
248     open_flags |= O_APPEND;
249   if (fileio_open_flags & FILEIO_O_RDONLY)
250     open_flags |= O_RDONLY;
251   if (fileio_open_flags & FILEIO_O_WRONLY)
252     open_flags |= O_WRONLY;
253   if (fileio_open_flags & FILEIO_O_RDWR)
254     open_flags |= O_RDWR;
255 /* On systems supporting binary and text mode, always open files in
256    binary mode. */
257 #ifdef O_BINARY
258   open_flags |= O_BINARY;
259 #endif
260
261   *open_flags_p = open_flags;
262   return 0;
263 }
264
265 static void
266 handle_open (char *own_buf)
267 {
268   char filename[PATH_MAX];
269   char *p;
270   int fileio_flags, mode, flags, fd;
271   struct fd_list *new_fd;
272
273   p = own_buf + strlen ("vFile:open:");
274
275   if (require_filename (&p, filename)
276       || require_comma (&p)
277       || require_int (&p, &fileio_flags)
278       || require_comma (&p)
279       || require_int (&p, &mode)
280       || require_end (p)
281       || fileio_open_flags_to_host (fileio_flags, &flags))
282     {
283       hostio_packet_error (own_buf);
284       return;
285     }
286
287   /* We do not need to convert MODE, since the fileio protocol
288      uses the standard values.  */
289   fd = open (filename, flags, mode);
290
291   if (fd == -1)
292     {
293       hostio_error (own_buf);
294       return;
295     }
296
297   /* Record the new file descriptor.  */
298   new_fd = malloc (sizeof (struct fd_list));
299   new_fd->fd = fd;
300   new_fd->next = open_fds;
301   open_fds = new_fd;
302
303   hostio_reply (own_buf, fd);
304 }
305
306 static void
307 handle_pread (char *own_buf, int *new_packet_len)
308 {
309   int fd, ret, len, offset, bytes_sent;
310   char *p, *data;
311
312   p = own_buf + strlen ("vFile:pread:");
313
314   if (require_int (&p, &fd)
315       || require_comma (&p)
316       || require_valid_fd (fd)
317       || require_int (&p, &len)
318       || require_comma (&p)
319       || require_int (&p, &offset)
320       || require_end (p))
321     {
322       hostio_packet_error (own_buf);
323       return;
324     }
325
326   data = malloc (len);
327 #ifdef HAVE_PREAD
328   ret = pread (fd, data, len, offset);
329 #else
330   ret = lseek (fd, offset, SEEK_SET);
331   if (ret != -1)
332     ret = read (fd, data, len);
333 #endif
334
335   if (ret == -1)
336     {
337       hostio_error (own_buf);
338       free (data);
339       return;
340     }
341
342   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
343
344   /* If we were using read, and the data did not all fit in the reply,
345      we would have to back up using lseek here.  With pread it does
346      not matter.  But we still have a problem; the return value in the
347      packet might be wrong, so we must fix it.  This time it will
348      definitely fit.  */
349   if (bytes_sent < ret)
350     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
351                                          new_packet_len);
352
353   free (data);
354 }
355
356 static void
357 handle_pwrite (char *own_buf, int packet_len)
358 {
359   int fd, ret, len, offset;
360   char *p, *data;
361
362   p = own_buf + strlen ("vFile:pwrite:");
363
364   if (require_int (&p, &fd)
365       || require_comma (&p)
366       || require_valid_fd (fd)
367       || require_int (&p, &offset)
368       || require_comma (&p)
369       || require_data (p, packet_len - (p - own_buf), &data, &len))
370     {
371       hostio_packet_error (own_buf);
372       return;
373     }
374
375 #ifdef HAVE_PWRITE
376   ret = pwrite (fd, data, len, offset);
377 #else
378   ret = lseek (fd, offset, SEEK_SET);
379   if (ret != -1)
380     ret = write (fd, data, len);
381 #endif
382
383   if (ret == -1)
384     {
385       hostio_error (own_buf);
386       free (data);
387       return;
388     }
389
390   hostio_reply (own_buf, ret);
391   free (data);
392 }
393
394 static void
395 handle_close (char *own_buf)
396 {
397   int fd, ret;
398   char *p;
399   struct fd_list **open_fd_p, *old_fd;
400
401   p = own_buf + strlen ("vFile:close:");
402
403   if (require_int (&p, &fd)
404       || require_valid_fd (fd)
405       || require_end (p))
406     {
407       hostio_packet_error (own_buf);
408       return;
409     }
410
411   ret = close (fd);
412
413   if (ret == -1)
414     {
415       hostio_error (own_buf);
416       return;
417     }
418
419   open_fd_p = &open_fds;
420   while (*open_fd_p && (*open_fd_p)->fd != fd)
421     open_fd_p = &(*open_fd_p)->next;
422
423   old_fd = *open_fd_p;
424   *open_fd_p = (*open_fd_p)->next;
425   free (old_fd);
426
427   hostio_reply (own_buf, ret);
428 }
429
430 static void
431 handle_unlink (char *own_buf)
432 {
433   char filename[PATH_MAX];
434   char *p;
435   int ret;
436
437   p = own_buf + strlen ("vFile:unlink:");
438
439   if (require_filename (&p, filename)
440       || require_end (p))
441     {
442       hostio_packet_error (own_buf);
443       return;
444     }
445
446   ret = unlink (filename);
447
448   if (ret == -1)
449     {
450       hostio_error (own_buf);
451       return;
452     }
453
454   hostio_reply (own_buf, ret);
455 }
456
457 /* Handle all the 'F' file transfer packets.  */
458
459 int
460 handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
461 {
462   if (strncmp (own_buf, "vFile:open:", 11) == 0)
463     handle_open (own_buf);
464   else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
465     handle_pread (own_buf, new_packet_len);
466   else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
467     handle_pwrite (own_buf, packet_len);
468   else if (strncmp (own_buf, "vFile:close:", 12) == 0)
469     handle_close (own_buf);
470   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
471     handle_unlink (own_buf);
472   else
473     return 0;
474
475   return 1;
476 }