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