diff options
Diffstat (limited to 'usr/src/cmd/backup/lib')
| -rw-r--r-- | usr/src/cmd/backup/lib/Makefile | 121 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/byteorder.c | 298 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/getdate.y | 984 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/lint.sed | 6 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/memutils.c | 84 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/myrcmd.c | 288 | ||||
| -rw-r--r-- | usr/src/cmd/backup/lib/rmtlib.c | 563 |
7 files changed, 2344 insertions, 0 deletions
diff --git a/usr/src/cmd/backup/lib/Makefile b/usr/src/cmd/backup/lib/Makefile new file mode 100644 index 0000000000..4c1d3955d8 --- /dev/null +++ b/usr/src/cmd/backup/lib/Makefile @@ -0,0 +1,121 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/backup/lib/Makefile +# +LIBRARY= libdump.a + +# Has to be before include of Makefile.backup +# This should be POFILE=libdump.po, but that causes make to +# fall over due to some seriously weird interactions in the +# various indirectly-included makefiles. So, since this works +# and is otherwise harmless, we fake it. +PROG= libdump + +# Include library definitions, then backup definitions, as in general +# we want the flags and such from our tree. + +include ../../../lib/Makefile.lib +include ../Makefile.backup + +# Specifically request the construction of a static library. +# This library is not installed in the proto area. +LIBS= $(LIBRARY) + +HDRS= ../include/byteorder.h \ + ../include/memutils.h ../include/myrcmd.h \ + ../../../head/protocols/dumprestore.h \ + ../include/rmt.h + +YFILE= getdate.y +YSRC= getdate.c + +CLOBBERFILES= $(YSRC) $(GLIB) *.ln + +LOBJS= rmtlib.o myrcmd.o \ + $(YSRC:%.c=%.o) \ + byteorder.o memutils.o $(RPC_CLNT:%.c=%.o) $(RPC_XDR:%.c=%.o) + +OBJECTS= $(LOBJS) +POFILES= $(OBJECTS:.o=.po) +GENERAL= ../include +GLOBAL= ../../../head +CPPFLAGS= -I$(GENERAL) -I$(GLOBAL) $(CPPFLAGS.master) +LINTOUT= lint.out +CLEANFILES= $(OBJECTS) $(LINTOUT) $(LINTLIB) $(DEBUGS) *.ln \ + $(YSRC) $(LIBRARY) +LINTFLAGS += -y + +# support for -g library +GLIB= libdump_g.a +DEBUGS= $(OBJECTS:%=.debug/%) +$(GLIB):= AROBJS = $(DEBUGS) +$(GLIB):= DIR = .debug +$(GLIB):= CFLAGS= -g $(XESS) -DDEBUG -DYYDEBUG ${SBFLAGS} + +.KEEP_STATE: + +all: $(LIBS) + +debug: $(LIBS) $(GLIB) + +.debug: + -@mkdir -p $@ + +.debug/%.o: %.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(GLIB): .debug $$(DEBUGS) + $(BUILD.AR) + $(POST_PROCESS_A) + +$(OBJECTS): $(HDRS) + +install: all + +$(POFILE): $(POFILES) + $(RM) $@; cat $(POFILES) > $@ + +# rpcgen produces unused local variables that we can't easily suppress. +# It is also stupid about 32/64 bit integers. Since we don't support +# the RPC subsystem any more, just ignore complaints about it all. +# We have no control over yaccpar, and it has lots of 32/64 complaints. +# Assumes lint run with -s argument +lint: lint.out + sed -f lint.sed lint.out + +lint.out: $(LINTLIB) + +check: $(HDRS) + $(CSTYLE) $(CSTYLEFLAGS) `echo $(SRCS) | sed -e s/getdate.c//` $(HDRS) + $(HDRCHK) $(HDRCHKFLAGS) $(HDRS) + +# include library targets +include ../../../lib/Makefile.targ + +_msg: $(POFILE) diff --git a/usr/src/cmd/backup/lib/byteorder.c b/usr/src/cmd/backup/lib/byteorder.c new file mode 100644 index 0000000000..ef21cbfe55 --- /dev/null +++ b/usr/src/cmd/backup/lib/byteorder.c @@ -0,0 +1,298 @@ +/* + * Copyright 1996, 1998, 2002-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <locale.h> +#include <stdlib.h> +#include <sys/fs/ufs_inode.h> +#include <sys/fs/ufs_fsdir.h> +#include <sys/fs/ufs_acl.h> +#include <byteorder.h> + +struct byteorder_ctx * +byteorder_create(void) +{ + struct byteorder_ctx *rc; + + /* LINTED: assignment value is used */ + if ((rc = (struct byteorder_ctx *)calloc(1, sizeof (*rc))) == NULL) + return (NULL); + return (rc); +} + +void +byteorder_destroy(struct byteorder_ctx *ctx) +{ + if (ctx != NULL) + (void) free((char *)ctx); +} + +void +byteorder_banner(struct byteorder_ctx *ctx, FILE *filep) +{ + if ((! ctx->initialized) || (filep == NULL)) + return; + + if (ctx->Bcvt) + (void) fprintf(filep, gettext("Note: doing byte swapping\n")); +} + +/* + * Control string (cp) is a sequence of optional numeric repeat counts + * and format specifiers. s/w/h indicate a 16-bit quantity is to be + * byte-swapped, l indicates a 32-bit quantity. A repeat count is + * identical in effect to having the following format character appear + * N times (e.g., "3h" is equivalent to "hhh"). + * + * The byte-swapping is performed in-place, in the buffer sp. + */ +void +swabst(char *cp, uchar_t *sp) +{ + int n = 0; + uchar_t c; + + while (*cp) { + switch (*cp) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = (n * 10) + (*cp++ - '0'); + continue; + + case 's': case 'w': case 'h': + /* LINTED: type punning ok here */ + c = sp[0]; sp[0] = sp[1]; sp[1] = c; + sp++; + break; + + case 'l': + c = sp[0]; sp[0] = sp[3]; sp[3] = c; + c = sp[2]; sp[2] = sp[1]; sp[1] = c; + sp += 3; + } + /* Any other character, like 'b' counts as byte. */ + sp++; + if (n <= 1) { + n = 0; cp++; + } else + n--; + } +} + +uint32_t +swabl(uint32_t x) +{ + uint32_t l = x; + + swabst("l", (uchar_t *)&l); + /* LINTED: type punning ok here */ + return (l); +} + +static int +checksum(struct byteorder_ctx *ctx, int *b, int size) +{ + uint_t i, j; + + if (! ctx->initialized) + return (-1); + + /* + * We should only be called on to checksum u_spcl's, so make + * sure that's what we got. + */ + if ((unsigned)size < tp_bsize) + return (-1); + + j = tp_bsize / sizeof (int); + i = 0; + if (!ctx->Bcvt) { + do + i += (uint_t)*b++; + while (--j); + } else { + /* + * What happens if we want to read restore tapes + * for a 16bit int machine??? + */ + do + i += swabl(*b++); + while (--j); + } + + return (i != CHECKSUM); +} + +/* + * normspcl() checks that a spclrec is valid. it does byte/quad + * swapping if necessary, and checks the checksum. it does NOT convert + * from the old filesystem format; gethead() in tape.c does that. + * + * ctx is the context for this package + * sp is a pointer to a current-format spclrec, that may need to be + * byteswapped. + * cs is a pointer to the thing we want to checksum. if we're + * converting from the old filesystem format, it might be different + * from sp. + * css is the size of the thing we want to checksum. + * magic is the magic number we compare against. + */ + +int +normspcl(struct byteorder_ctx *ctx, struct s_spcl *sp, int *cs, + int css, int magic) +{ + u_offset_t sv; + + if ((! ctx->initialized) && (sp->c_magic != magic)) { + if (swabl(sp->c_magic) != (uint32_t)magic) + return (-1); + ctx->Bcvt = 1; + } + ctx->initialized = 1; + + if (checksum(ctx, cs, css)) + return (-1); + + /* + * Unless our caller is actively trying to break us, a + * successful checksum() means that *sp is at least as + * big as what we think it should be as far as byte + * swapping goes. Therefore, we don't need to do any + * more size checks here. + */ + + /* handle byte swapping */ + if (ctx->Bcvt) { + /* + * byteswap + * c_type, c_date, c_ddate, c_volume, c_tapea, c_inumber, + * c_magic, c_checksum, + * all of c_dinode, and c_count. + */ + + swabst("8l4s31l", (uchar_t *)sp); + + /* + * byteswap + * c_flags, c_firstrec, and c_spare. + */ + + swabst("34l", (uchar_t *)&(sp->c_flags)); + + /* byteswap the inodes if necessary. */ + +#ifndef lint /* lint won't shut up about sprintf below */ + if (sp->c_flags & DR_INODEINFO) { + char buffy[BUFSIZ]; + /* Can't overflow, max len is %d format (20)+`l'+\0 */ + /* LINTED lint can't tell diff between %ld and %dl */ + (void) sprintf(buffy, "%dl", TP_NINOS); + swabst(buffy, (uchar_t *)sp->c_data.s_inos); + } +#endif /* lint */ + + /* if no metadata, byteswap the level */ + + if (! (sp->c_flags & DR_HASMETA)) + swabst("1l", (uchar_t *)&(sp->c_level)); + } + + /* handle quad swapping (note -- we no longer perform this check */ + /* we now do quad swapping iff we're doing byte swapping.) */ + + /* + * the following code is being changed during the large file + * project. This code needed to be changed because ic_size + * is no longer a quad, it has been changed to ic_lsize, which is + * an offset_t, and the field "val" doesn't exist anymore. + */ + +/* + * This is the old code. (before large file project.) + * + * sv = sp->c_dinode.di_ic.ic_size.val; + * + * if (ctx->Bcvt) { + * long foo; + * + * foo = sv[1]; + * sv[1] = sv[0]; + * sv[0] = foo; + * } + */ + + /* swap the upper 32 bits of ic_lsize with the lower 32 bits */ + + if (ctx->Bcvt) { + sv = sp->c_dinode.di_ic.ic_lsize; + sv = (sv << 32) | (sv >> 32); + sp->c_dinode.di_ic.ic_lsize = sv; + } + + if (sp->c_magic != magic) + return (-1); + return (0); +} + +void +normdirect(ctx, d) + struct byteorder_ctx *ctx; + struct direct *d; +{ + assert(ctx->initialized); + + if (ctx->Bcvt) + swabst("l2s", (uchar_t *)d); +} + +void +normacls(struct byteorder_ctx *ctx, ufs_acl_t *acl, int n) +{ + static int complained = 0; + int i; + uid32_t uid; + + assert(ctx->initialized); + + if (! ctx->Bcvt) + return; + + for (i = 0; i < n; i++) { + swabst("1s", (uchar_t *)&(acl[i].acl_tag)); /* u_short */ + swabst("1s", (uchar_t *)&(acl[i].acl_perm)); /* o_mode_t */ + + /* LINTED explicitly checking for truncation below */ + uid = (uid32_t)(acl[i].acl_who); + if (!complained && ((uid_t)uid) != acl[i].acl_who) { + /* + * The problem is that acl_who is a uid_t, + * and we know that the on-tape version is + * definitely 32 bits. To avoid getting + * burned if/when uid_t becomes bigger + * than that, we need to do the explicit + * conversion and check. + */ + (void) fprintf(stderr, + "Some ACL uids have been truncated\n"); + complained = 1; + } + swabst("1l", (uchar_t *)&(uid)); /* uid32_t */ + } +} diff --git a/usr/src/cmd/backup/lib/getdate.y b/usr/src/cmd/backup/lib/getdate.y new file mode 100644 index 0000000000..187739bdc7 --- /dev/null +++ b/usr/src/cmd/backup/lib/getdate.y @@ -0,0 +1,984 @@ +%{ +/* + * Copyright (c) 1998 by Sun Microsystems, Inc. + * All rights reserved. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* $OrigRevision: 2.1 $ +** +** Originally written by Steven M. Bellovin <smb@research.att.com> while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990; +** send any email to Rich. +** +** This grammar has eight shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ +#include <stdio.h> +#include <ctype.h> + +#include <sys/types.h> +#define NEED_TZSET +struct timeb { + time_t time; /* Seconds since the epoch */ + unsigned short millitm; /* Field not used */ + short timezone; + short dstflag; /* Field not used */ +}; +#include <time.h> + +#include <locale.h> +#include <string.h> +#include <stdlib.h> +#include <note.h> +#include <libintl.h> + +#if !defined(lint) && !defined(SABER) +static char RCS[] = + "$Header: /home/laramie/berliner/ws/backup/usr/src/cmd/backup/lib/getdate.y,v 1.5 1992/06/09 21:46:21 sam Exp $"; +#endif /* !defined(lint) && !defined(SABER) */ + + +#define EPOCH 1970 +#define HOURN(x) (x * 60) +#define SECSPERDAY (24L * 60L * 60L) + +#define CHECK_TM(y) (((y) % 100) < 70 ? (y) + 2000 : (y) + 1900) + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +static char *domainname = "hsm_libdump"; /* for dgettext() */ + +#define yylex 1 /* suppress yacc's definition */ +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT +%token tSEC_UNIT tSNUMBER tUNUMBER tZONE + +%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT +%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE +%type <Meridian> tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; + } + | zone { + yyHaveZone++; + } + | date { + yyHaveDate++; + } + | day { + yyHaveDay++; + } + | rel { + yyHaveRel++; + } + | number + ; + +time : tUNUMBER tMERIDIAN { + yyHour = $1; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($4 % 100 + ($4 / 100) * 60); + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($6 % 100 + ($6 / 100) * 60); + } + ; + +zone : tZONE { + yyTimezone = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + yyTimezone = $1; + yyDSTmode = DSTon; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + yyMonth = $2; + yyDay = $1; + } + | tUNUMBER tMONTH tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; + } + ; + +rel : relunit tAGO { + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } + | relunit + ; + +relunit : tUNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tSNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tMINUTE_UNIT { + yyRelSeconds += $1 * 60L; + } + | tSNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tSEC_UNIT { + yyRelSeconds++; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tMONTH_UNIT { + yyRelMonth += $1; + } + ; + +number : tUNUMBER { + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = $1; + else { + yyHaveTime++; + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + ; + +o_merid : /* NULL */ { + $$ = MER24; + } + | tMERIDIAN { + $$ = $1; + } + ; + +%% + +/* Month and day table. */ +static TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +static TABLE TimezoneTable[] = { + { "gmt", tZONE, HOURN( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOURN( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOURN( 0) }, + { "wet", tZONE, HOURN( 0) }, /* Western European */ + { "bst", tDAYZONE, HOURN( 0) }, /* British Summer */ + { "wat", tZONE, HOURN( 1) }, /* West Africa */ + { "at", tZONE, HOURN( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOURN( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOURN( 3) }, /* Greenland Standard */ +#endif + { "nft", tZONE, HOURN(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOURN(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOURN(3.5) }, /* Newfoundland Daylight */ + { "ast", tZONE, HOURN( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOURN( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOURN( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOURN( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOURN( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOURN( 6) }, /* Central Daylight */ + { "mst", tZONE, HOURN( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOURN( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOURN( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOURN( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOURN( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOURN( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOURN(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOURN(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOURN(10) }, /* Central Alaska */ + { "ahst", tZONE, HOURN(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOURN(11) }, /* Nome */ + { "idlw", tZONE, HOURN(12) }, /* International Date Line West */ + { "cet", tZONE, -HOURN(1) }, /* Central European */ + { "met", tZONE, -HOURN(1) }, /* Middle European */ + { "mewt", tZONE, -HOURN(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOURN(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOURN(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOURN(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOURN(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOURN(1) }, /* French Summer */ + { "eet", tZONE, -HOURN(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOURN(3) }, /* Baghdad, USSR Zone 2 */ + { "it", tZONE, -HOURN(3.5) },/* Iran */ + { "zp4", tZONE, -HOURN(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOURN(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -HOURN(5.5) },/* Indian Standard */ + { "zp6", tZONE, -HOURN(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, nad SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOURN(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOURN(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOURN(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOURN(7) }, /* West Australian Daylight */ + { "jt", tZONE, -HOURN(7.5) },/* Java (3pm in Cronusland!) */ + { "cct", tZONE, -HOURN(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOURN(9) }, /* Japan Standard, USSR Zone 8 */ + { "cast", tZONE, -HOURN(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOURN(9.5) },/* Central Australian Daylight */ + { "east", tZONE, -HOURN(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOURN(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOURN(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOURN(12) }, /* New Zealand */ + { "nzst", tZONE, -HOURN(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOURN(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOURN(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE MilitaryTable[] = { + { "a", tZONE, HOURN( 1) }, + { "b", tZONE, HOURN( 2) }, + { "c", tZONE, HOURN( 3) }, + { "d", tZONE, HOURN( 4) }, + { "e", tZONE, HOURN( 5) }, + { "f", tZONE, HOURN( 6) }, + { "g", tZONE, HOURN( 7) }, + { "h", tZONE, HOURN( 8) }, + { "i", tZONE, HOURN( 9) }, + { "k", tZONE, HOURN( 10) }, + { "l", tZONE, HOURN( 11) }, + { "m", tZONE, HOURN( 12) }, + { "n", tZONE, HOURN(- 1) }, + { "o", tZONE, HOURN(- 2) }, + { "p", tZONE, HOURN(- 3) }, + { "q", tZONE, HOURN(- 4) }, + { "r", tZONE, HOURN(- 5) }, + { "s", tZONE, HOURN(- 6) }, + { "t", tZONE, HOURN(- 7) }, + { "u", tZONE, HOURN(- 8) }, + { "v", tZONE, HOURN(- 9) }, + { "w", tZONE, HOURN(-10) }, + { "x", tZONE, HOURN(-11) }, + { "y", tZONE, HOURN(-12) }, + { "z", tZONE, HOURN( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +static void +yyerror(s) + char *s; +{ +} + + +static time_t +ToSeconds(Hours, Minutes, Seconds, Meridian) + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours != 12) + return (Hours * 60L + Minutes) * 60L + Seconds; + else + return Minutes * 60L + Seconds; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours != 12) + return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + else + return (720L + Minutes) * 60L + Seconds; + } + /* NOTREACHED */ +} + + +static time_t +Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) + time_t Month; + time_t Day; + time_t Year; + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; + DSTMODE DSTmode; +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + time_t i; + + if (Year < 0) + Year = -Year; + if (Year < 138) + Year += 1900; + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + if (Year < EPOCH || Year > 2037 + || Month < 1 || Month > 12 + /* LINTED Month is a time_t so intermediate results aren't truncated */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + for (Julian = Day - 1, i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(Start, Future) + time_t Start; + time_t Future; +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(Start, DayOrdinal, DayNumber) + time_t Start; + time_t DayOrdinal; + time_t DayNumber; +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(Start, RelMonth) + time_t Start; + time_t RelMonth; +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(buff) + char *buff; +{ + char *p; + char *q; + TABLE *tp; + uint_t i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper((u_char)*p)) + *p = tolower(*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha((u_char)*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + +void +pdateerr(p) + char *p; +{ + char *name = "DATEMSK"; /* env variable for date format */ + char *value; + char fmt[256], line[256]; + FILE *fp; + time_t now; + struct tm *tm; + + value = getenv(name); + if (value == (char *)0) { + fprintf(stderr, + dgettext(domainname, "%s: Environment variable %s not set\n"), + p, name); + return; + } + switch (getdate_err) { + case 0: + default: + fprintf(stderr, + dgettext(domainname, "%s: Unkown getdate() error\n"), p); + break; + case 1: + fprintf(stderr, + dgettext(domainname, "%s: %s null or undefined\n"), p, name); + break; + case 2: + fprintf(stderr, dgettext(domainname, + "%s: Cannot read template file %s\n"), p, value); + break; + case 3: + fprintf(stderr, dgettext(domainname, + "%s: Failed to get file status information\n"), p); + break; + case 4: + fprintf(stderr, dgettext(domainname, + "%s: Template file %s not a regular file\n"), p, value); + break; + case 5: + fprintf(stderr, dgettext(domainname, + "%s: Error reading template file %s\n"), p, value); + break; + case 6: + fprintf(stderr, dgettext(domainname, + "%s: %s failed\n"), p, "malloc()"); + break; + case 7: + fprintf(stderr, dgettext(domainname, + "%s: Bad date/time format\n"), p); + fp = fopen(value, "r"); + if (fp == (FILE *)0) + break; + now = time((time_t *)0); + tm = localtime(&now); + fprintf(stderr, dgettext(domainname, + "The following are examples of valid formats:\n")); + while (fgets(fmt, sizeof (fmt), fp)) { + if (strchr(fmt, '%') == (char *)0) + continue; + fprintf(stderr, " "); + (void) strftime(line, sizeof (line), fmt, tm); + fprintf(stderr, "%s", line); + } + (void) fclose(fp); + break; + case 8: + (void) fprintf(stderr, dgettext(domainname, + "%s: Invalid date specification\n"), p); + break; + } +} + +#undef yylex +static int +yylex() +{ + char c; + char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace((u_char)*yyInput)) + yyInput++; + + if (isdigit((u_char)(c = *yyInput)) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit((u_char)*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + yylval.Number = 0; + while (isdigit((u_char)(c = *yyInput++))) { + int n; + char digit = c; + (void) sscanf(&digit, "%1d", &n); + yylval.Number = 10 * yylval.Number + n; + } + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha((u_char)c)) { + for (p = buff; isalpha((u_char)(c = *yyInput++)) || c == '.'; ) + if (p < &buff[sizeof (buff) - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + + +time_t +getreldate(p, now) + char *p; + struct timeb *now; +{ + struct tm *tm; + struct timeb ftz; + time_t Start; + time_t tod; + + if (strcmp(setlocale(LC_TIME, NULL), "C")) { + static char localedate[24]; + struct tm ltm; + + tm = getdate(p); + if (getdate_err == 1 /* NODATEMASK */) { + char buffy[BUFSIZ]; + time_t current; + + printf(gettext("environment variable %s not set\n"), "DATEMSK"); + do { + time(¤t); + tm = localtime(¤t); + memcpy(<m, tm, sizeof(ltm)); + tm = <m; + + (void) fputs(gettext("Enter date as mmddhhmm[yy]: "), stdout); + (void) fflush(stdout); + if (fgets(buffy, sizeof (buffy), stdin) == NULL) { + (void) printf(gettext("Encountered EOF on stdin\n")); + return(-1); + } + } while (sscanf(buffy, "%2d%2d%2d%2d%2d", + &(tm->tm_mon), &(tm->tm_mday), &(tm->tm_hour), + &(tm->tm_min), &(tm->tm_year)) < 4); + + (tm->tm_mon)--; + } else if (tm == NULL) + return(-1); + + (void)sprintf(localedate, "%d:%2.2d %d/%d %d", + tm->tm_hour, tm->tm_min, tm->tm_mon + 1, + tm->tm_mday, CHECK_TM(tm->tm_year)); + p = localedate; + } + + yyInput = p; + if (now == NULL) { + now = &ftz; + (void) time(&ftz.time); + /* Set the timezone global. */ + tzset(); + /* LINTED timezone is time_t so intermediate results aren't truncated */ + ftz.timezone = (int) timezone / 60; + } + + tm = localtime(&now->time); + yyYear = tm->tm_year; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = now->timezone; + yyDSTmode = DSTmaybe; + yyHour = tm->tm_hour; + yyMinutes = tm->tm_min; + yySeconds = tm->tm_sec; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L) + tm->tm_min * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + +#if defined(TEST) + +/* ARGSUSED */ +main(ac, av) + int ac; + char *av[]; +{ + char buff[128]; + time_t d; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + + (void) printf(gettext("Enter date, or blank line to exit.\n\t> ")); + (void) fflush(stdout); + while (gets(buff) && buff[0]) { + d = getreldate(buff, (struct timeb *)NULL); + if (d == -1) + (void) printf(gettext("Bad format - couldn't convert.\n")); + else { + (void) cftime(buff, "%c\n", &d); + (void) printf("%s", buff); + } + (void) printf("\t> "); + (void) fflush(stdout); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/usr/src/cmd/backup/lib/lint.sed b/usr/src/cmd/backup/lib/lint.sed new file mode 100644 index 0000000000..dfd06505f6 --- /dev/null +++ b/usr/src/cmd/backup/lib/lint.sed @@ -0,0 +1,6 @@ +/^"operator_xdr.c.*variable unused in function/d +/yaccpar/d +/getdate.y.*include file.*unnecessary/d +/different definitions.*CLK_TCK/d +/lint suppression directive not used/d +/no corresponding .h file/d diff --git a/usr/src/cmd/backup/lib/memutils.c b/usr/src/cmd/backup/lib/memutils.c new file mode 100644 index 0000000000..e46c33430b --- /dev/null +++ b/usr/src/cmd/backup/lib/memutils.c @@ -0,0 +1,84 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <errno.h> +#include <libintl.h> +#include <string.h> +#include "memutils.h" + +extern void msg(const char *, ...); +extern void dumpabort(void); + +void * +xmalloc(bytes) + size_t bytes; +{ + void *cp; + + cp = malloc(bytes); + if (cp == NULL) { + int saverr = errno; + msg(gettext("Cannot allocate memory: %s\n"), strerror(saverr)); + dumpabort(); + } + return (cp); +} + +void * +xcalloc(nelem, size) + size_t nelem; + size_t size; +{ + void *cp; + + cp = calloc(nelem, size); + if (cp == NULL) { + int saverr = errno; + msg(gettext("Cannot allocate memory: %s\n"), strerror(saverr)); + dumpabort(); + } + return (cp); +} + +void * +xrealloc(allocated, newsize) + void *allocated; + size_t newsize; +{ + void *cp; + + /* LINTED realloc knows what to do with a NULL pointer */ + cp = realloc(allocated, newsize); + if (cp == NULL) { + int saverr = errno; + msg(gettext("Cannot allocate memory: %s\n"), strerror(saverr)); + dumpabort(); + } + return (cp); +} diff --git a/usr/src/cmd/backup/lib/myrcmd.c b/usr/src/cmd/backup/lib/myrcmd.c new file mode 100644 index 0000000000..a2a77c6e5b --- /dev/null +++ b/usr/src/cmd/backup/lib/myrcmd.c @@ -0,0 +1,288 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Portions of this source code were derived from Berkeley 4.3 BSD + * under license from the Regents of the University of California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <myrcmd.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <pwd.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/file.h> +#include <signal.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <netdb.h> +#include <fcntl.h> +#include <libintl.h> + +#include <memutils.h> + +#define index(s, c) strchr(s, c) +char *strchr(); + +char *inet_ntoa(); + +char myrcmd_stderr[1024]; + +int +myrcmd(char **ahost, unsigned short rport, char *locuser, char *remuser, + char *cmd) +{ + uint_t loclen, remlen, cmdlen; + int s, timo, retval; + int tries = 0; + pid_t pid; + struct sockaddr_in sin; + char c; + int lport; + int saverr; + struct hostent *hp; + sigset_t oldmask; + sigset_t newmask; + struct sigaction oldaction; + struct sigaction newaction; + static struct hostent numhp; + static char numhostname[32]; /* big enough for "255.255.255.255" */ + struct in_addr numaddr; + struct in_addr *numaddrlist[2]; + + myrcmd_stderr[0] = '\0'; /* empty error string */ + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == 0) { + char *straddr; + + bzero((char *)numaddrlist, sizeof (numaddrlist)); + if ((numaddr.s_addr = inet_addr(*ahost)) == (in_addr_t)-1) { + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + gettext("%s: unknown host\n"), *ahost); + return (MYRCMD_NOHOST); + } else { + bzero((char *)&numhp, sizeof (numhp)); + bzero(numhostname, sizeof (numhostname)); + + if ((straddr = inet_ntoa(numaddr)) == (char *)0) { + (void) snprintf(myrcmd_stderr, + sizeof (myrcmd_stderr), + gettext("%s: unknown host\n"), *ahost); + return (MYRCMD_NOHOST); + } + (void) strncpy(numhostname, straddr, + sizeof (numhostname)); + numhostname[sizeof (numhostname) - 1] = '\0'; + numhp.h_name = numhostname; + numhp.h_addrtype = AF_INET; + numhp.h_length = sizeof (numaddr); + numaddrlist[0] = &numaddr; + numaddrlist[1] = NULL; + numhp.h_addr_list = (char **)numaddrlist; + hp = &numhp; + } + } + *ahost = hp->h_name; + + /* This provides a bounds-test for the bcopy()s below. */ + if ((unsigned)(hp->h_length) > sizeof (sin.sin_addr)) { + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + gettext("rcmd: address size: %d larger than limit %d\n"), + hp->h_length, sizeof (sin.sin_addr)); + return (MYRCMD_EBAD); + } + + /* ignore SIGPIPE */ + bzero((char *)&newaction, sizeof (newaction)); + newaction.sa_handler = SIG_IGN; + newaction.sa_flags = SA_ONSTACK; + (void) sigaction(SIGPIPE, &newaction, &oldaction); + + /* block SIGURG */ + bzero((char *)&newmask, sizeof (newmask)); + (void) sigaddset(&newmask, SIGURG); + (void) sigprocmask(SIG_BLOCK, &newmask, &oldmask); +again: + timo = 1; + /* + * Use 0 as lport means that rresvport() will bind to a port in + * the anonymous priviledged port range. + */ + lport = 0; + for (;;) { + s = rresvport(&lport); + if (s < 0) { + int err; + + if (errno == EAGAIN) { + (void) snprintf(myrcmd_stderr, + sizeof (myrcmd_stderr), + gettext("socket: All ports in use\n")); + err = MYRCMD_ENOPORT; + } else { + saverr = errno; + (void) snprintf(myrcmd_stderr, + sizeof (myrcmd_stderr), + gettext("rcmd: socket: %s\n"), + strerror(saverr)); + err = MYRCMD_ENOSOCK; + } + /* restore original SIGPIPE handler */ + (void) sigaction(SIGPIPE, &oldaction, + (struct sigaction *)0); + + /* restore original signal mask */ + (void) sigprocmask(SIG_SETMASK, &oldmask, + (sigset_t *)0); + return (err); + } + /* Can't fail, according to fcntl(2) */ + (void) fcntl(s, F_SETOWN, pid); + sin.sin_family = hp->h_addrtype; + bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); + sin.sin_port = rport; + if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) + break; + saverr = errno; + (void) close(s); + if (saverr == EADDRINUSE) { + continue; + } + if (saverr == ECONNREFUSED && timo <= 16) { + sleep(timo); + timo *= 2; + continue; + } + if (hp->h_addr_list[1] != NULL) { + saverr = errno; + + fprintf(stderr, + gettext("connect to address %s: "), + inet_ntoa(sin.sin_addr)); + errno = saverr; + perror(0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, + hp->h_length); + fprintf(stderr, gettext("Trying %s...\n"), + inet_ntoa(sin.sin_addr)); + continue; + } + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + "%s: %s\n", hp->h_name, strerror(saverr)); + /* restore original SIGPIPE handler */ + (void) sigaction(SIGPIPE, &oldaction, + (struct sigaction *)0); + + /* restore original signal mask */ + (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); + return (MYRCMD_ENOCONNECT); + } + if (write(s, "", 1) < 0) { + (void) close(s); + return (MYRCMD_ENOCONNECT); + } + + loclen = strlen(locuser) + 1; + remlen = strlen(remuser) + 1; + cmdlen = strlen(cmd) + 1; + + if (((retval = write(s, locuser, loclen)) != loclen) || + ((retval = write(s, remuser, remlen)) != remlen) || + ((retval = write(s, cmd, cmdlen)) != cmdlen)) { + if (retval == -1) + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + "write: %s\n", strerror(errno)); + else + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + gettext("write unexpectedly truncated\n")); + goto bad; + } + retval = read(s, &c, 1); + if (retval != 1) { + if (retval == 0) { + /* + * Solaris 2.0 bug alert. Sometimes, if the + * tapehost is a Solaris 2.0 system, the connection + * will be dropped at this point. Let's try again, + * three times, before we throw in the towel. + */ + if (++tries < 3) { + (void) close(s); + goto again; + } + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + gettext("Protocol error, %s closed connection\n"), + *ahost); + } else if (retval < 0) { + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + "%s: %s\n", *ahost, strerror(errno)); + } else { + (void) snprintf(myrcmd_stderr, sizeof (myrcmd_stderr), + gettext("Protocol error, %s sent %d bytes\n"), + *ahost, retval); + } + goto bad; + } + if (c != 0) { + char *cp = myrcmd_stderr; + char *ecp = &myrcmd_stderr[sizeof (myrcmd_stderr) - 1]; + + while (read(s, &c, 1) == 1) { + *cp++ = c; + if (c == '\n' || cp >= ecp) + break; + } + *cp = '\0'; + goto bad; + } + /* restore original SIGPIPE handler */ + (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); + + /* restore original signal mask */ + (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); + return (s); +bad: + (void) close(s); + /* restore original SIGPIPE handler */ + (void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0); + + /* restore original signal mask */ + (void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0); + return (MYRCMD_EBAD); +} diff --git a/usr/src/cmd/backup/lib/rmtlib.c b/usr/src/cmd/backup/lib/rmtlib.c new file mode 100644 index 0000000000..2f63049f87 --- /dev/null +++ b/usr/src/cmd/backup/lib/rmtlib.c @@ -0,0 +1,563 @@ +/*LINTLIBRARY*/ +/*PROTOLIB1*/ +/* + * Copyright 1998, 2002-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +/* line below is from UCB 5.4 12/11/85 */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <myrcmd.h> +#include <stdio.h> +#include <locale.h> +#include <ctype.h> +#include <pwd.h> +#include <string.h> +#include <signal.h> +#include <sys/mtio.h> +#include <sys/socket.h> +#include <unistd.h> +#include <netdb.h> +#include <locale.h> +#include <stdlib.h> +#include <errno.h> +#include <rmt.h> +#include <libintl.h> + +#define sigvec sigaction +#define sv_handler sa_handler + +#include <netinet/in.h> + +extern int32_t tp_bsize; + +#define TS_CLOSED 0 +#define TS_OPEN 1 + +static int rmtstate = TS_CLOSED; +static int rmtape = -1; +static int rmtversion = 0; +static char *rmtpeer, *rmtpeer_malloc; +static uint_t ntrec; /* blocking factor on tape */ + +static char *domainname = "hsm_libdump"; /* for dgettext() */ + +#ifdef __STDC__ +static void rmtmsg(const char *, ...); /* package print routine */ +static void rmtconnaborted(int); +static void rmtgetconn(void); +static int rmtstatus_extended(struct mtget *); +static int rmtioctl_extended(int, long); +static int map_extended_ioctl(int); +static int okname(char *); +static int rmtcall(char *, char *); +static int rmtreply(char *); +static int rmtpush(char *, uint_t); +static void rmtgets(char *, int); + +static void (*print)(const char *, ...); /* print routine */ +static void (*Exit)(int); /* exit routine */ +#else +static void rmtmsg(); +static void rmtconnaborted(); +static void rmtgetconn(); +static int okname(); +static int rmtstatus_extended(); +static int rmtioctl_extended(); +static int map_extended_ioctl(); +static int rmtcall(); +static int rmtreply(); +static int rmtpush(); +static void rmtgets(); + +static void (*print)(); +static void (*Exit)(); +#endif + +/* + * Get a program-specific print and exit routine into + * the package. This is primarily for dump's benefit. + * This routine is optional -- if not called the two + * default to fprintf(stderr) and exit. + */ +#ifdef __STDC__ +void +rmtinit( + void (*errmsg)(const char *, ...), /* print routine */ + void (*errexit)(int)) /* exit routine */ +#else +void +rmtinit(errmsg, errexit) + void (*errmsg)(); /* print routine */ + void (*errexit)(); /* exit routine */ +#endif +{ + print = errmsg; + Exit = errexit; +} + +rmthost(host, blocksize) + char *host; + uint_t blocksize; /* in Kbytes per tape block */ +{ + struct sigvec sv; + +#ifdef __STDC__ + if (print == (void (*)(const char *, ...))0) +#else + if (print == (void (*)())0) +#endif + print = rmtmsg; +#ifdef __STDC__ + if (Exit == (void (*)(int))0) +#else + if (Exit == (void (*)())0) +#endif + Exit = exit; + if (rmtape >= 0 && rmtstate != TS_OPEN) { + (void) close(rmtape); + rmtape = -1; + } + if (rmtpeer_malloc) + (void) free(rmtpeer_malloc); + rmtpeer = rmtpeer_malloc = strdup(host); + if (rmtpeer == (char *)0) + return (0); + ntrec = blocksize; + sv.sa_flags = SA_RESTART; + (void) sigemptyset(&sv.sa_mask); + sv.sv_handler = rmtconnaborted; + (void) sigvec(SIGPIPE, &sv, (struct sigvec *)0); + rmtgetconn(); + if (rmtape < 0) + return (0); + return (1); +} + +/*ARGSUSED*/ +static void +rmtconnaborted(sig) + int sig; +{ + print(dgettext(domainname, "Lost connection to remote host.\n")); + Exit(1); +} + +static void +#ifdef __STDC__ +rmtgetconn(void) +#else +rmtgetconn() +#endif +{ + static struct servent *sp = 0; + static struct passwd *pwd = 0; + char *tuser, *host, *device; + uint_t size; + + if (sp == 0) { + sp = getservbyname("shell", "tcp"); + if (sp == 0) { + print(dgettext(domainname, + "shell/tcp: unknown service\n")); + Exit(1); + } + pwd = getpwuid(getuid()); + if (pwd == 0) { + print(dgettext(domainname, + "Cannot find password entry for uid %d\n"), + getuid()); + Exit(1); + } + } + /* Was strrchr(), be consistent with dump */ + host = strchr(rmtpeer, '@'); + if (host) { + tuser = rmtpeer; + *host++ = 0; + rmtpeer = host; + if (!okname(tuser)) + Exit(1); + } else { + host = rmtpeer; + tuser = pwd->pw_name; + } + /* Was strrchr() - be consistent with dump and restore */ + device = strchr(host, ':'); + if (device) + *device = 0; /* throw away device name */ + /* + * myrcmd() replaces the contents of rmtpeer with a pointer + * to a static copy of the canonical host name. However, + * since we never refer to rmtpeer again (other than to + * overwrite it in the next rmthost() invocation), we don't + * really care. + */ + /* LINTED sp->s_port is an int, even though port numbers are 1..65535 */ + rmtape = myrcmd(&rmtpeer, (ushort_t)sp->s_port, pwd->pw_name, + tuser, "/etc/rmt"); + if (rmtape < 0) { + if (*myrcmd_stderr) + print("%s", myrcmd_stderr); + } else { + size = ntrec * tp_bsize; + while (size > tp_bsize && + setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, (char *)&size, + sizeof (size)) < 0) + size -= tp_bsize; + } +} + +static int +okname(cp0) + char *cp0; +{ + char *cp; + uchar_t c; + + for (cp = cp0; *cp; cp++) { + c = (uchar_t)*cp; + if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) { + print(dgettext(domainname, + "invalid user name %s\n"), cp0); + return (0); + } + } + return (1); +} + +rmtopen(tape, mode) + char *tape; + int mode; +{ + struct mtget mt; + char buf[256]; + int fd; + + (void) snprintf(buf, sizeof (buf), "O%s\n%d\n", tape, mode); + rmtstate = TS_OPEN; + fd = rmtcall(tape, buf); + if (fd != -1) { + /* see if the rmt server supports the extended protocol */ + rmtversion = rmtioctl(-1, 0); + + /* + * Some rmt daemons apparently close the connection + * when they get a bogus ioctl. See 1210852 (ignore + * the evaluation). Make sure we can still talk to + * the device, re-opening it if necessary. + */ + if (rmtversion < 1) { + if (rmtstatus(&mt) < 0) { + rmtclose(); + rmtgetconn(); + rmtversion = 0; + } + } + } + return (fd); +} + +void +#ifdef __STDC__ +rmtclose(void) +#else +rmtclose() +#endif +{ + if (rmtstate != TS_OPEN) + return; + (void) rmtcall("close", "C\n"); + rmtstate = TS_CLOSED; +} + +rmtstatus(mt) + struct mtget *mt; +{ + char *buf = (char *)mt; + int n, i, cc; + + if (rmtversion > 0) + return (rmtstatus_extended(mt)); + + n = rmtcall("status", "S"); + if (n < 0) { + return (-1); + } + if ((unsigned)n > sizeof (*mt)) { + print(dgettext(domainname, + "rmtstatus: expected response size %d, got %d\n"), + sizeof (struct mtget), n); + print(dgettext(domainname, + "This means the remote rmt daemon is not compatible.\n")); + rmtconnaborted(0); + } + i = 0; + while (i < n) { + cc = read(rmtape, buf+i, n - i); + if (cc <= 0) + rmtconnaborted(0); + i += cc; + } + return (n); +} + +static int +rmtstatus_extended(mt) + struct mtget *mt; +{ + if ((mt->mt_type = rmtcall("status", "sT")) == -1) + return (-1); + mt->mt_dsreg = rmtcall("status", "sD"); + mt->mt_erreg = rmtcall("status", "sE"); + mt->mt_resid = rmtcall("status", "sR"); + mt->mt_fileno = rmtcall("status", "sF"); + mt->mt_blkno = rmtcall("status", "sB"); + mt->mt_flags = rmtcall("status", "sf"); + mt->mt_bf = rmtcall("status", "sb"); + return (0); +} + +rmtread(buf, count) + char *buf; + uint_t count; +{ + char line[30]; + int n, i, cc; + + (void) snprintf(line, sizeof (line), "R%d\n", count); + n = rmtcall("read", line); + if (n < 0) { + return (-1); + } + if (n > count) { + print(dgettext(domainname, + "rmtread: expected response size %d, got %d\n"), + count, n); + print(dgettext(domainname, + "This means the remote rmt daemon is not compatible.\n")); + rmtconnaborted(0); + } + i = 0; + while (i < n) { + cc = read(rmtape, buf+i, n - i); + if (cc <= 0) + rmtconnaborted(0); + i += cc; + } + return (n); +} + +rmtwrite(buf, count) + char *buf; + uint_t count; +{ + int retval; + char line[64]; /* numbers can get big */ + + (void) snprintf(line, sizeof (line), "W%d\n", count); + retval = rmtpush(line, strlen(line)); + if (retval <= 0) + return (-1); + + retval = rmtpush(buf, count); + if (retval <= 0) + return (-1); + + return (rmtreply("write")); +} + +int +rmtpush(buf, count) + char *buf; + uint_t count; +{ + int retval; + + do { + retval = write(rmtape, buf, count); + buf += retval; + count -= retval; + } while (count && retval > 0); + + return (retval); +} + +int +rmtseek(offset, pos) + int offset, pos; +{ + char line[80]; + + (void) snprintf(line, sizeof (line), "L%d\n%d\n", offset, pos); + return (rmtcall("seek", line)); +} + +int +rmtioctl(cmd, count) + int cmd; + long count; +{ + char buf[256]; + int xcmd; + + if (count < 0) + return (-1); + + if ((xcmd = map_extended_ioctl(cmd)) != -1) + return (rmtioctl_extended(xcmd, count)); + + (void) snprintf(buf, sizeof (buf), "I%d\n%ld\n", cmd, count); + return (rmtcall("ioctl", buf)); +} + +/* + * Map from the standard Sun ioctl commands into the extended version, + * if possible. + */ +static int +map_extended_ioctl(cmd) + int cmd; +{ + int xcmd; + + if (rmtversion <= 0) + return (-1); /* extended protocol not supported */ + + switch (cmd) { + case MTRETEN: + xcmd = 2; + break; + case MTERASE: + xcmd = 3; + break; + case MTEOM: + xcmd = 4; + break; + case MTNBSF: + xcmd = 5; + break; + default: + xcmd = -1; /* not supported */ + break; + } + return (xcmd); +} + +static int +rmtioctl_extended(cmd, count) + int cmd; + long count; +{ + char buf[256]; + + (void) snprintf(buf, sizeof (buf), "i%d\n%ld\n", cmd, count); + return (rmtcall("ioctl", buf)); +} + +static int +rmtcall(cmd, buf) + char *cmd, *buf; +{ + if (rmtpush(buf, strlen(buf)) != strlen(buf)) + rmtconnaborted(0); + return (rmtreply(cmd)); +} + +static int +rmtreply(cmd) + char *cmd; +{ + char code[30], emsg[BUFSIZ]; + + rmtgets(code, sizeof (code)); + if (*code == 'E' || *code == 'F') { + rmtgets(emsg, sizeof (emsg)); + /* + * don't print error message for ioctl or status; + * or if we are opening up a full path (i.e. device) + * and the tape is not loaded (EIO error) + */ + if (strcmp(cmd, "ioctl") != 0 && + strcmp(cmd, "status") != 0 && + !(cmd[0] == '/' && atoi(code + 1) == EIO)) + print("%s: %s\n", cmd, emsg); + errno = atoi(code + 1); + if (*code == 'F') { + rmtstate = TS_CLOSED; + return (-1); + } + return (-1); + } + if (*code != 'A') { + print(dgettext(domainname, + "Protocol to remote tape server botched (code %s?).\n"), + code); + rmtconnaborted(0); + } + return (atoi(code + 1)); +} + +static void +rmtgets(cp, len) + char *cp; + int len; +{ + int i, n; + + n = recv(rmtape, cp, len-1, MSG_PEEK); + for (i = 0; i < n; i++) + if (cp[i] == '\n') + break; + n = i + 1; /* characters to read at once */ + for (i = 0; i < len; i += n, n = 1) { + n = read(rmtape, cp, n); + if (n <= 0) + rmtconnaborted(0); + cp += n; + if (cp[-1] == '\n') { + cp[-1] = '\0'; + return; + } + } + print(dgettext(domainname, + "Protocol to remote tape server botched (in rmtgets).\n")); + rmtconnaborted(0); +} + +#ifdef __STDC__ +#include <stdarg.h> + +/* VARARGS1 */ +static void +rmtmsg(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void) vfprintf(stderr, fmt, args); + (void) fflush(stderr); +} +#else +#include <varargs.h> + +/* VARARGS */ +static void +rmtmsg(va_alist) + va_dcl +{ + va_list args; + char *fmt; + + va_start(args); + fmt = va_arg(args, char *); + (void) vfprintf(stderr, fmt, args); + (void) fflush(stderr); +} +#endif |
