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