rmt.c 11 KB

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