]> Dogcows Code - chaz/tar/blob - src/rmt.c
(allocated_size): Now size_t, and now initialized to 0.
[chaz/tar] / src / rmt.c
1 /* Remote connection server.
2 Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 /* Copyright (C) 1983 Regents of the University of California.
19 All rights reserved.
20
21 Redistribution and use in source and binary forms are permitted provided
22 that the above copyright notice and this paragraph are duplicated in all
23 such forms and that any documentation, advertising materials, and other
24 materials related to such distribution and use acknowledge that the
25 software was developed by the University of California, Berkeley. The
26 name of the University may not be used to endorse or promote products
27 derived from this software without specific prior written permission.
28 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
29 WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
30 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
31
32 #include "system.h"
33
34 #include <sys/socket.h>
35
36 #ifndef EXIT_FAILURE
37 # define EXIT_FAILURE 1
38 #endif
39 #ifndef EXIT_SUCCESS
40 # define EXIT_SUCCESS 0
41 #endif
42
43 /* Maximum size of a string from the requesting program. */
44 #define STRING_SIZE 64
45
46 /* Name of executing program. */
47 const char *program_name;
48
49 /* File descriptor of the tape device, or negative if none open. */
50 static int tape = -1;
51
52 /* Buffer containing transferred data, and its allocated size. */
53 static char *record_buffer = NULL;
54 static size_t allocated_size = 0;
55
56 /* Buffer for constructing the reply. */
57 static char reply_buffer[BUFSIZ];
58
59 /* Debugging tools. */
60
61 static FILE *debug_file = NULL;
62
63 #define DEBUG(File) \
64 if (debug_file) fprintf(debug_file, File)
65
66 #define DEBUG1(File, Arg) \
67 if (debug_file) fprintf(debug_file, File, Arg)
68
69 #define DEBUG2(File, Arg1, Arg2) \
70 if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
71
72 /*------------------------------------------------.
73 | Return an error string, given an error number. |
74 `------------------------------------------------*/
75
76 #if HAVE_STRERROR
77 # ifndef strerror
78 char *strerror ();
79 # endif
80 #else
81 static char *
82 private_strerror (int errnum)
83 {
84 extern const char *const sys_errlist[];
85 extern int sys_nerr;
86
87 if (errnum > 0 && errnum <= sys_nerr)
88 return sys_errlist[errnum];
89 return N_("Unknown system error");
90 }
91 # define strerror private_strerror
92 #endif
93
94 /*---.
95 | ? |
96 `---*/
97
98 static void
99 report_error_message (const char *string)
100 {
101 DEBUG1 ("rmtd: E 0 (%s)\n", string);
102
103 sprintf (reply_buffer, "E0\n%s\n", string);
104 write (1, reply_buffer, strlen (reply_buffer));
105 }
106
107 /*---.
108 | ? |
109 `---*/
110
111 static void
112 report_numbered_error (int num)
113 {
114 DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
115
116 sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
117 write (1, reply_buffer, strlen (reply_buffer));
118 }
119
120 /*---.
121 | ? |
122 `---*/
123
124 static void
125 get_string (char *string)
126 {
127 int counter;
128
129 for (counter = 0; counter < STRING_SIZE; counter++)
130 {
131 if (read (0, string + counter, 1) != 1)
132 exit (EXIT_SUCCESS);
133
134 if (string[counter] == '\n')
135 break;
136 }
137 string[counter] = '\0';
138 }
139
140 /*---.
141 | ? |
142 `---*/
143
144 static void
145 prepare_record_buffer (size_t size)
146 {
147 if (size <= allocated_size)
148 return;
149
150 if (record_buffer)
151 free (record_buffer);
152
153 record_buffer = malloc (size);
154
155 if (record_buffer == NULL)
156 {
157 DEBUG (_("rmtd: Cannot allocate buffer space\n"));
158
159 report_error_message (N_("Cannot allocate buffer space"));
160 exit (EXIT_FAILURE); /* exit status used to be 4 */
161 }
162
163 allocated_size = size;
164
165 #ifdef SO_RCVBUF
166 while (size > 1024 &&
167 setsockopt (0, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (size)) < 0)
168 size -= 1024;
169 #else
170 /* FIXME: I do not see any purpose to the following line... Sigh! */
171 size = 1 + ((size - 1) % 1024);
172 #endif
173 }
174
175 /*---.
176 | ? |
177 `---*/
178
179 int
180 main (int argc, char *const *argv)
181 {
182 char command;
183 long status;
184
185 /* FIXME: Localisation is meaningless, unless --help and --version are
186 locally used. Localisation would be best accomplished by the calling
187 tar, on messages found within error packets. */
188
189 program_name = argv[0];
190 setlocale (LC_ALL, "");
191 bindtextdomain (PACKAGE, LOCALEDIR);
192 textdomain (PACKAGE);
193
194 /* FIXME: Implement --help and --version as for any other GNU program. */
195
196 argc--, argv++;
197 if (argc > 0)
198 {
199 debug_file = fopen (*argv, "w");
200 if (debug_file == 0)
201 {
202 report_numbered_error (errno);
203 exit (EXIT_FAILURE);
204 }
205 setbuf (debug_file, NULL);
206 }
207
208 top:
209 errno = 0; /* FIXME: errno should be read-only */
210 status = 0;
211 if (read (0, &command, 1) != 1)
212 exit (EXIT_SUCCESS);
213
214 switch (command)
215 {
216 /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
217
218 case 'O':
219 {
220 char device_string[STRING_SIZE];
221 char mode_string[STRING_SIZE];
222
223 get_string (device_string);
224 get_string (mode_string);
225 DEBUG2 ("rmtd: O %s %s\n", device_string, mode_string);
226
227 if (tape >= 0)
228 close (tape);
229
230 #if defined (i386) && defined (AIX)
231
232 /* This is alleged to fix a byte ordering problem. I'm quite
233 suspicious if it's right. -- mib. */
234
235 {
236 mode_t old_mode = atol (mode_string);
237 mode_t new_mode = 0;
238
239 if ((old_mode & 3) == 0)
240 new_mode |= O_RDONLY;
241 if (old_mode & 1)
242 new_mode |= O_WRONLY;
243 if (old_mode & 2)
244 new_mode |= O_RDWR;
245 if (old_mode & 0x0008)
246 new_mode |= O_APPEND;
247 if (old_mode & 0x0200)
248 new_mode |= O_CREAT;
249 if (old_mode & 0x0400)
250 new_mode |= O_TRUNC;
251 if (old_mode & 0x0800)
252 new_mode |= O_EXCL;
253 tape = open (device_string, new_mode, 0666);
254 }
255 #else
256 tape = open (device_string, atoi (mode_string), 0666);
257 #endif
258 if (tape < 0)
259 goto ioerror;
260 goto respond;
261 }
262
263 case 'C':
264 {
265 char device_string[STRING_SIZE];
266
267 get_string (device_string); /* discard */
268 DEBUG ("rmtd: C\n");
269
270 if (close (tape) < 0)
271 goto ioerror;
272 tape = -1;
273 goto respond;
274 }
275
276 case 'L':
277 {
278 char count_string[STRING_SIZE];
279 char position_string[STRING_SIZE];
280 off_t count = 0;
281 int negative;
282 char *p;
283
284 get_string (count_string);
285 get_string (position_string);
286 DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
287
288 /* Parse count_string, taking care to check for overflow.
289 We can't use standard functions,
290 since off_t might be longer than long. */
291
292 for (p = count_string; *p == ' ' || *p == '\t'; p++)
293 continue;
294
295 negative = *p == '-';
296 p += negative || *p == '+';
297
298 for (;;)
299 {
300 int digit = *p++ - '0';
301 if (9 < (unsigned) digit)
302 break;
303 else
304 {
305 off_t c10 = 10 * count;
306 off_t nc = negative ? c10 - digit : c10 + digit;
307 if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
308 {
309 report_error_message (N_("Seek offset out of range"));
310 exit (EXIT_FAILURE);
311 }
312 count = nc;
313 }
314 }
315
316 count = lseek (tape, count, atoi (position_string));
317 if (count < 0)
318 goto ioerror;
319
320 /* Convert count back to string for reply.
321 We can't use sprintf, since off_t might be longer than long. */
322 p = count_string + sizeof count_string;
323 *--p = '\0';
324 do
325 *--p = '0' + (int) (count % 10);
326 while ((count /= 10) != 0);
327
328 DEBUG1 ("rmtd: A %s\n", p);
329
330 sprintf (reply_buffer, "A%s\n", p);
331 write (1, reply_buffer, strlen (reply_buffer));
332 goto top;
333 }
334
335 case 'W':
336 {
337 char count_string[STRING_SIZE];
338 size_t size;
339 size_t counter;
340
341 get_string (count_string);
342 size = atol (count_string);
343 DEBUG1 ("rmtd: W %s\n", count_string);
344
345 prepare_record_buffer (size);
346 for (counter = 0; counter < size; counter += status)
347 {
348 status = read (0, &record_buffer[counter], size - counter);
349 if (status <= 0)
350 {
351 DEBUG (_("rmtd: Premature eof\n"));
352
353 report_error_message (N_("Premature end of file"));
354 exit (EXIT_FAILURE); /* exit status used to be 2 */
355 }
356 }
357 status = write (tape, record_buffer, size);
358 if (status < 0)
359 goto ioerror;
360 goto respond;
361 }
362
363 case 'R':
364 {
365 char count_string[STRING_SIZE];
366 size_t size;
367
368 get_string (count_string);
369 DEBUG1 ("rmtd: R %s\n", count_string);
370
371 size = atol (count_string);
372 prepare_record_buffer (size);
373 status = read (tape, record_buffer, size);
374 if (status < 0)
375 goto ioerror;
376 sprintf (reply_buffer, "A%ld\n", status);
377 write (1, reply_buffer, strlen (reply_buffer));
378 write (1, record_buffer, (size_t) status);
379 goto top;
380 }
381
382 case 'I':
383 {
384 char operation_string[STRING_SIZE];
385 char count_string[STRING_SIZE];
386
387 get_string (operation_string);
388 get_string (count_string);
389 DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
390
391 #ifdef MTIOCTOP
392 {
393 struct mtop mtop;
394 const char *p;
395 daddr_t count = 0;
396 int negative;
397
398 /* Parse count_string, taking care to check for overflow.
399 We can't use standard functions,
400 since daddr_t might be longer than long. */
401
402 for (p = count_string; *p == ' ' || *p == '\t'; p++)
403 continue;
404
405 negative = *p == '-';
406 p += negative || *p == '+';
407
408 for (;;)
409 {
410 int digit = *p++ - '0';
411 if (9 < (unsigned) digit)
412 break;
413 else
414 {
415 daddr_t c10 = 10 * count;
416 daddr_t nc = negative ? c10 - digit : c10 + digit;
417 if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
418 {
419 report_error_message (N_("Seek offset out of range"));
420 exit (EXIT_FAILURE);
421 }
422 count = nc;
423 }
424 }
425
426 mtop.mt_count = count;
427 mtop.mt_op = atoi (operation_string);
428
429 if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
430 goto ioerror;
431 }
432 #endif
433 goto respond;
434 }
435
436 case 'S': /* status */
437 {
438 DEBUG ("rmtd: S\n");
439
440 #ifdef MTIOCGET
441 {
442 struct mtget operation;
443
444 if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
445 goto ioerror;
446 status = sizeof (operation);
447 sprintf (reply_buffer, "A%ld\n", status);
448 write (1, reply_buffer, strlen (reply_buffer));
449 write (1, (char *) &operation, sizeof (operation));
450 }
451 #endif
452 goto top;
453 }
454
455 default:
456 DEBUG1 (_("rmtd: Garbage command %c\n"), command);
457
458 report_error_message (N_("Garbage command"));
459 exit (EXIT_FAILURE); /* exit status used to be 3 */
460 }
461
462 respond:
463 DEBUG1 ("rmtd: A %ld\n", status);
464
465 sprintf (reply_buffer, "A%ld\n", status);
466 write (1, reply_buffer, strlen (reply_buffer));
467 goto top;
468
469 ioerror:
470 report_numbered_error (errno);
471 goto top;
472 }
This page took 0.062345 seconds and 5 git commands to generate.