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