rmtlib.c revision 1.18 1 1.18 lukem /* $NetBSD: rmtlib.c,v 1.18 2001/11/05 15:10:25 lukem Exp $ */
2 1.1 jtc
3 1.1 jtc /*
4 1.1 jtc * rmt --- remote tape emulator subroutines
5 1.1 jtc *
6 1.1 jtc * Originally written by Jeff Lee, modified some by Arnold Robbins
7 1.1 jtc *
8 1.1 jtc * WARNING: The man page rmt(8) for /etc/rmt documents the remote mag
9 1.1 jtc * tape protocol which rdump and rrestore use. Unfortunately, the man
10 1.1 jtc * page is *WRONG*. The author of the routines I'm including originally
11 1.1 jtc * wrote his code just based on the man page, and it didn't work, so he
12 1.1 jtc * went to the rdump source to figure out why. The only thing he had to
13 1.1 jtc * change was to check for the 'F' return code in addition to the 'E',
14 1.1 jtc * and to separate the various arguments with \n instead of a space. I
15 1.1 jtc * personally don't think that this is much of a problem, but I wanted to
16 1.1 jtc * point it out.
17 1.1 jtc * -- Arnold Robbins
18 1.1 jtc *
19 1.1 jtc * Redone as a library that can replace open, read, write, etc, by
20 1.1 jtc * Fred Fish, with some additional work by Arnold Robbins.
21 1.1 jtc */
22 1.11 simonb
23 1.1 jtc /*
24 1.1 jtc * MAXUNIT --- Maximum number of remote tape file units
25 1.1 jtc *
26 1.1 jtc * READ --- Return the number of the read side file descriptor
27 1.1 jtc * WRITE --- Return the number of the write side file descriptor
28 1.1 jtc */
29 1.1 jtc
30 1.1 jtc #define RMTIOCTL 1
31 1.6 mikel /* #define USE_REXEC 1 */ /* rexec code courtesy of Dan Kegel, srs!dan */
32 1.1 jtc
33 1.1 jtc #include <sys/types.h>
34 1.12 lukem #include <sys/stat.h>
35 1.1 jtc
36 1.1 jtc #ifdef RMTIOCTL
37 1.1 jtc #include <sys/ioctl.h>
38 1.1 jtc #include <sys/mtio.h>
39 1.1 jtc #endif
40 1.1 jtc
41 1.12 lukem #include <assert.h>
42 1.12 lukem #include <errno.h>
43 1.12 lukem #include <fcntl.h>
44 1.12 lukem #include <signal.h>
45 1.14 lukem #include <stdarg.h>
46 1.12 lukem #include <stdio.h>
47 1.12 lukem #include <stdlib.h>
48 1.12 lukem #include <string.h>
49 1.12 lukem #include <unistd.h>
50 1.12 lukem
51 1.1 jtc #ifdef USE_REXEC
52 1.1 jtc #include <netdb.h>
53 1.1 jtc #endif
54 1.1 jtc
55 1.9 thorpej #define __RMTLIB_PRIVATE
56 1.9 thorpej #include <rmt.h> /* get prototypes for remapped functions */
57 1.9 thorpej
58 1.10 mrg #include "pathnames.h"
59 1.10 mrg
60 1.14 lukem static int _rmt_close(int);
61 1.14 lukem static int _rmt_ioctl(int, unsigned long, void *);
62 1.14 lukem static off_t _rmt_lseek(int, off_t, int);
63 1.14 lukem static int _rmt_open(const char *, int, int);
64 1.14 lukem static ssize_t _rmt_read(int, void *, size_t);
65 1.14 lukem static ssize_t _rmt_write(int, const void *, size_t);
66 1.14 lukem static int command(int, char *);
67 1.14 lukem static int remdev(const char *);
68 1.14 lukem static void rmtabort(int);
69 1.14 lukem static int status(int);
70 1.7 lukem
71 1.14 lukem int isrmt(int);
72 1.7 lukem
73 1.7 lukem
74 1.1 jtc #define BUFMAGIC 64 /* a magic number for buffer sizes */
75 1.15 enami #define MAXUNIT 4
76 1.1 jtc
77 1.1 jtc #define READ(fd) (Ctp[fd][0])
78 1.1 jtc #define WRITE(fd) (Ptc[fd][1])
79 1.1 jtc
80 1.6 mikel static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
81 1.6 mikel static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
82 1.1 jtc
83 1.1 jtc
84 1.1 jtc /*
85 1.2 jtc * rmtabort --- close off a remote tape connection
86 1.1 jtc */
87 1.7 lukem static void
88 1.14 lukem rmtabort(int fildes)
89 1.1 jtc {
90 1.14 lukem
91 1.1 jtc close(READ(fildes));
92 1.1 jtc close(WRITE(fildes));
93 1.1 jtc READ(fildes) = -1;
94 1.1 jtc WRITE(fildes) = -1;
95 1.1 jtc }
96 1.1 jtc
97 1.1 jtc
98 1.1 jtc /*
99 1.1 jtc * command --- attempt to perform a remote tape command
100 1.1 jtc */
101 1.7 lukem static int
102 1.14 lukem command(int fildes, char *buf)
103 1.1 jtc {
104 1.14 lukem size_t blen;
105 1.14 lukem void (*pstat)(int);
106 1.1 jtc
107 1.12 lukem _DIAGASSERT(buf != NULL);
108 1.12 lukem
109 1.1 jtc /*
110 1.1 jtc * save current pipe status and try to make the request
111 1.1 jtc */
112 1.1 jtc
113 1.1 jtc blen = strlen(buf);
114 1.1 jtc pstat = signal(SIGPIPE, SIG_IGN);
115 1.14 lukem if (write(WRITE(fildes), buf, blen) == blen) {
116 1.1 jtc signal(SIGPIPE, pstat);
117 1.15 enami return (0);
118 1.1 jtc }
119 1.1 jtc
120 1.1 jtc /*
121 1.1 jtc * something went wrong. close down and go home
122 1.1 jtc */
123 1.1 jtc
124 1.1 jtc signal(SIGPIPE, pstat);
125 1.2 jtc rmtabort(fildes);
126 1.1 jtc
127 1.1 jtc errno = EIO;
128 1.15 enami return (-1);
129 1.1 jtc }
130 1.1 jtc
131 1.1 jtc
132 1.1 jtc /*
133 1.1 jtc * status --- retrieve the status from the pipe
134 1.1 jtc */
135 1.7 lukem static int
136 1.14 lukem status(int fildes)
137 1.1 jtc {
138 1.1 jtc int i;
139 1.1 jtc char c, *cp;
140 1.1 jtc char buffer[BUFMAGIC];
141 1.1 jtc
142 1.1 jtc /*
143 1.1 jtc * read the reply command line
144 1.1 jtc */
145 1.1 jtc
146 1.14 lukem for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) {
147 1.14 lukem if (read(READ(fildes), cp, 1) != 1) {
148 1.2 jtc rmtabort(fildes);
149 1.1 jtc errno = EIO;
150 1.15 enami return (-1);
151 1.1 jtc }
152 1.14 lukem if (*cp == '\n') {
153 1.1 jtc *cp = 0;
154 1.1 jtc break;
155 1.1 jtc }
156 1.1 jtc }
157 1.1 jtc
158 1.14 lukem if (i == BUFMAGIC) {
159 1.2 jtc rmtabort(fildes);
160 1.1 jtc errno = EIO;
161 1.15 enami return (-1);
162 1.1 jtc }
163 1.1 jtc
164 1.1 jtc /*
165 1.1 jtc * check the return status
166 1.1 jtc */
167 1.1 jtc
168 1.1 jtc for (cp = buffer; *cp; cp++)
169 1.1 jtc if (*cp != ' ')
170 1.1 jtc break;
171 1.1 jtc
172 1.14 lukem if (*cp == 'E' || *cp == 'F') {
173 1.1 jtc errno = atoi(cp + 1);
174 1.1 jtc while (read(READ(fildes), &c, 1) == 1)
175 1.1 jtc if (c == '\n')
176 1.1 jtc break;
177 1.1 jtc
178 1.1 jtc if (*cp == 'F')
179 1.2 jtc rmtabort(fildes);
180 1.1 jtc
181 1.15 enami return (-1);
182 1.1 jtc }
183 1.1 jtc
184 1.1 jtc /*
185 1.1 jtc * check for mis-synced pipes
186 1.1 jtc */
187 1.1 jtc
188 1.14 lukem if (*cp != 'A') {
189 1.2 jtc rmtabort(fildes);
190 1.1 jtc errno = EIO;
191 1.15 enami return (-1);
192 1.1 jtc }
193 1.1 jtc
194 1.15 enami return (atoi(cp + 1));
195 1.1 jtc }
196 1.1 jtc
197 1.14 lukem
198 1.1 jtc #ifdef USE_REXEC
199 1.1 jtc /*
200 1.1 jtc * _rmt_rexec
201 1.1 jtc *
202 1.1 jtc * execute /etc/rmt on a remote system using rexec().
203 1.1 jtc * Return file descriptor of bidirectional socket for stdin and stdout
204 1.1 jtc * If username is NULL, or an empty string, uses current username.
205 1.1 jtc *
206 1.1 jtc * ADR: By default, this code is not used, since it requires that
207 1.1 jtc * the user have a .netrc file in his/her home directory, or that the
208 1.1 jtc * application designer be willing to have rexec prompt for login and
209 1.1 jtc * password info. This may be unacceptable, and .rhosts files for use
210 1.1 jtc * with rsh are much more common on BSD systems.
211 1.1 jtc */
212 1.1 jtc
213 1.14 lukem static int _rmt_rexec(const char *, const char *);
214 1.7 lukem
215 1.1 jtc static int
216 1.14 lukem _rmt_rexec(const char *host, const char *user)
217 1.1 jtc {
218 1.1 jtc struct servent *rexecserv;
219 1.1 jtc
220 1.12 lukem _DIAGASSERT(host != NULL);
221 1.12 lukem /* user may be NULL */
222 1.12 lukem
223 1.1 jtc rexecserv = getservbyname("exec", "tcp");
224 1.15 enami if (rexecserv == NULL) {
225 1.14 lukem fprintf(stderr, "? exec/tcp: service not available.");
226 1.17 wiz exit(1);
227 1.1 jtc }
228 1.1 jtc if ((user != NULL) && *user == '\0')
229 1.15 enami user = NULL;
230 1.14 lukem return (rexec(&host, rexecserv->s_port, user, NULL,
231 1.15 enami "/etc/rmt", NULL));
232 1.1 jtc }
233 1.1 jtc #endif /* USE_REXEC */
234 1.1 jtc
235 1.14 lukem
236 1.1 jtc /*
237 1.1 jtc * _rmt_open --- open a magtape device on system specified, as given user
238 1.1 jtc *
239 1.1 jtc * file name has the form [user@]system:/dev/????
240 1.1 jtc #ifdef COMPAT
241 1.1 jtc * file name has the form system[.user]:/dev/????
242 1.1 jtc #endif
243 1.1 jtc */
244 1.1 jtc
245 1.1 jtc #define MAXHOSTLEN 257 /* BSD allows very long host names... */
246 1.1 jtc
247 1.7 lukem static int
248 1.14 lukem _rmt_open(const char *path, int oflag, int mode)
249 1.1 jtc {
250 1.1 jtc int i, rc;
251 1.1 jtc char buffer[BUFMAGIC];
252 1.18 lukem char host[MAXHOSTLEN];
253 1.1 jtc char device[BUFMAGIC];
254 1.1 jtc char login[BUFMAGIC];
255 1.1 jtc char *sys, *dev, *user;
256 1.1 jtc
257 1.12 lukem _DIAGASSERT(path != NULL);
258 1.12 lukem
259 1.18 lukem sys = host;
260 1.1 jtc dev = device;
261 1.1 jtc user = login;
262 1.1 jtc
263 1.1 jtc /*
264 1.1 jtc * first, find an open pair of file descriptors
265 1.1 jtc */
266 1.1 jtc
267 1.1 jtc for (i = 0; i < MAXUNIT; i++)
268 1.1 jtc if (READ(i) == -1 && WRITE(i) == -1)
269 1.1 jtc break;
270 1.1 jtc
271 1.14 lukem if (i == MAXUNIT) {
272 1.1 jtc errno = EMFILE;
273 1.15 enami return (-1);
274 1.1 jtc }
275 1.1 jtc
276 1.1 jtc /*
277 1.1 jtc * pull apart system and device, and optional user
278 1.1 jtc * don't munge original string
279 1.1 jtc * if COMPAT is defined, also handle old (4.2) style person.site notation.
280 1.1 jtc */
281 1.1 jtc
282 1.1 jtc while (*path != '@'
283 1.1 jtc #ifdef COMPAT
284 1.1 jtc && *path != '.'
285 1.1 jtc #endif
286 1.1 jtc && *path != ':') {
287 1.1 jtc *sys++ = *path++;
288 1.1 jtc }
289 1.1 jtc *sys = '\0';
290 1.1 jtc path++;
291 1.1 jtc
292 1.14 lukem if (*(path - 1) == '@') {
293 1.18 lukem (void)strncpy(user, host, sizeof(login) - 1);
294 1.5 mrg /* saw user part of user@host */
295 1.18 lukem sys = host; /* start over */
296 1.1 jtc while (*path != ':') {
297 1.1 jtc *sys++ = *path++;
298 1.1 jtc }
299 1.1 jtc *sys = '\0';
300 1.1 jtc path++;
301 1.1 jtc }
302 1.1 jtc #ifdef COMPAT
303 1.14 lukem else if (*(path - 1) == '.') {
304 1.1 jtc while (*path != ':') {
305 1.1 jtc *user++ = *path++;
306 1.1 jtc }
307 1.1 jtc *user = '\0';
308 1.1 jtc path++;
309 1.1 jtc }
310 1.1 jtc #endif
311 1.1 jtc else
312 1.1 jtc *user = '\0';
313 1.1 jtc
314 1.1 jtc while (*path) {
315 1.1 jtc *dev++ = *path++;
316 1.1 jtc }
317 1.1 jtc *dev = '\0';
318 1.1 jtc
319 1.1 jtc #ifdef USE_REXEC
320 1.11 simonb /*
321 1.11 simonb * Execute the remote command using rexec
322 1.1 jtc */
323 1.18 lukem READ(i) = WRITE(i) = _rmt_rexec(host, login);
324 1.1 jtc if (READ(i) < 0)
325 1.15 enami return (-1);
326 1.1 jtc #else
327 1.1 jtc /*
328 1.1 jtc * setup the pipes for the 'rsh' command and fork
329 1.1 jtc */
330 1.1 jtc
331 1.1 jtc if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
332 1.15 enami return (-1);
333 1.1 jtc
334 1.1 jtc if ((rc = fork()) == -1)
335 1.15 enami return (-1);
336 1.1 jtc
337 1.14 lukem if (rc == 0) {
338 1.10 mrg char *rshpath, *rsh;
339 1.10 mrg
340 1.1 jtc close(0);
341 1.1 jtc dup(Ptc[i][0]);
342 1.1 jtc close(Ptc[i][0]); close(Ptc[i][1]);
343 1.1 jtc close(1);
344 1.1 jtc dup(Ctp[i][1]);
345 1.1 jtc close(Ctp[i][0]); close(Ctp[i][1]);
346 1.14 lukem (void) setuid(getuid());
347 1.14 lukem (void) setgid(getgid());
348 1.11 simonb
349 1.10 mrg if ((rshpath = getenv("RCMD_CMD")) == NULL)
350 1.10 mrg rshpath = _PATH_RSH;
351 1.10 mrg if ((rsh = strrchr(rshpath, '/')) == NULL)
352 1.10 mrg rsh = rshpath;
353 1.10 mrg else
354 1.10 mrg rsh++;
355 1.11 simonb
356 1.14 lukem if (*login) {
357 1.18 lukem execl(rshpath, rsh, host, "-l", login,
358 1.15 enami _PATH_RMT, NULL);
359 1.14 lukem } else {
360 1.18 lukem execl(rshpath, rsh, host,
361 1.15 enami _PATH_RMT, NULL);
362 1.1 jtc }
363 1.1 jtc
364 1.1 jtc /*
365 1.1 jtc * bad problems if we get here
366 1.1 jtc */
367 1.1 jtc
368 1.1 jtc perror("exec");
369 1.1 jtc exit(1);
370 1.1 jtc }
371 1.1 jtc
372 1.1 jtc close(Ptc[i][0]); close(Ctp[i][1]);
373 1.1 jtc #endif
374 1.1 jtc
375 1.1 jtc /*
376 1.1 jtc * now attempt to open the tape device
377 1.1 jtc */
378 1.1 jtc
379 1.5 mrg (void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
380 1.1 jtc if (command(i, buffer) == -1 || status(i) == -1)
381 1.15 enami return (-1);
382 1.1 jtc
383 1.15 enami return (i);
384 1.1 jtc }
385 1.1 jtc
386 1.1 jtc
387 1.1 jtc /*
388 1.1 jtc * _rmt_close --- close a remote magtape unit and shut down
389 1.1 jtc */
390 1.7 lukem static int
391 1.14 lukem _rmt_close(int fildes)
392 1.1 jtc {
393 1.1 jtc int rc;
394 1.1 jtc
395 1.14 lukem if (command(fildes, "C\n") != -1) {
396 1.1 jtc rc = status(fildes);
397 1.1 jtc
398 1.2 jtc rmtabort(fildes);
399 1.15 enami return (rc);
400 1.1 jtc }
401 1.1 jtc
402 1.15 enami return (-1);
403 1.1 jtc }
404 1.1 jtc
405 1.1 jtc
406 1.1 jtc /*
407 1.1 jtc * _rmt_read --- read a buffer from a remote tape
408 1.1 jtc */
409 1.14 lukem static ssize_t
410 1.14 lukem _rmt_read(int fildes, void *buf, size_t nbyte)
411 1.1 jtc {
412 1.14 lukem size_t rc, i;
413 1.14 lukem char *p;
414 1.1 jtc char buffer[BUFMAGIC];
415 1.1 jtc
416 1.12 lukem _DIAGASSERT(buf != NULL);
417 1.12 lukem
418 1.16 enami (void)snprintf(buffer, sizeof buffer, "R%lu\n", (u_long)nbyte);
419 1.1 jtc if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
420 1.15 enami return (-1);
421 1.1 jtc
422 1.14 lukem p = buf;
423 1.14 lukem for (i = 0; i < rc; i += nbyte, p += nbyte) {
424 1.14 lukem nbyte = read(READ(fildes), p, rc);
425 1.14 lukem if (nbyte <= 0) {
426 1.2 jtc rmtabort(fildes);
427 1.1 jtc errno = EIO;
428 1.15 enami return (-1);
429 1.1 jtc }
430 1.1 jtc }
431 1.1 jtc
432 1.15 enami return (rc);
433 1.1 jtc }
434 1.1 jtc
435 1.1 jtc
436 1.1 jtc /*
437 1.1 jtc * _rmt_write --- write a buffer to the remote tape
438 1.1 jtc */
439 1.14 lukem static ssize_t
440 1.14 lukem _rmt_write(int fildes, const void *buf, size_t nbyte)
441 1.1 jtc {
442 1.1 jtc char buffer[BUFMAGIC];
443 1.14 lukem void (*pstat)(int);
444 1.1 jtc
445 1.12 lukem _DIAGASSERT(buf != NULL);
446 1.12 lukem
447 1.16 enami (void)snprintf(buffer, sizeof buffer, "W%lu\n", (u_long)nbyte);
448 1.1 jtc if (command(fildes, buffer) == -1)
449 1.15 enami return (-1);
450 1.1 jtc
451 1.1 jtc pstat = signal(SIGPIPE, SIG_IGN);
452 1.14 lukem if (write(WRITE(fildes), buf, nbyte) == nbyte) {
453 1.14 lukem signal(SIGPIPE, pstat);
454 1.15 enami return (status(fildes));
455 1.1 jtc }
456 1.1 jtc
457 1.14 lukem signal(SIGPIPE, pstat);
458 1.2 jtc rmtabort(fildes);
459 1.1 jtc errno = EIO;
460 1.15 enami return (-1);
461 1.1 jtc }
462 1.1 jtc
463 1.1 jtc
464 1.1 jtc /*
465 1.1 jtc * _rmt_lseek --- perform an imitation lseek operation remotely
466 1.1 jtc */
467 1.7 lukem static off_t
468 1.14 lukem _rmt_lseek(int fildes, off_t offset, int whence)
469 1.1 jtc {
470 1.1 jtc char buffer[BUFMAGIC];
471 1.1 jtc
472 1.14 lukem (void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset,
473 1.8 mrg whence);
474 1.1 jtc if (command(fildes, buffer) == -1)
475 1.15 enami return (-1);
476 1.1 jtc
477 1.15 enami return (status(fildes));
478 1.1 jtc }
479 1.1 jtc
480 1.1 jtc
481 1.1 jtc /*
482 1.1 jtc * _rmt_ioctl --- perform raw tape operations remotely
483 1.1 jtc */
484 1.1 jtc #ifdef RMTIOCTL
485 1.7 lukem static int
486 1.14 lukem _rmt_ioctl(int fildes, unsigned long op, void *arg)
487 1.1 jtc {
488 1.1 jtc char c;
489 1.14 lukem size_t rc, cnt;
490 1.14 lukem char buffer[BUFMAGIC], *p;
491 1.1 jtc
492 1.12 lukem _DIAGASSERT(arg != NULL);
493 1.12 lukem
494 1.1 jtc /*
495 1.1 jtc * MTIOCOP is the easy one. nothing is transfered in binary
496 1.1 jtc */
497 1.1 jtc
498 1.14 lukem if (op == MTIOCTOP) {
499 1.5 mrg (void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
500 1.5 mrg ((struct mtop *)arg)->mt_op,
501 1.5 mrg ((struct mtop *)arg)->mt_count);
502 1.1 jtc if (command(fildes, buffer) == -1)
503 1.15 enami return (-1);
504 1.15 enami return (status(fildes));
505 1.1 jtc }
506 1.1 jtc
507 1.1 jtc /*
508 1.1 jtc * we can only handle 2 ops, if not the other one, punt
509 1.1 jtc */
510 1.1 jtc
511 1.14 lukem if (op != MTIOCGET) {
512 1.1 jtc errno = EINVAL;
513 1.15 enami return (-1);
514 1.1 jtc }
515 1.1 jtc
516 1.1 jtc /*
517 1.1 jtc * grab the status and read it directly into the structure
518 1.1 jtc * this assumes that the status buffer is (hopefully) not
519 1.1 jtc * padded and that 2 shorts fit in a long without any word
520 1.1 jtc * alignment problems, ie - the whole struct is contiguous
521 1.1 jtc * NOTE - this is probably NOT a good assumption.
522 1.1 jtc */
523 1.1 jtc
524 1.1 jtc if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
525 1.15 enami return (-1);
526 1.1 jtc
527 1.14 lukem p = arg;
528 1.14 lukem for (; rc > 0; rc -= cnt, p += cnt) {
529 1.14 lukem cnt = read(READ(fildes), p, rc);
530 1.14 lukem if (cnt <= 0) {
531 1.2 jtc rmtabort(fildes);
532 1.1 jtc errno = EIO;
533 1.15 enami return (-1);
534 1.1 jtc }
535 1.1 jtc }
536 1.1 jtc
537 1.1 jtc /*
538 1.1 jtc * now we check for byte position. mt_type is a small integer field
539 1.1 jtc * (normally) so we will check its magnitude. if it is larger than
540 1.1 jtc * 256, we will assume that the bytes are swapped and go through
541 1.1 jtc * and reverse all the bytes
542 1.1 jtc */
543 1.1 jtc
544 1.14 lukem if (((struct mtget *) p)->mt_type < 256)
545 1.15 enami return (0);
546 1.1 jtc
547 1.14 lukem for (cnt = 0; cnt < rc; cnt += 2) {
548 1.14 lukem c = p[cnt];
549 1.14 lukem p[cnt] = p[cnt+1];
550 1.14 lukem p[cnt+1] = c;
551 1.1 jtc }
552 1.1 jtc
553 1.15 enami return (0);
554 1.15 enami }
555 1.1 jtc #endif /* RMTIOCTL */
556 1.1 jtc
557 1.14 lukem
558 1.1 jtc /*
559 1.1 jtc * Added routines to replace open(), close(), lseek(), ioctl(), etc.
560 1.1 jtc * The preprocessor can be used to remap these the rmtopen(), etc
561 1.1 jtc * thus minimizing source changes:
562 1.1 jtc *
563 1.1 jtc * #ifdef <something>
564 1.1 jtc * # define access rmtaccess
565 1.1 jtc * # define close rmtclose
566 1.1 jtc * # define creat rmtcreat
567 1.1 jtc * # define dup rmtdup
568 1.1 jtc * # define fcntl rmtfcntl
569 1.1 jtc * # define fstat rmtfstat
570 1.1 jtc * # define ioctl rmtioctl
571 1.1 jtc * # define isatty rmtisatty
572 1.1 jtc * # define lseek rmtlseek
573 1.1 jtc * # define lstat rmtlstat
574 1.1 jtc * # define open rmtopen
575 1.1 jtc * # define read rmtread
576 1.1 jtc * # define stat rmtstat
577 1.1 jtc * # define write rmtwrite
578 1.1 jtc * #endif
579 1.1 jtc *
580 1.1 jtc * -- Fred Fish
581 1.1 jtc *
582 1.1 jtc * ADR --- I set up a <rmt.h> include file for this
583 1.1 jtc *
584 1.1 jtc */
585 1.1 jtc
586 1.1 jtc /*
587 1.1 jtc * Note that local vs remote file descriptors are distinquished
588 1.1 jtc * by adding a bias to the remote descriptors. This is a quick
589 1.1 jtc * and dirty trick that may not be portable to some systems.
590 1.1 jtc */
591 1.1 jtc
592 1.1 jtc #define REM_BIAS 128
593 1.1 jtc
594 1.1 jtc
595 1.1 jtc /*
596 1.1 jtc * Test pathname to see if it is local or remote. A remote device
597 1.1 jtc * is any string that contains ":/dev/". Returns 1 if remote,
598 1.1 jtc * 0 otherwise.
599 1.1 jtc */
600 1.11 simonb
601 1.7 lukem static int
602 1.14 lukem remdev(const char *path)
603 1.1 jtc {
604 1.12 lukem
605 1.12 lukem _DIAGASSERT(path != NULL);
606 1.12 lukem
607 1.14 lukem if ((path = strchr(path, ':')) != NULL) {
608 1.14 lukem if (strncmp(path + 1, "/dev/", 5) == 0) {
609 1.1 jtc return (1);
610 1.1 jtc }
611 1.1 jtc }
612 1.1 jtc return (0);
613 1.1 jtc }
614 1.1 jtc
615 1.1 jtc
616 1.1 jtc /*
617 1.1 jtc * Open a local or remote file. Looks just like open(2) to
618 1.1 jtc * caller.
619 1.1 jtc */
620 1.7 lukem int
621 1.9 thorpej rmtopen(const char *path, int oflag, ...)
622 1.9 thorpej {
623 1.9 thorpej mode_t mode;
624 1.9 thorpej int fd;
625 1.9 thorpej va_list ap;
626 1.9 thorpej va_start(ap, oflag);
627 1.9 thorpej
628 1.9 thorpej mode = va_arg(ap, mode_t);
629 1.9 thorpej va_end(ap);
630 1.1 jtc
631 1.12 lukem _DIAGASSERT(path != NULL);
632 1.12 lukem
633 1.14 lukem if (remdev(path)) {
634 1.14 lukem fd = _rmt_open(path, oflag, mode);
635 1.1 jtc
636 1.14 lukem return ((fd == -1) ? -1 : (fd + REM_BIAS));
637 1.14 lukem } else {
638 1.14 lukem return (open(path, oflag, mode));
639 1.1 jtc }
640 1.1 jtc }
641 1.1 jtc
642 1.1 jtc /*
643 1.1 jtc * Test pathname for specified access. Looks just like access(2)
644 1.1 jtc * to caller.
645 1.1 jtc */
646 1.11 simonb
647 1.7 lukem int
648 1.14 lukem rmtaccess(const char *path, int amode)
649 1.1 jtc {
650 1.12 lukem
651 1.12 lukem _DIAGASSERT(path != NULL);
652 1.12 lukem
653 1.14 lukem if (remdev(path)) {
654 1.1 jtc return (0); /* Let /etc/rmt find out */
655 1.14 lukem } else {
656 1.14 lukem return (access(path, amode));
657 1.1 jtc }
658 1.1 jtc }
659 1.1 jtc
660 1.1 jtc
661 1.1 jtc /*
662 1.6 mikel * Isrmt. Let a programmer know he has a remote device.
663 1.6 mikel */
664 1.7 lukem int
665 1.14 lukem isrmt(int fd)
666 1.6 mikel {
667 1.14 lukem
668 1.6 mikel return (fd >= REM_BIAS);
669 1.6 mikel }
670 1.6 mikel
671 1.6 mikel
672 1.6 mikel /*
673 1.1 jtc * Read from stream. Looks just like read(2) to caller.
674 1.1 jtc */
675 1.7 lukem ssize_t
676 1.14 lukem rmtread(int fildes, void *buf, size_t nbyte)
677 1.1 jtc {
678 1.12 lukem
679 1.12 lukem _DIAGASSERT(buf != NULL);
680 1.12 lukem
681 1.14 lukem if (isrmt(fildes)) {
682 1.14 lukem return (_rmt_read(fildes - REM_BIAS, buf, nbyte));
683 1.14 lukem } else {
684 1.14 lukem return (read(fildes, buf, nbyte));
685 1.1 jtc }
686 1.1 jtc }
687 1.1 jtc
688 1.1 jtc
689 1.1 jtc /*
690 1.1 jtc * Write to stream. Looks just like write(2) to caller.
691 1.1 jtc */
692 1.7 lukem ssize_t
693 1.14 lukem rmtwrite(int fildes, const void *buf, size_t nbyte)
694 1.1 jtc {
695 1.12 lukem
696 1.12 lukem _DIAGASSERT(buf != NULL);
697 1.12 lukem
698 1.14 lukem if (isrmt(fildes)) {
699 1.14 lukem return (_rmt_write(fildes - REM_BIAS, buf, nbyte));
700 1.14 lukem } else {
701 1.14 lukem return (write(fildes, buf, nbyte));
702 1.1 jtc }
703 1.1 jtc }
704 1.1 jtc
705 1.1 jtc /*
706 1.1 jtc * Perform lseek on file. Looks just like lseek(2) to caller.
707 1.1 jtc */
708 1.7 lukem off_t
709 1.14 lukem rmtlseek(int fildes, off_t offset, int whence)
710 1.14 lukem {
711 1.15 enami
712 1.14 lukem if (isrmt(fildes)) {
713 1.14 lukem return (_rmt_lseek(fildes - REM_BIAS, offset, whence));
714 1.14 lukem } else {
715 1.14 lukem return (lseek(fildes, offset, whence));
716 1.1 jtc }
717 1.1 jtc }
718 1.1 jtc
719 1.1 jtc
720 1.1 jtc /*
721 1.1 jtc * Close a file. Looks just like close(2) to caller.
722 1.1 jtc */
723 1.7 lukem int
724 1.14 lukem rmtclose(int fildes)
725 1.1 jtc {
726 1.15 enami
727 1.14 lukem if (isrmt(fildes)) {
728 1.14 lukem return (_rmt_close(fildes - REM_BIAS));
729 1.14 lukem } else {
730 1.14 lukem return (close(fildes));
731 1.1 jtc }
732 1.1 jtc }
733 1.1 jtc
734 1.14 lukem
735 1.1 jtc /*
736 1.1 jtc * Do ioctl on file. Looks just like ioctl(2) to caller.
737 1.1 jtc */
738 1.7 lukem int
739 1.9 thorpej rmtioctl(int fildes, unsigned long request, ...)
740 1.9 thorpej {
741 1.9 thorpej char *arg;
742 1.9 thorpej va_list ap;
743 1.9 thorpej va_start(ap, request);
744 1.9 thorpej
745 1.9 thorpej arg = va_arg(ap, char *);
746 1.9 thorpej va_end(ap);
747 1.9 thorpej
748 1.12 lukem /* XXX: arg may be NULL ? */
749 1.12 lukem
750 1.14 lukem if (isrmt(fildes)) {
751 1.1 jtc #ifdef RMTIOCTL
752 1.14 lukem return (_rmt_ioctl(fildes - REM_BIAS, request, arg));
753 1.1 jtc #else
754 1.1 jtc errno = EOPNOTSUPP;
755 1.14 lukem return (-1); /* For now (fnf) */
756 1.1 jtc #endif
757 1.14 lukem } else {
758 1.14 lukem return (ioctl(fildes, request, arg));
759 1.1 jtc }
760 1.1 jtc }
761 1.1 jtc
762 1.1 jtc
763 1.1 jtc /*
764 1.1 jtc * Duplicate an open file descriptor. Looks just like dup(2)
765 1.1 jtc * to caller.
766 1.1 jtc */
767 1.7 lukem int
768 1.14 lukem rmtdup(int fildes)
769 1.1 jtc {
770 1.15 enami
771 1.14 lukem if (isrmt(fildes)) {
772 1.1 jtc errno = EOPNOTSUPP;
773 1.1 jtc return (-1); /* For now (fnf) */
774 1.14 lukem } else {
775 1.14 lukem return (dup(fildes));
776 1.1 jtc }
777 1.1 jtc }
778 1.1 jtc
779 1.14 lukem
780 1.1 jtc /*
781 1.1 jtc * Get file status. Looks just like fstat(2) to caller.
782 1.1 jtc */
783 1.7 lukem int
784 1.14 lukem rmtfstat(int fildes, struct stat *buf)
785 1.1 jtc {
786 1.12 lukem
787 1.12 lukem _DIAGASSERT(buf != NULL);
788 1.12 lukem
789 1.14 lukem if (isrmt(fildes)) {
790 1.1 jtc errno = EOPNOTSUPP;
791 1.1 jtc return (-1); /* For now (fnf) */
792 1.14 lukem } else {
793 1.14 lukem return (fstat(fildes, buf));
794 1.1 jtc }
795 1.1 jtc }
796 1.1 jtc
797 1.1 jtc
798 1.1 jtc /*
799 1.1 jtc * Get file status. Looks just like stat(2) to caller.
800 1.1 jtc */
801 1.7 lukem int
802 1.14 lukem rmtstat(const char *path, struct stat *buf)
803 1.1 jtc {
804 1.12 lukem
805 1.12 lukem _DIAGASSERT(path != NULL);
806 1.12 lukem _DIAGASSERT(buf != NULL);
807 1.12 lukem
808 1.14 lukem if (remdev(path)) {
809 1.1 jtc errno = EOPNOTSUPP;
810 1.1 jtc return (-1); /* For now (fnf) */
811 1.14 lukem } else {
812 1.14 lukem return (stat(path, buf));
813 1.1 jtc }
814 1.1 jtc }
815 1.1 jtc
816 1.1 jtc
817 1.1 jtc /*
818 1.1 jtc * Create a file from scratch. Looks just like creat(2) to the caller.
819 1.1 jtc */
820 1.7 lukem int
821 1.14 lukem rmtcreat(const char *path, mode_t mode)
822 1.1 jtc {
823 1.12 lukem
824 1.12 lukem _DIAGASSERT(path != NULL);
825 1.12 lukem
826 1.14 lukem if (remdev(path)) {
827 1.14 lukem return (rmtopen(path, 1 | O_CREAT, mode));
828 1.14 lukem } else {
829 1.14 lukem return (creat(path, mode));
830 1.1 jtc }
831 1.1 jtc }
832 1.1 jtc
833 1.14 lukem
834 1.1 jtc /*
835 1.1 jtc * Rmtfcntl. Do a remote fcntl operation.
836 1.1 jtc */
837 1.7 lukem int
838 1.9 thorpej rmtfcntl(int fd, int cmd, ...)
839 1.1 jtc {
840 1.9 thorpej void *arg;
841 1.9 thorpej va_list ap;
842 1.9 thorpej va_start(ap, cmd);
843 1.9 thorpej
844 1.9 thorpej arg = va_arg(ap, void *);
845 1.9 thorpej va_end(ap);
846 1.9 thorpej
847 1.12 lukem /* XXX: arg may be NULL ? */
848 1.12 lukem
849 1.14 lukem if (isrmt(fd)) {
850 1.1 jtc errno = EOPNOTSUPP;
851 1.1 jtc return (-1);
852 1.14 lukem } else {
853 1.14 lukem return (fcntl(fd, cmd, arg));
854 1.1 jtc }
855 1.1 jtc }
856 1.1 jtc
857 1.14 lukem
858 1.1 jtc /*
859 1.1 jtc * Rmtisatty. Do the isatty function.
860 1.1 jtc */
861 1.7 lukem int
862 1.14 lukem rmtisatty(int fd)
863 1.1 jtc {
864 1.14 lukem
865 1.14 lukem if (isrmt(fd))
866 1.1 jtc return (0);
867 1.1 jtc else
868 1.14 lukem return (isatty(fd));
869 1.1 jtc }
870 1.1 jtc
871 1.1 jtc
872 1.1 jtc /*
873 1.1 jtc * Get file status, even if symlink. Looks just like lstat(2) to caller.
874 1.1 jtc */
875 1.7 lukem int
876 1.14 lukem rmtlstat(const char *path, struct stat *buf)
877 1.1 jtc {
878 1.12 lukem
879 1.12 lukem _DIAGASSERT(path != NULL);
880 1.12 lukem _DIAGASSERT(buf != NULL);
881 1.12 lukem
882 1.14 lukem if (remdev(path)) {
883 1.1 jtc errno = EOPNOTSUPP;
884 1.1 jtc return (-1); /* For now (fnf) */
885 1.14 lukem } else {
886 1.14 lukem return (lstat(path, buf));
887 1.1 jtc }
888 1.1 jtc }
889