4 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
8 * Copyright (c) 1980 Regents of the University of California.
9 * All rights reserved. The Berkeley software License Agreement
10 * specifies the terms and conditions for redistribution.
13 /* line below is from UCB 5.4 12/11/85 */
14 #pragma ident "%Z%%M% %I% %E% SMI"
24 #include <sys/socket.h>
33 #define sigvec sigaction
34 #define sv_handler sa_handler
36 #include <netinet/in.h>
38 extern int32_t tp_bsize
;
43 static int rmtstate
= TS_CLOSED
;
44 static int rmtape
= -1;
45 static int rmtversion
= 0;
46 static char *rmtpeer
, *rmtpeer_malloc
;
47 static uint_t ntrec
; /* blocking factor on tape */
49 static char *domainname
= "hsm_libdump"; /* for dgettext() */
52 static void rmtmsg(const char *, ...); /* package print routine */
53 static void rmtconnaborted(int);
54 static void rmtgetconn(void);
55 static int rmtstatus_extended(struct mtget
*);
56 static int rmtioctl_extended(int, long);
57 static int map_extended_ioctl(int);
58 static int okname(char *);
59 static int rmtcall(char *, char *);
60 static int rmtreply(char *);
61 static int rmtpush(char *, uint_t
);
62 static void rmtgets(char *, int);
64 static void (*print
)(const char *, ...); /* print routine */
65 static void (*Exit
)(int); /* exit routine */
68 static void rmtconnaborted();
69 static void rmtgetconn();
71 static int rmtstatus_extended();
72 static int rmtioctl_extended();
73 static int map_extended_ioctl();
75 static int rmtreply();
77 static void rmtgets();
79 static void (*print
)();
80 static void (*Exit
)();
84 * Get a program-specific print and exit routine into
85 * the package. This is primarily for dump's benefit.
86 * This routine is optional -- if not called the two
87 * default to fprintf(stderr) and exit.
92 void (*errmsg
)(const char *, ...), /* print routine */
93 void (*errexit
)(int)) /* exit routine */
96 rmtinit(void (*errmsg
)(), void (*errexit
)())
104 rmthost(char *host
, uint_t blocksize
)
109 if (print
== (void (*)(const char *, ...))0)
111 if (print
== (void (*)())0)
115 if (Exit
== (void (*)(int))0)
117 if (Exit
== (void (*)())0)
120 if (rmtape
>= 0 && rmtstate
!= TS_OPEN
) {
121 (void) close(rmtape
);
125 (void) free(rmtpeer_malloc
);
126 rmtpeer
= rmtpeer_malloc
= strdup(host
);
127 if (rmtpeer
== (char *)0)
130 sv
.sa_flags
= SA_RESTART
;
131 (void) sigemptyset(&sv
.sa_mask
);
132 sv
.sv_handler
= rmtconnaborted
;
133 (void) sigvec(SIGPIPE
, &sv
, (struct sigvec
*)0);
142 rmtconnaborted(int sig
)
144 print(dgettext(domainname
, "Lost connection to remote host.\n"));
155 static struct servent
*sp
= 0;
156 static struct passwd
*pwd
= 0;
157 char *tuser
, *host
, *device
;
161 sp
= getservbyname("shell", "tcp");
163 print(dgettext(domainname
,
164 "shell/tcp: unknown service\n"));
167 pwd
= getpwuid(getuid());
169 print(dgettext(domainname
,
170 "Cannot find password entry for uid %d\n"),
175 /* Was strrchr(), be consistent with dump */
176 host
= strchr(rmtpeer
, '@');
185 tuser
= pwd
->pw_name
;
187 /* Was strrchr() - be consistent with dump and restore */
188 device
= strchr(host
, ':');
190 *device
= 0; /* throw away device name */
192 * myrcmd() replaces the contents of rmtpeer with a pointer
193 * to a static copy of the canonical host name. However,
194 * since we never refer to rmtpeer again (other than to
195 * overwrite it in the next rmthost() invocation), we don't
198 /* LINTED sp->s_port is an int, even though port numbers are 1..65535 */
199 rmtape
= myrcmd(&rmtpeer
, (ushort_t
)sp
->s_port
, pwd
->pw_name
,
203 print("%s", myrcmd_stderr
);
205 size
= ntrec
* tp_bsize
;
206 while (size
> tp_bsize
&&
207 setsockopt(rmtape
, SOL_SOCKET
, SO_SNDBUF
, (char *)&size
,
219 for (cp
= cp0
; *cp
; cp
++) {
221 if (!isascii(c
) || !(isalnum(c
) || c
== '_' || c
== '-')) {
222 print(dgettext(domainname
,
223 "invalid user name %s\n"), cp0
);
231 rmtopen(char *tape
, int mode
)
237 (void) snprintf(buf
, sizeof (buf
), "O%s\n%d\n", tape
, mode
);
239 fd
= rmtcall(tape
, buf
);
241 /* see if the rmt server supports the extended protocol */
242 rmtversion
= rmtioctl(-1, 0);
245 * Some rmt daemons apparently close the connection
246 * when they get a bogus ioctl. See 1210852 (ignore
247 * the evaluation). Make sure we can still talk to
248 * the device, re-opening it if necessary.
250 if (rmtversion
< 1) {
251 if (rmtstatus(&mt
) < 0) {
268 if (rmtstate
!= TS_OPEN
)
270 (void) rmtcall("close", "C\n");
271 rmtstate
= TS_CLOSED
;
275 rmtstatus(struct mtget
*mt
)
277 char *buf
= (char *)mt
;
281 return (rmtstatus_extended(mt
));
283 n
= rmtcall("status", "S");
287 if ((unsigned)n
> sizeof (*mt
)) {
288 print(dgettext(domainname
,
289 "rmtstatus: expected response size %d, got %d\n"),
290 sizeof (struct mtget
), n
);
291 print(dgettext(domainname
,
292 "This means the remote rmt daemon is not compatible.\n"));
297 cc
= read(rmtape
, buf
+i
, n
- i
);
306 rmtstatus_extended(struct mtget
*mt
)
308 if ((mt
->mt_type
= rmtcall("status", "sT")) == -1)
310 mt
->mt_dsreg
= rmtcall("status", "sD");
311 mt
->mt_erreg
= rmtcall("status", "sE");
312 mt
->mt_resid
= rmtcall("status", "sR");
313 mt
->mt_fileno
= rmtcall("status", "sF");
314 mt
->mt_blkno
= rmtcall("status", "sB");
315 mt
->mt_flags
= rmtcall("status", "sf");
316 mt
->mt_bf
= rmtcall("status", "sb");
321 rmtread(char *buf
, uint_t count
)
326 (void) snprintf(line
, sizeof (line
), "R%d\n", count
);
327 n
= rmtcall("read", line
);
332 print(dgettext(domainname
,
333 "rmtread: expected response size %d, got %d\n"),
335 print(dgettext(domainname
,
336 "This means the remote rmt daemon is not compatible.\n"));
341 cc
= read(rmtape
, buf
+i
, n
- i
);
350 rmtwrite(char *buf
, uint_t count
)
353 char line
[64]; /* numbers can get big */
355 (void) snprintf(line
, sizeof (line
), "W%d\n", count
);
356 retval
= rmtpush(line
, strlen(line
));
360 retval
= rmtpush(buf
, count
);
364 return (rmtreply("write"));
368 rmtpush(char *buf
, uint_t count
)
373 retval
= write(rmtape
, buf
, count
);
376 } while (count
&& retval
> 0);
382 rmtseek(int offset
, int pos
)
386 (void) snprintf(line
, sizeof (line
), "L%d\n%d\n", offset
, pos
);
387 return (rmtcall("seek", line
));
391 rmtioctl(int cmd
, long count
)
399 if ((xcmd
= map_extended_ioctl(cmd
)) != -1)
400 return (rmtioctl_extended(xcmd
, count
));
402 (void) snprintf(buf
, sizeof (buf
), "I%d\n%ld\n", cmd
, count
);
403 return (rmtcall("ioctl", buf
));
407 * Map from the standard Sun ioctl commands into the extended version,
411 map_extended_ioctl(int cmd
)
416 return (-1); /* extended protocol not supported */
432 xcmd
= -1; /* not supported */
439 rmtioctl_extended(int cmd
, long count
)
443 (void) snprintf(buf
, sizeof (buf
), "i%d\n%ld\n", cmd
, count
);
444 return (rmtcall("ioctl", buf
));
448 rmtcall(char *cmd
, char *buf
)
450 if (rmtpush(buf
, strlen(buf
)) != strlen(buf
))
452 return (rmtreply(cmd
));
458 char code
[30], emsg
[BUFSIZ
];
460 rmtgets(code
, sizeof (code
));
461 if (*code
== 'E' || *code
== 'F') {
462 rmtgets(emsg
, sizeof (emsg
));
464 * don't print error message for ioctl or status;
465 * or if we are opening up a full path (i.e. device)
466 * and the tape is not loaded (EIO error)
468 if (strcmp(cmd
, "ioctl") != 0 &&
469 strcmp(cmd
, "status") != 0 &&
470 !(cmd
[0] == '/' && atoi(code
+ 1) == EIO
))
471 print("%s: %s\n", cmd
, emsg
);
472 errno
= atoi(code
+ 1);
474 rmtstate
= TS_CLOSED
;
480 print(dgettext(domainname
,
481 "Protocol to remote tape server botched (code %s?).\n"),
485 return (atoi(code
+ 1));
489 rmtgets(char *cp
, int len
)
493 n
= recv(rmtape
, cp
, len
-1, MSG_PEEK
);
494 for (i
= 0; i
< n
; i
++)
497 n
= i
+ 1; /* characters to read at once */
498 for (i
= 0; i
< len
; i
+= n
, n
= 1) {
499 n
= read(rmtape
, cp
, n
);
503 if (cp
[-1] == '\n') {
508 print(dgettext(domainname
,
509 "Protocol to remote tape server botched (in rmtgets).\n"));
518 rmtmsg(const char *fmt
, ...)
523 (void) vfprintf(stderr
, fmt
, args
);
524 (void) fflush(stderr
);
537 fmt
= va_arg(args
, char *);
538 (void) vfprintf(stderr
, fmt
, args
);
539 (void) fflush(stderr
);