rmtlib.c revision 1.19 1 1.19 lukem /* $NetBSD: rmtlib.c,v 1.19 2003/03/08 07:47:49 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.19 lukem
30 1.19 lukem #include <sys/cdefs.h>
31 1.19 lukem __RCSID("$NetBSD: rmtlib.c,v 1.19 2003/03/08 07:47:49 lukem 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.14 lukem _rmt_open(const char *path, int oflag, int mode)
252 1.1 jtc {
253 1.1 jtc int i, rc;
254 1.1 jtc char buffer[BUFMAGIC];
255 1.18 lukem char host[MAXHOSTLEN];
256 1.1 jtc char device[BUFMAGIC];
257 1.1 jtc char login[BUFMAGIC];
258 1.1 jtc char *sys, *dev, *user;
259 1.1 jtc
260 1.12 lukem _DIAGASSERT(path != NULL);
261 1.12 lukem
262 1.18 lukem sys = host;
263 1.1 jtc dev = device;
264 1.1 jtc user = login;
265 1.1 jtc
266 1.1 jtc /*
267 1.1 jtc * first, find an open pair of file descriptors
268 1.1 jtc */
269 1.1 jtc
270 1.1 jtc for (i = 0; i < MAXUNIT; i++)
271 1.1 jtc if (READ(i) == -1 && WRITE(i) == -1)
272 1.1 jtc break;
273 1.1 jtc
274 1.14 lukem if (i == MAXUNIT) {
275 1.1 jtc errno = EMFILE;
276 1.15 enami return (-1);
277 1.1 jtc }
278 1.1 jtc
279 1.1 jtc /*
280 1.1 jtc * pull apart system and device, and optional user
281 1.1 jtc * don't munge original string
282 1.1 jtc * if COMPAT is defined, also handle old (4.2) style person.site notation.
283 1.1 jtc */
284 1.1 jtc
285 1.1 jtc while (*path != '@'
286 1.1 jtc #ifdef COMPAT
287 1.1 jtc && *path != '.'
288 1.1 jtc #endif
289 1.1 jtc && *path != ':') {
290 1.1 jtc *sys++ = *path++;
291 1.1 jtc }
292 1.1 jtc *sys = '\0';
293 1.1 jtc path++;
294 1.1 jtc
295 1.14 lukem if (*(path - 1) == '@') {
296 1.18 lukem (void)strncpy(user, host, sizeof(login) - 1);
297 1.5 mrg /* saw user part of user@host */
298 1.18 lukem sys = host; /* start over */
299 1.1 jtc while (*path != ':') {
300 1.1 jtc *sys++ = *path++;
301 1.1 jtc }
302 1.1 jtc *sys = '\0';
303 1.1 jtc path++;
304 1.1 jtc }
305 1.1 jtc #ifdef COMPAT
306 1.14 lukem else if (*(path - 1) == '.') {
307 1.1 jtc while (*path != ':') {
308 1.1 jtc *user++ = *path++;
309 1.1 jtc }
310 1.1 jtc *user = '\0';
311 1.1 jtc path++;
312 1.1 jtc }
313 1.1 jtc #endif
314 1.1 jtc else
315 1.1 jtc *user = '\0';
316 1.1 jtc
317 1.1 jtc while (*path) {
318 1.1 jtc *dev++ = *path++;
319 1.1 jtc }
320 1.1 jtc *dev = '\0';
321 1.1 jtc
322 1.1 jtc #ifdef USE_REXEC
323 1.11 simonb /*
324 1.11 simonb * Execute the remote command using rexec
325 1.1 jtc */
326 1.18 lukem READ(i) = WRITE(i) = _rmt_rexec(host, login);
327 1.1 jtc if (READ(i) < 0)
328 1.15 enami return (-1);
329 1.1 jtc #else
330 1.1 jtc /*
331 1.1 jtc * setup the pipes for the 'rsh' command and fork
332 1.1 jtc */
333 1.1 jtc
334 1.1 jtc if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
335 1.15 enami return (-1);
336 1.1 jtc
337 1.1 jtc if ((rc = fork()) == -1)
338 1.15 enami return (-1);
339 1.1 jtc
340 1.14 lukem if (rc == 0) {
341 1.10 mrg char *rshpath, *rsh;
342 1.10 mrg
343 1.1 jtc close(0);
344 1.1 jtc dup(Ptc[i][0]);
345 1.1 jtc close(Ptc[i][0]); close(Ptc[i][1]);
346 1.1 jtc close(1);
347 1.1 jtc dup(Ctp[i][1]);
348 1.1 jtc close(Ctp[i][0]); close(Ctp[i][1]);
349 1.14 lukem (void) setuid(getuid());
350 1.14 lukem (void) setgid(getgid());
351 1.11 simonb
352 1.10 mrg if ((rshpath = getenv("RCMD_CMD")) == NULL)
353 1.10 mrg rshpath = _PATH_RSH;
354 1.10 mrg if ((rsh = strrchr(rshpath, '/')) == NULL)
355 1.10 mrg rsh = rshpath;
356 1.10 mrg else
357 1.10 mrg rsh++;
358 1.11 simonb
359 1.14 lukem if (*login) {
360 1.18 lukem execl(rshpath, rsh, host, "-l", login,
361 1.15 enami _PATH_RMT, NULL);
362 1.14 lukem } else {
363 1.18 lukem execl(rshpath, rsh, host,
364 1.15 enami _PATH_RMT, NULL);
365 1.1 jtc }
366 1.1 jtc
367 1.1 jtc /*
368 1.1 jtc * bad problems if we get here
369 1.1 jtc */
370 1.1 jtc
371 1.1 jtc perror("exec");
372 1.1 jtc exit(1);
373 1.1 jtc }
374 1.1 jtc
375 1.1 jtc close(Ptc[i][0]); close(Ctp[i][1]);
376 1.1 jtc #endif
377 1.1 jtc
378 1.1 jtc /*
379 1.1 jtc * now attempt to open the tape device
380 1.1 jtc */
381 1.1 jtc
382 1.5 mrg (void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
383 1.1 jtc if (command(i, buffer) == -1 || status(i) == -1)
384 1.15 enami return (-1);
385 1.1 jtc
386 1.15 enami return (i);
387 1.1 jtc }
388 1.1 jtc
389 1.1 jtc
390 1.1 jtc /*
391 1.1 jtc * _rmt_close --- close a remote magtape unit and shut down
392 1.1 jtc */
393 1.7 lukem static int
394 1.14 lukem _rmt_close(int fildes)
395 1.1 jtc {
396 1.1 jtc int rc;
397 1.1 jtc
398 1.14 lukem if (command(fildes, "C\n") != -1) {
399 1.1 jtc rc = status(fildes);
400 1.1 jtc
401 1.2 jtc rmtabort(fildes);
402 1.15 enami return (rc);
403 1.1 jtc }
404 1.1 jtc
405 1.15 enami return (-1);
406 1.1 jtc }
407 1.1 jtc
408 1.1 jtc
409 1.1 jtc /*
410 1.1 jtc * _rmt_read --- read a buffer from a remote tape
411 1.1 jtc */
412 1.14 lukem static ssize_t
413 1.14 lukem _rmt_read(int fildes, void *buf, size_t nbyte)
414 1.1 jtc {
415 1.14 lukem size_t rc, i;
416 1.14 lukem char *p;
417 1.1 jtc char buffer[BUFMAGIC];
418 1.1 jtc
419 1.12 lukem _DIAGASSERT(buf != NULL);
420 1.12 lukem
421 1.16 enami (void)snprintf(buffer, sizeof buffer, "R%lu\n", (u_long)nbyte);
422 1.1 jtc if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
423 1.15 enami return (-1);
424 1.1 jtc
425 1.14 lukem p = buf;
426 1.14 lukem for (i = 0; i < rc; i += nbyte, p += nbyte) {
427 1.14 lukem nbyte = read(READ(fildes), p, rc);
428 1.14 lukem if (nbyte <= 0) {
429 1.2 jtc rmtabort(fildes);
430 1.1 jtc errno = EIO;
431 1.15 enami return (-1);
432 1.1 jtc }
433 1.1 jtc }
434 1.1 jtc
435 1.15 enami return (rc);
436 1.1 jtc }
437 1.1 jtc
438 1.1 jtc
439 1.1 jtc /*
440 1.1 jtc * _rmt_write --- write a buffer to the remote tape
441 1.1 jtc */
442 1.14 lukem static ssize_t
443 1.14 lukem _rmt_write(int fildes, const void *buf, size_t nbyte)
444 1.1 jtc {
445 1.1 jtc char buffer[BUFMAGIC];
446 1.14 lukem void (*pstat)(int);
447 1.1 jtc
448 1.12 lukem _DIAGASSERT(buf != NULL);
449 1.12 lukem
450 1.16 enami (void)snprintf(buffer, sizeof buffer, "W%lu\n", (u_long)nbyte);
451 1.1 jtc if (command(fildes, buffer) == -1)
452 1.15 enami return (-1);
453 1.1 jtc
454 1.1 jtc pstat = signal(SIGPIPE, SIG_IGN);
455 1.14 lukem if (write(WRITE(fildes), buf, nbyte) == nbyte) {
456 1.14 lukem signal(SIGPIPE, pstat);
457 1.15 enami return (status(fildes));
458 1.1 jtc }
459 1.1 jtc
460 1.14 lukem signal(SIGPIPE, pstat);
461 1.2 jtc rmtabort(fildes);
462 1.1 jtc errno = EIO;
463 1.15 enami return (-1);
464 1.1 jtc }
465 1.1 jtc
466 1.1 jtc
467 1.1 jtc /*
468 1.1 jtc * _rmt_lseek --- perform an imitation lseek operation remotely
469 1.1 jtc */
470 1.7 lukem static off_t
471 1.14 lukem _rmt_lseek(int fildes, off_t offset, int whence)
472 1.1 jtc {
473 1.1 jtc char buffer[BUFMAGIC];
474 1.1 jtc
475 1.14 lukem (void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset,
476 1.8 mrg whence);
477 1.1 jtc if (command(fildes, buffer) == -1)
478 1.15 enami return (-1);
479 1.1 jtc
480 1.15 enami return (status(fildes));
481 1.1 jtc }
482 1.1 jtc
483 1.1 jtc
484 1.1 jtc /*
485 1.1 jtc * _rmt_ioctl --- perform raw tape operations remotely
486 1.1 jtc */
487 1.1 jtc #ifdef RMTIOCTL
488 1.7 lukem static int
489 1.14 lukem _rmt_ioctl(int fildes, unsigned long op, void *arg)
490 1.1 jtc {
491 1.1 jtc char c;
492 1.14 lukem size_t rc, cnt;
493 1.14 lukem char buffer[BUFMAGIC], *p;
494 1.1 jtc
495 1.12 lukem _DIAGASSERT(arg != NULL);
496 1.12 lukem
497 1.1 jtc /*
498 1.1 jtc * MTIOCOP is the easy one. nothing is transfered in binary
499 1.1 jtc */
500 1.1 jtc
501 1.14 lukem if (op == MTIOCTOP) {
502 1.5 mrg (void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
503 1.5 mrg ((struct mtop *)arg)->mt_op,
504 1.5 mrg ((struct mtop *)arg)->mt_count);
505 1.1 jtc if (command(fildes, buffer) == -1)
506 1.15 enami return (-1);
507 1.15 enami return (status(fildes));
508 1.1 jtc }
509 1.1 jtc
510 1.1 jtc /*
511 1.1 jtc * we can only handle 2 ops, if not the other one, punt
512 1.1 jtc */
513 1.1 jtc
514 1.14 lukem if (op != MTIOCGET) {
515 1.1 jtc errno = EINVAL;
516 1.15 enami return (-1);
517 1.1 jtc }
518 1.1 jtc
519 1.1 jtc /*
520 1.1 jtc * grab the status and read it directly into the structure
521 1.1 jtc * this assumes that the status buffer is (hopefully) not
522 1.1 jtc * padded and that 2 shorts fit in a long without any word
523 1.1 jtc * alignment problems, ie - the whole struct is contiguous
524 1.1 jtc * NOTE - this is probably NOT a good assumption.
525 1.1 jtc */
526 1.1 jtc
527 1.1 jtc if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
528 1.15 enami return (-1);
529 1.1 jtc
530 1.14 lukem p = arg;
531 1.14 lukem for (; rc > 0; rc -= cnt, p += cnt) {
532 1.14 lukem cnt = read(READ(fildes), p, rc);
533 1.14 lukem if (cnt <= 0) {
534 1.2 jtc rmtabort(fildes);
535 1.1 jtc errno = EIO;
536 1.15 enami return (-1);
537 1.1 jtc }
538 1.1 jtc }
539 1.1 jtc
540 1.1 jtc /*
541 1.1 jtc * now we check for byte position. mt_type is a small integer field
542 1.1 jtc * (normally) so we will check its magnitude. if it is larger than
543 1.1 jtc * 256, we will assume that the bytes are swapped and go through
544 1.1 jtc * and reverse all the bytes
545 1.1 jtc */
546 1.1 jtc
547 1.14 lukem if (((struct mtget *) p)->mt_type < 256)
548 1.15 enami return (0);
549 1.1 jtc
550 1.14 lukem for (cnt = 0; cnt < rc; cnt += 2) {
551 1.14 lukem c = p[cnt];
552 1.14 lukem p[cnt] = p[cnt+1];
553 1.14 lukem p[cnt+1] = c;
554 1.1 jtc }
555 1.1 jtc
556 1.15 enami return (0);
557 1.15 enami }
558 1.1 jtc #endif /* RMTIOCTL */
559 1.1 jtc
560 1.14 lukem
561 1.1 jtc /*
562 1.1 jtc * Added routines to replace open(), close(), lseek(), ioctl(), etc.
563 1.1 jtc * The preprocessor can be used to remap these the rmtopen(), etc
564 1.1 jtc * thus minimizing source changes:
565 1.1 jtc *
566 1.1 jtc * #ifdef <something>
567 1.1 jtc * # define access rmtaccess
568 1.1 jtc * # define close rmtclose
569 1.1 jtc * # define creat rmtcreat
570 1.1 jtc * # define dup rmtdup
571 1.1 jtc * # define fcntl rmtfcntl
572 1.1 jtc * # define fstat rmtfstat
573 1.1 jtc * # define ioctl rmtioctl
574 1.1 jtc * # define isatty rmtisatty
575 1.1 jtc * # define lseek rmtlseek
576 1.1 jtc * # define lstat rmtlstat
577 1.1 jtc * # define open rmtopen
578 1.1 jtc * # define read rmtread
579 1.1 jtc * # define stat rmtstat
580 1.1 jtc * # define write rmtwrite
581 1.1 jtc * #endif
582 1.1 jtc *
583 1.1 jtc * -- Fred Fish
584 1.1 jtc *
585 1.1 jtc * ADR --- I set up a <rmt.h> include file for this
586 1.1 jtc *
587 1.1 jtc */
588 1.1 jtc
589 1.1 jtc /*
590 1.1 jtc * Note that local vs remote file descriptors are distinquished
591 1.1 jtc * by adding a bias to the remote descriptors. This is a quick
592 1.1 jtc * and dirty trick that may not be portable to some systems.
593 1.1 jtc */
594 1.1 jtc
595 1.1 jtc #define REM_BIAS 128
596 1.1 jtc
597 1.1 jtc
598 1.1 jtc /*
599 1.1 jtc * Test pathname to see if it is local or remote. A remote device
600 1.1 jtc * is any string that contains ":/dev/". Returns 1 if remote,
601 1.1 jtc * 0 otherwise.
602 1.1 jtc */
603 1.11 simonb
604 1.7 lukem static int
605 1.14 lukem remdev(const char *path)
606 1.1 jtc {
607 1.12 lukem
608 1.12 lukem _DIAGASSERT(path != NULL);
609 1.12 lukem
610 1.14 lukem if ((path = strchr(path, ':')) != NULL) {
611 1.14 lukem if (strncmp(path + 1, "/dev/", 5) == 0) {
612 1.1 jtc return (1);
613 1.1 jtc }
614 1.1 jtc }
615 1.1 jtc return (0);
616 1.1 jtc }
617 1.1 jtc
618 1.1 jtc
619 1.1 jtc /*
620 1.1 jtc * Open a local or remote file. Looks just like open(2) to
621 1.1 jtc * caller.
622 1.1 jtc */
623 1.7 lukem int
624 1.9 thorpej rmtopen(const char *path, int oflag, ...)
625 1.9 thorpej {
626 1.9 thorpej mode_t mode;
627 1.9 thorpej int fd;
628 1.9 thorpej va_list ap;
629 1.9 thorpej va_start(ap, oflag);
630 1.9 thorpej
631 1.9 thorpej mode = va_arg(ap, mode_t);
632 1.9 thorpej va_end(ap);
633 1.1 jtc
634 1.12 lukem _DIAGASSERT(path != NULL);
635 1.12 lukem
636 1.14 lukem if (remdev(path)) {
637 1.14 lukem fd = _rmt_open(path, oflag, mode);
638 1.1 jtc
639 1.14 lukem return ((fd == -1) ? -1 : (fd + REM_BIAS));
640 1.14 lukem } else {
641 1.14 lukem return (open(path, oflag, mode));
642 1.1 jtc }
643 1.1 jtc }
644 1.1 jtc
645 1.1 jtc /*
646 1.1 jtc * Test pathname for specified access. Looks just like access(2)
647 1.1 jtc * to caller.
648 1.1 jtc */
649 1.11 simonb
650 1.7 lukem int
651 1.14 lukem rmtaccess(const char *path, int amode)
652 1.1 jtc {
653 1.12 lukem
654 1.12 lukem _DIAGASSERT(path != NULL);
655 1.12 lukem
656 1.14 lukem if (remdev(path)) {
657 1.1 jtc return (0); /* Let /etc/rmt find out */
658 1.14 lukem } else {
659 1.14 lukem return (access(path, amode));
660 1.1 jtc }
661 1.1 jtc }
662 1.1 jtc
663 1.1 jtc
664 1.1 jtc /*
665 1.6 mikel * Isrmt. Let a programmer know he has a remote device.
666 1.6 mikel */
667 1.7 lukem int
668 1.14 lukem isrmt(int fd)
669 1.6 mikel {
670 1.14 lukem
671 1.6 mikel return (fd >= REM_BIAS);
672 1.6 mikel }
673 1.6 mikel
674 1.6 mikel
675 1.6 mikel /*
676 1.1 jtc * Read from stream. Looks just like read(2) to caller.
677 1.1 jtc */
678 1.7 lukem ssize_t
679 1.14 lukem rmtread(int fildes, void *buf, size_t nbyte)
680 1.1 jtc {
681 1.12 lukem
682 1.12 lukem _DIAGASSERT(buf != NULL);
683 1.12 lukem
684 1.14 lukem if (isrmt(fildes)) {
685 1.14 lukem return (_rmt_read(fildes - REM_BIAS, buf, nbyte));
686 1.14 lukem } else {
687 1.14 lukem return (read(fildes, buf, nbyte));
688 1.1 jtc }
689 1.1 jtc }
690 1.1 jtc
691 1.1 jtc
692 1.1 jtc /*
693 1.1 jtc * Write to stream. Looks just like write(2) to caller.
694 1.1 jtc */
695 1.7 lukem ssize_t
696 1.14 lukem rmtwrite(int fildes, const void *buf, size_t nbyte)
697 1.1 jtc {
698 1.12 lukem
699 1.12 lukem _DIAGASSERT(buf != NULL);
700 1.12 lukem
701 1.14 lukem if (isrmt(fildes)) {
702 1.14 lukem return (_rmt_write(fildes - REM_BIAS, buf, nbyte));
703 1.14 lukem } else {
704 1.14 lukem return (write(fildes, buf, nbyte));
705 1.1 jtc }
706 1.1 jtc }
707 1.1 jtc
708 1.1 jtc /*
709 1.1 jtc * Perform lseek on file. Looks just like lseek(2) to caller.
710 1.1 jtc */
711 1.7 lukem off_t
712 1.14 lukem rmtlseek(int fildes, off_t offset, int whence)
713 1.14 lukem {
714 1.15 enami
715 1.14 lukem if (isrmt(fildes)) {
716 1.14 lukem return (_rmt_lseek(fildes - REM_BIAS, offset, whence));
717 1.14 lukem } else {
718 1.14 lukem return (lseek(fildes, offset, whence));
719 1.1 jtc }
720 1.1 jtc }
721 1.1 jtc
722 1.1 jtc
723 1.1 jtc /*
724 1.1 jtc * Close a file. Looks just like close(2) to caller.
725 1.1 jtc */
726 1.7 lukem int
727 1.14 lukem rmtclose(int fildes)
728 1.1 jtc {
729 1.15 enami
730 1.14 lukem if (isrmt(fildes)) {
731 1.14 lukem return (_rmt_close(fildes - REM_BIAS));
732 1.14 lukem } else {
733 1.14 lukem return (close(fildes));
734 1.1 jtc }
735 1.1 jtc }
736 1.1 jtc
737 1.14 lukem
738 1.1 jtc /*
739 1.1 jtc * Do ioctl on file. Looks just like ioctl(2) to caller.
740 1.1 jtc */
741 1.7 lukem int
742 1.9 thorpej rmtioctl(int fildes, unsigned long request, ...)
743 1.9 thorpej {
744 1.9 thorpej char *arg;
745 1.9 thorpej va_list ap;
746 1.9 thorpej va_start(ap, request);
747 1.9 thorpej
748 1.9 thorpej arg = va_arg(ap, char *);
749 1.9 thorpej va_end(ap);
750 1.9 thorpej
751 1.12 lukem /* XXX: arg may be NULL ? */
752 1.12 lukem
753 1.14 lukem if (isrmt(fildes)) {
754 1.1 jtc #ifdef RMTIOCTL
755 1.14 lukem return (_rmt_ioctl(fildes - REM_BIAS, request, arg));
756 1.1 jtc #else
757 1.1 jtc errno = EOPNOTSUPP;
758 1.14 lukem return (-1); /* For now (fnf) */
759 1.1 jtc #endif
760 1.14 lukem } else {
761 1.14 lukem return (ioctl(fildes, request, arg));
762 1.1 jtc }
763 1.1 jtc }
764 1.1 jtc
765 1.1 jtc
766 1.1 jtc /*
767 1.1 jtc * Duplicate an open file descriptor. Looks just like dup(2)
768 1.1 jtc * to caller.
769 1.1 jtc */
770 1.7 lukem int
771 1.14 lukem rmtdup(int fildes)
772 1.1 jtc {
773 1.15 enami
774 1.14 lukem if (isrmt(fildes)) {
775 1.1 jtc errno = EOPNOTSUPP;
776 1.1 jtc return (-1); /* For now (fnf) */
777 1.14 lukem } else {
778 1.14 lukem return (dup(fildes));
779 1.1 jtc }
780 1.1 jtc }
781 1.1 jtc
782 1.14 lukem
783 1.1 jtc /*
784 1.1 jtc * Get file status. Looks just like fstat(2) to caller.
785 1.1 jtc */
786 1.7 lukem int
787 1.14 lukem rmtfstat(int fildes, struct stat *buf)
788 1.1 jtc {
789 1.12 lukem
790 1.12 lukem _DIAGASSERT(buf != NULL);
791 1.12 lukem
792 1.14 lukem if (isrmt(fildes)) {
793 1.1 jtc errno = EOPNOTSUPP;
794 1.1 jtc return (-1); /* For now (fnf) */
795 1.14 lukem } else {
796 1.14 lukem return (fstat(fildes, buf));
797 1.1 jtc }
798 1.1 jtc }
799 1.1 jtc
800 1.1 jtc
801 1.1 jtc /*
802 1.1 jtc * Get file status. Looks just like stat(2) to caller.
803 1.1 jtc */
804 1.7 lukem int
805 1.14 lukem rmtstat(const char *path, struct stat *buf)
806 1.1 jtc {
807 1.12 lukem
808 1.12 lukem _DIAGASSERT(path != NULL);
809 1.12 lukem _DIAGASSERT(buf != NULL);
810 1.12 lukem
811 1.14 lukem if (remdev(path)) {
812 1.1 jtc errno = EOPNOTSUPP;
813 1.1 jtc return (-1); /* For now (fnf) */
814 1.14 lukem } else {
815 1.14 lukem return (stat(path, buf));
816 1.1 jtc }
817 1.1 jtc }
818 1.1 jtc
819 1.1 jtc
820 1.1 jtc /*
821 1.1 jtc * Create a file from scratch. Looks just like creat(2) to the caller.
822 1.1 jtc */
823 1.7 lukem int
824 1.14 lukem rmtcreat(const char *path, mode_t mode)
825 1.1 jtc {
826 1.12 lukem
827 1.12 lukem _DIAGASSERT(path != NULL);
828 1.12 lukem
829 1.14 lukem if (remdev(path)) {
830 1.14 lukem return (rmtopen(path, 1 | O_CREAT, mode));
831 1.14 lukem } else {
832 1.14 lukem return (creat(path, mode));
833 1.1 jtc }
834 1.1 jtc }
835 1.1 jtc
836 1.14 lukem
837 1.1 jtc /*
838 1.1 jtc * Rmtfcntl. Do a remote fcntl operation.
839 1.1 jtc */
840 1.7 lukem int
841 1.9 thorpej rmtfcntl(int fd, int cmd, ...)
842 1.1 jtc {
843 1.9 thorpej void *arg;
844 1.9 thorpej va_list ap;
845 1.9 thorpej va_start(ap, cmd);
846 1.9 thorpej
847 1.9 thorpej arg = va_arg(ap, void *);
848 1.9 thorpej va_end(ap);
849 1.9 thorpej
850 1.12 lukem /* XXX: arg may be NULL ? */
851 1.12 lukem
852 1.14 lukem if (isrmt(fd)) {
853 1.1 jtc errno = EOPNOTSUPP;
854 1.1 jtc return (-1);
855 1.14 lukem } else {
856 1.14 lukem return (fcntl(fd, cmd, arg));
857 1.1 jtc }
858 1.1 jtc }
859 1.1 jtc
860 1.14 lukem
861 1.1 jtc /*
862 1.1 jtc * Rmtisatty. Do the isatty function.
863 1.1 jtc */
864 1.7 lukem int
865 1.14 lukem rmtisatty(int fd)
866 1.1 jtc {
867 1.14 lukem
868 1.14 lukem if (isrmt(fd))
869 1.1 jtc return (0);
870 1.1 jtc else
871 1.14 lukem return (isatty(fd));
872 1.1 jtc }
873 1.1 jtc
874 1.1 jtc
875 1.1 jtc /*
876 1.1 jtc * Get file status, even if symlink. Looks just like lstat(2) to caller.
877 1.1 jtc */
878 1.7 lukem int
879 1.14 lukem rmtlstat(const char *path, struct stat *buf)
880 1.1 jtc {
881 1.12 lukem
882 1.12 lukem _DIAGASSERT(path != NULL);
883 1.12 lukem _DIAGASSERT(buf != NULL);
884 1.12 lukem
885 1.14 lukem if (remdev(path)) {
886 1.1 jtc errno = EOPNOTSUPP;
887 1.1 jtc return (-1); /* For now (fnf) */
888 1.14 lukem } else {
889 1.14 lukem return (lstat(path, buf));
890 1.1 jtc }
891 1.1 jtc }
892