summaryrefslogtreecommitdiff
path: root/usr/src/lib/libpkg/common/dstream.c
diff options
context:
space:
mode:
authorMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
committerMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
commit5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch)
tree0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/lib/libpkg/common/dstream.c
parent2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff)
downloadillumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/lib/libpkg/common/dstream.c')
-rw-r--r--usr/src/lib/libpkg/common/dstream.c1036
1 files changed, 1036 insertions, 0 deletions
diff --git a/usr/src/lib/libpkg/common/dstream.c b/usr/src/lib/libpkg/common/dstream.c
new file mode 100644
index 0000000000..68ff540393
--- /dev/null
+++ b/usr/src/lib/libpkg/common/dstream.c
@@ -0,0 +1,1036 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#ifdef u3b2
+#include <sys/sys3b.h>
+#endif /* u3b2 */
+#include <openssl/err.h>
+#include "pkglib.h"
+#include "pkglibmsgs.h"
+#include "pkglocale.h"
+#ifdef u3b2
+static
+struct stat orig_st_buf; /* Stat structure of original file (3B2/CTC) */
+static char ds_ctcflg;
+#endif /* u3b2 */
+
+/* libadm.a */
+extern char *devattr(char *device, char *attribute);
+extern int pkgnmchk(register char *pkg, register char *spec,
+ int presvr4flg);
+extern int getvol(char *device, char *label, int options, char *prompt);
+
+#define CMDSIZ 512
+#define LSIZE 128
+#define DDPROC "/usr/bin/dd"
+#define CPIOPROC "/usr/bin/cpio"
+
+/* device types */
+
+#define G_TM_TAPE 1 /* Tapemaster controller */
+#define G_XY_DISK 3 /* xy disks */
+#define G_SD_DISK 7 /* scsi sd disk */
+#define G_XT_TAPE 8 /* xt tapes */
+#define G_SF_FLOPPY 9 /* sf floppy */
+#define G_XD_DISK 10 /* xd disks */
+#define G_ST_TAPE 11 /* scsi tape */
+#define G_NS 12 /* noswap pseudo-dev */
+#define G_RAM 13 /* ram pseudo-dev */
+#define G_FT 14 /* tftp */
+#define G_HD 15 /* 386 network disk */
+#define G_FD 16 /* 386 AT disk */
+#define G_FILE 28 /* file, not a device */
+#define G_NO_DEV 29 /* device does not require special treatment */
+#define G_DEV_MAX 30 /* last valid device type */
+
+struct dstoc {
+ int cnt;
+ char pkg[NON_ABI_NAMELNGTH];
+ int nparts;
+ long maxsiz;
+ char volnos[128];
+ struct dstoc *next;
+} *ds_head, *ds_toc;
+
+#define ds_nparts ds_toc->nparts
+#define ds_maxsiz ds_toc->maxsiz
+
+int ds_totread; /* total number of parts read */
+int ds_fd = -1;
+int ds_curpartcnt = -1;
+
+int ds_next(char *device, char *instdir);
+int ds_ginit(char *device);
+int ds_close(int pkgendflg);
+
+static FILE *ds_pp;
+static int ds_realfd = -1; /* file descriptor for real device */
+static int ds_read; /* number of parts read for current package */
+static int ds_volno; /* volume number of current volume */
+static int ds_volcnt; /* total number of volumes */
+static char ds_volnos[128]; /* parts/volume info */
+static char *ds_device;
+static int ds_volpart; /* number of parts read in current volume, */
+ /* including skipped parts */
+static int ds_bufsize;
+static int ds_skippart; /* number of parts skipped in current volume */
+
+static int ds_getnextvol(char *device);
+static int ds_skip(char *device, int nskip);
+
+void
+ds_order(char *list[])
+{
+ struct dstoc *toc_pt;
+ register int j, n;
+ char *pt;
+
+ toc_pt = ds_head;
+ n = 0;
+ while (toc_pt) {
+ for (j = n; list[j]; j++) {
+ if (strcmp(list[j], toc_pt->pkg) == 0) {
+ /* just swap places in the array */
+ pt = list[n];
+ list[n++] = list[j];
+ list[j] = pt;
+ }
+ }
+ toc_pt = toc_pt->next;
+ }
+}
+
+static char *pds_header;
+static char *ds_header;
+static char *ds_header_raw;
+static int ds_headsize;
+
+static char *
+ds_gets(char *buf, int size)
+{
+ int length;
+ char *nextp;
+
+ nextp = strchr(pds_header, '\n');
+ if (nextp == NULL) {
+ length = strlen(pds_header);
+ if (length > size)
+ return (0);
+ if ((ds_header = (char *)realloc(ds_header,
+ ds_headsize + BLK_SIZE)) == NULL)
+ return (0);
+ if (read(ds_fd, ds_header + ds_headsize, BLK_SIZE) < BLK_SIZE)
+ return (0);
+ ds_headsize += BLK_SIZE;
+ nextp = strchr(pds_header, '\n');
+ if (nextp == NULL)
+ return (0);
+ *nextp = '\0';
+ if (length + (int)strlen(pds_header) > size)
+ return (0);
+ (void) strncpy(buf + length, pds_header, strlen(pds_header));
+ buf[length + strlen(pds_header)] = '\0';
+ pds_header = nextp + 1;
+ return (buf);
+ }
+ *nextp = '\0';
+ if ((int)strlen(pds_header) > size)
+ return (0);
+ (void) strncpy(buf, pds_header, strlen(pds_header));
+ buf[strlen(pds_header)] = '\0';
+ pds_header = nextp + 1;
+ return (buf);
+}
+
+/*
+ * function to determine if media is datastream or mounted
+ * floppy
+ */
+int
+ds_readbuf(char *device)
+{
+ char buf[BLK_SIZE];
+
+ if (ds_fd >= 0)
+ (void) close(ds_fd);
+ if ((ds_fd = open(device, O_RDONLY)) >= 0 &&
+ read(ds_fd, buf, BLK_SIZE) == BLK_SIZE &&
+ strncmp(buf, HDR_PREFIX, 20) == 0) {
+ if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_MEM));
+ (void) ds_close(0);
+ return (0);
+ }
+ memcpy(ds_header, buf, BLK_SIZE);
+ ds_headsize = BLK_SIZE;
+
+ if (ds_ginit(device) < 0) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_OPEN), device, errno);
+ (void) ds_close(0);
+ return (0);
+ }
+ return (1);
+ } else if (ds_fd >= 0) {
+ (void) close(ds_fd);
+ ds_fd = -1;
+ }
+ return (0);
+}
+
+/*
+ * Determine how many additional volumes are needed for current package.
+ * Note: a 0 will occur as first volume number when the package begins
+ * on the next volume.
+ */
+static int
+ds_volsum(struct dstoc *toc)
+{
+ int curpartcnt, volcnt;
+ char volnos[128], tmpvol[128];
+ if (toc->volnos[0]) {
+ int index, sum;
+ sscanf(toc->volnos, "%d %[ 0-9]", &curpartcnt, volnos);
+ volcnt = 0;
+ sum = curpartcnt;
+ while (sum < toc->nparts && sscanf(volnos, "%d %[ 0-9]",
+ &index, tmpvol) >= 1) {
+ (void) strcpy(volnos, tmpvol);
+ volcnt++;
+ sum += index;
+ }
+ /* side effect - set number of parts read on current volume */
+ ds_volpart = index;
+ return (volcnt);
+ }
+ ds_volpart += toc->nparts;
+ return (0);
+}
+
+/* initialize ds_curpartcnt and ds_volnos */
+static void
+ds_pkginit(void)
+{
+ if (ds_toc->volnos[0])
+ sscanf(ds_toc->volnos, "%d %[ 0-9]", &ds_curpartcnt, ds_volnos);
+ else
+ ds_curpartcnt = -1;
+}
+
+/*
+ * functions to pass current package info to exec'ed program
+ */
+void
+ds_putinfo(char *buf)
+{
+ (void) sprintf(buf, "%d %d %d %d %d %d %d %d %d %d %s",
+ ds_fd, ds_realfd, ds_volcnt, ds_volno, ds_totread, ds_volpart,
+ ds_skippart, ds_bufsize, ds_toc->nparts, ds_toc->maxsiz,
+ ds_toc->volnos);
+}
+
+int
+ds_getinfo(char *string)
+{
+ ds_toc = (struct dstoc *)calloc(1, sizeof (struct dstoc));
+ (void) sscanf(string, "%d %d %d %d %d %d %d %d %d %d %[ 0-9]",
+ &ds_fd, &ds_realfd, &ds_volcnt, &ds_volno, &ds_totread,
+ &ds_volpart, &ds_skippart, &ds_bufsize, &ds_toc->nparts,
+ &ds_toc->maxsiz, ds_toc->volnos);
+ ds_pkginit();
+ return (ds_toc->nparts);
+}
+
+/*
+ * Return true if the file descriptor (ds_fd) is open on the package stream.
+ */
+boolean_t
+ds_fd_open(void)
+{
+ return (ds_fd >= 0 ? B_TRUE : B_FALSE);
+}
+
+/*
+ * Read the source device. Acquire the header data and check it for validity.
+ */
+int
+ds_init(char *device, char **pkg, char *norewind)
+{
+ struct dstoc *tail, *toc_pt;
+ char *ret;
+ char cmd[CMDSIZ];
+ char line[LSIZE+1];
+ int i, n, count = 0, header_size = BLK_SIZE;
+
+ if (!ds_header) { /* If the header hasn't been read yet */
+ if (ds_fd >= 0)
+ (void) ds_close(0);
+
+ /* always start with rewind device */
+ if ((ds_fd = open(device, O_RDONLY)) < 0) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_OPEN), device, errno);
+ return (-1);
+ }
+
+ /* allocate room for the header equivalent to a block */
+ if ((ds_header = (char *)calloc(BLK_SIZE, 1)) == NULL) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_MEM));
+ return (-1);
+ }
+
+ /* initialize the device */
+ if (ds_ginit(device) < 0) {
+ (void) ds_close(0);
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_OPEN), device, errno);
+ return (-1);
+ }
+
+ /* read a logical block from the source device */
+ if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ (void) ds_close(0);
+ return (-1);
+ }
+
+ /*
+ * This loop scans the medium for the start of the header.
+ * If the above read worked, we skip this. If it did't, this
+ * loop will retry the read ten times looking for the header
+ * marker string.
+ */
+ while (strncmp(ds_header, HDR_PREFIX, 20) != 0) {
+ /* only ten tries iff the device rewinds */
+ if (!norewind || count++ > 10) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ (void) ds_close(0);
+ return (-1);
+ }
+
+ /* read through to the last block */
+ if (count > 1)
+ while (read(ds_fd, ds_header, BLK_SIZE) > 0)
+ ;
+
+ /* then close the device */
+ (void) ds_close(0);
+
+ /* and reopen it */
+ if ((ds_fd = open(norewind, O_RDONLY)) < 0) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_OPEN), device, errno);
+ (void) free(ds_header);
+ return (-1);
+ }
+
+ /* initialize the device */
+ if (ds_ginit(device) < 0) {
+ (void) ds_close(0);
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_OPEN), device, errno);
+ return (-1);
+ }
+
+ /* read the block again */
+ if (read(ds_fd, ds_header, BLK_SIZE) != BLK_SIZE) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ (void) ds_close(0);
+ return (-1);
+ }
+ }
+
+ /* Now keep scanning until the whole header is in place. */
+ while (strstr(ds_header, HDR_SUFFIX) == NULL) {
+ /* We need a bigger buffer */
+ if ((ds_header = (char *)realloc(ds_header,
+ header_size + BLK_SIZE)) == NULL) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_MEM));
+ (void) ds_close(0);
+ return (1);
+ }
+
+ /* clear the new memory */
+ (void) memset(ds_header + header_size, '\0',
+ BLK_SIZE);
+
+
+ /* read a logical block from the source device */
+ if (read(ds_fd, ds_header + header_size, BLK_SIZE) !=
+ BLK_SIZE) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ (void) ds_close(0);
+ return (-1);
+ } else
+ header_size += BLK_SIZE; /* new size */
+ }
+
+ /*
+ * remember rewind device for ds_close to rewind at
+ * close
+ */
+ if (count >= 1)
+ ds_device = device;
+ ds_headsize = header_size;
+
+ }
+
+ pds_header = ds_header;
+
+ /* save raw copy of header for later use in BIO_dump_header */
+ if ((ds_header_raw = (char *)malloc(header_size)) == NULL) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_MEM));
+ (void) ds_close(0);
+ return (1);
+ }
+ memcpy(ds_header_raw, ds_header, header_size);
+
+ /* read datastream table of contents */
+ ds_head = tail = (struct dstoc *)0;
+ ds_volcnt = 1;
+
+ while (ret = ds_gets(line, LSIZE)) {
+ if (strcmp(line, HDR_SUFFIX) == 0)
+ break;
+ if (!line[0] || line[0] == '#')
+ continue;
+ toc_pt = (struct dstoc *)calloc(1, sizeof (struct dstoc));
+ if (!toc_pt) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_MEM));
+ ecleanup();
+ (void) free(ds_header);
+ return (-1);
+ }
+ if (sscanf(line, "%s %d %d %[ 0-9]", toc_pt->pkg,
+ &toc_pt->nparts, &toc_pt->maxsiz, toc_pt->volnos) < 3) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ free(toc_pt);
+ (void) free(ds_header);
+ ecleanup();
+ return (-1);
+ }
+ if (tail) {
+ tail->next = toc_pt;
+ tail = toc_pt;
+ } else
+ ds_head = tail = toc_pt;
+ ds_volcnt += ds_volsum(toc_pt);
+ }
+ if (!ret) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_TOC));
+ (void) free(ds_header);
+ return (-1);
+ }
+ sighold(SIGINT);
+ sigrelse(SIGINT);
+ if (!ds_head) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_EMPTY));
+ (void) free(ds_header);
+ return (-1);
+ }
+ /* this could break, thanks to cpio command limit */
+#ifndef SUNOS41
+ (void) sprintf(cmd, "%s -icdumD -C %d", CPIOPROC, (int)BLK_SIZE);
+#else
+ (void) sprintf(cmd, "%s -icdum -C %d", CPIOPROC, (int)BLK_SIZE);
+#endif
+ n = 0;
+ for (i = 0; pkg[i]; i++) {
+ if (strcmp(pkg[i], "all") == 0)
+ continue;
+ if (n == 0) {
+ strcat(cmd, " ");
+ n = 1;
+ }
+ strlcat(cmd, pkg[i], CMDSIZ);
+ strlcat(cmd, "'/*' ", CMDSIZ);
+
+ /* extract signature too, if present. */
+ strlcat(cmd, SIGNATURE_FILENAME, CMDSIZ);
+ strlcat(cmd, " ", CMDSIZ);
+ }
+
+ /*
+ * if we are extracting all packages (pkgs == NULL),
+ * signature will automatically be extracted
+ */
+ if (n = esystem(cmd, ds_fd, -1)) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
+ (void) free(ds_header);
+ return (-1);
+ }
+
+ ds_toc = ds_head;
+ ds_totread = 0;
+ ds_volno = 1;
+ return (0);
+}
+
+int
+ds_findpkg(char *device, char *pkg)
+{
+ char *pkglist[2];
+ int nskip, ods_volpart;
+
+ if (ds_head == NULL) {
+ pkglist[0] = pkg;
+ pkglist[1] = NULL;
+ if (ds_init(device, pkglist, NULL))
+ return (-1);
+ }
+
+ if (!pkg || pkgnmchk(pkg, "all", 0)) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_PKGNAME));
+ return (-1);
+ }
+
+ nskip = 0;
+ ds_volno = 1;
+ ds_volpart = 0;
+ ds_toc = ds_head;
+ while (ds_toc) {
+ if (strcmp(ds_toc->pkg, pkg) == 0)
+ break;
+ nskip += ds_toc->nparts;
+ ds_volno += ds_volsum(ds_toc);
+ ds_toc = ds_toc->next;
+ }
+ if (!ds_toc) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_NOPKG), pkg);
+ return (-1);
+ }
+
+ ds_pkginit();
+ ds_skippart = 0;
+ if (ds_curpartcnt > 0) {
+ ods_volpart = ds_volpart;
+ /*
+ * skip past archives belonging to last package on current
+ * volume
+ */
+ if (ds_volpart > 0 && ds_getnextvol(device))
+ return (-1);
+ ds_totread = nskip - ods_volpart;
+ if (ds_skip(device, ods_volpart))
+ return (-1);
+ } else if (ds_curpartcnt < 0) {
+ if (ds_skip(device, nskip - ds_totread))
+ return (-1);
+ } else
+ ds_totread = nskip;
+ ds_read = 0;
+ return (ds_nparts);
+}
+
+/*
+ * Get datastream part
+ * Call for first part should be preceded by
+ * call to ds_findpkg
+ */
+
+int
+ds_getpkg(char *device, int n, char *dstdir)
+{
+ struct statvfs64 svfsb;
+ u_longlong_t free_blocks;
+
+ if (ds_read >= ds_nparts)
+ return (2);
+
+ if (ds_read == n)
+ return (0);
+ else if ((ds_read > n) || (n > ds_nparts))
+ return (2);
+
+ if (ds_maxsiz > 0) {
+ if (statvfs64(".", &svfsb)) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_STATFS), errno);
+ return (-1);
+ }
+#ifdef SUNOS41
+ free_blocks = svfsb.f_bfree * howmany(svfsb.f_bsize, DEV_BSIZE);
+#else /* !SUNOS41 */
+ free_blocks = (((long)svfsb.f_frsize > 0) ?
+ howmany(svfsb.f_frsize, DEV_BSIZE) :
+ howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;
+#endif /* SUNOS41 */
+ if ((ds_maxsiz + 50) > free_blocks) {
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_NOSPACE), ds_maxsiz+50, free_blocks);
+ return (-1);
+ }
+ }
+ return (ds_next(device, dstdir));
+}
+
+static int
+ds_getnextvol(char *device)
+{
+ char prompt[128];
+ int n;
+
+ if (ds_close(0))
+ return (-1);
+ (void) sprintf(prompt,
+ pkg_gt("Insert %%v %d of %d into %%p"),
+ ds_volno, ds_volcnt);
+ if (n = getvol(device, NULL, NULL, prompt))
+ return (n);
+ if ((ds_fd = open(device, O_RDONLY)) < 0)
+ return (-1);
+ if (ds_ginit(device) < 0) {
+ (void) ds_close(0);
+ return (-1);
+ }
+ ds_volpart = 0;
+ return (0);
+}
+
+/*
+ * called by ds_findpkg to skip past archives for unwanted packages
+ * in current volume
+ */
+static int
+ds_skip(char *device, int nskip)
+{
+ char cmd[CMDSIZ];
+ int n, onskip = nskip;
+
+ while (nskip--) {
+ /* skip this one */
+#ifndef SUNOS41
+ (void) sprintf(cmd, "%s -ictD -C %d > /dev/null",
+#else
+ (void) sprintf(cmd, "%s -ict -C %d > /dev/null",
+#endif
+ CPIOPROC, (int)BLK_SIZE);
+ if (n = esystem(cmd, ds_fd, -1)) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
+ nskip = onskip;
+ if (ds_volno == 1 || ds_volpart > 0)
+ return (n);
+ if (n = ds_getnextvol(device))
+ return (n);
+ }
+ }
+ ds_totread += onskip;
+ ds_volpart = onskip;
+ ds_skippart = onskip;
+ return (0);
+}
+
+/* skip to end of package if necessary */
+void
+ds_skiptoend(char *device)
+{
+ if (ds_read < ds_nparts && ds_curpartcnt < 0)
+ (void) ds_skip(device, ds_nparts - ds_read);
+}
+
+int
+ds_next(char *device, char *instdir)
+{
+ char cmd[CMDSIZ], tmpvol[128];
+ int nparts, n, index;
+
+ /*CONSTCOND*/
+ while (1) {
+ if (ds_read + 1 > ds_curpartcnt && ds_curpartcnt >= 0) {
+ ds_volno++;
+ if (n = ds_getnextvol(device))
+ return (n);
+ (void) sscanf(ds_volnos, "%d %[ 0-9]", &index, tmpvol);
+ (void) strcpy(ds_volnos, tmpvol);
+ ds_curpartcnt += index;
+ }
+#ifndef SUNOS41
+ (void) sprintf(cmd, "%s -icdumD -C %d",
+#else
+ (void) sprintf(cmd, "%s -icdum -C %d",
+#endif
+ CPIOPROC, (int)BLK_SIZE);
+ if (n = esystem(cmd, ds_fd, -1)) {
+ rpterr();
+ progerr(pkg_gt(ERR_UNPACK));
+ logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
+ }
+ if (ds_read == 0)
+ nparts = 0;
+ else
+ nparts = ds_toc->nparts;
+ if (n || (n = ckvolseq(instdir, ds_read + 1, nparts))) {
+ if (ds_volno == 1 || ds_volpart > ds_skippart)
+ return (-1);
+
+ if (n = ds_getnextvol(device))
+ return (n);
+ continue;
+ }
+ ds_read++;
+ ds_totread++;
+ ds_volpart++;
+
+ return (0);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * Name: BIO_ds_dump
+ * Description: Dumps all data from the static 'ds_fd' file handle into
+ * the supplied BIO.
+ *
+ * Arguments: err - where to record any errors.
+ * device - Description of device being dumped into,
+ * for error reporting
+ * bio - BIO object to dump data into
+ *
+ * Returns : zero - successfully dumped all data to EOF
+ * non-zero - some failure occurred.
+ */
+int
+BIO_ds_dump(PKG_ERR *err, char *device, BIO *bio)
+{
+ int amtread;
+ char readbuf[BLK_SIZE];
+
+ /*
+ * note this will read to the end of the device, so it won't
+ * work for character devices since we don't know when the
+ * end of the CPIO archive is
+ */
+ while ((amtread = read(ds_fd, readbuf, BLK_SIZE)) != 0) {
+ if (BIO_write(bio, readbuf, amtread) != amtread) {
+ pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, device,
+ ERR_error_string(ERR_get_error(), NULL));
+ return (1);
+ }
+ }
+
+ return (0);
+ /*NOTREACHED*/
+}
+
+
+/*
+ * Name: BIO_ds_dump_header
+ * Description: Dumps all ds_headsize bytes from the
+ * static 'ds_header_raw' character array
+ * to the supplied BIO.
+ *
+ * Arguments: err - where to record any errors.
+ * bio - BIO object to dump data into
+ *
+ * Returns : zero - successfully dumped all raw
+ * header characters
+ * non-zero - some failure occurred.
+ */
+int
+BIO_ds_dump_header(PKG_ERR *err, BIO *bio)
+{
+
+ char zeros[BLK_SIZE];
+
+ memset(zeros, 0, BLK_SIZE);
+
+ if (BIO_write(bio, ds_header_raw, ds_headsize) != ds_headsize) {
+ pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, "bio",
+ ERR_error_string(ERR_get_error(), NULL));
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * ds_ginit: Determine the device being accessed, set the buffer size,
+ * and perform any device specific initialization. For the 3B2,
+ * a device with major number of 17 (0x11) is an internal hard disk,
+ * unless the minor number is 128 (0x80) in which case it is an internal
+ * floppy disk. Otherwise, get the system configuration
+ * table and check it by comparing slot numbers to major numbers.
+ * For the special case of the 3B2 CTC several unusual things must be done.
+ * To enable
+ * streaming mode on the CTC, the file descriptor must be closed, re-opened
+ * (with O_RDWR and O_CTSPECIAL flags set), the STREAMON ioctl(2) command
+ * issued, and the file descriptor re-re-opened either read-only or write_only.
+ */
+
+int
+ds_ginit(char *device)
+{
+#ifdef u3b2
+ major_t maj;
+ minor_t min;
+ int nflag, i, count, size;
+ struct s3bconf *buffer;
+ struct s3bc *table;
+ struct stat st_buf;
+ int devtype;
+ char buf[BLK_SIZE];
+ int fd2, fd;
+#endif /* u3b2 */
+ int oflag;
+ char *pbufsize, cmd[CMDSIZ];
+ int fd2, fd;
+
+ if ((pbufsize = devattr(device, "bufsize")) != NULL) {
+ ds_bufsize = atoi(pbufsize);
+ (void) free(pbufsize);
+ } else
+ ds_bufsize = BLK_SIZE;
+ oflag = fcntl(ds_fd, F_GETFL, 0);
+#ifdef u3b2
+ devtype = G_NO_DEV;
+ if (fstat(ds_fd, &st_buf) == -1)
+ return (-1);
+ if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode))
+ goto lab;
+
+ /*
+ * We'll have to add a remote attribute to stat but this should
+ * work for now.
+ */
+ else if (st_buf.st_dev & 0x8000) /* if remote rdev */
+ goto lab;
+
+ maj = major(st_buf.st_rdev);
+ min = minor(st_buf.st_rdev);
+ if (maj == 0x11) { /* internal hard or floppy disk */
+ if (min & 0x80)
+ devtype = G_3B2_FD; /* internal floppy disk */
+ else
+ devtype = G_3B2_HD; /* internal hard disk */
+ } else {
+ if (sys3b(S3BCONF, (struct s3bconf *)&count, sizeof (count)) ==
+ -1)
+ return (-1);
+ size = sizeof (int) + (count * sizeof (struct s3bconf));
+ buffer = (struct s3bconf *)malloc((unsigned)size);
+ if (sys3b(S3BCONF, buffer, size) == -1)
+ return (-1);
+ table = (struct s3bc *)((char *)buffer + sizeof (int));
+ for (i = 0; i < count; i++) {
+ if (maj == (int)table->board) {
+ if (strncmp(table->name, "CTC", 3) == 0) {
+ devtype = G_3B2_CTC;
+ break;
+ } else if (strncmp(table->name, "TAPE", 4)
+ == 0) {
+ devtype = G_TAPE;
+ break;
+ }
+ /* other possible devices can go here */
+ }
+ table++;
+ }
+ }
+ switch (devtype) {
+ case G_3B2_CTC: /* do special CTC initialization */
+ ds_bufsize = pbufsize ? ds_bufsize : 15872;
+ if (fstat(ds_fd, &orig_st_buf) < 0) {
+ ds_bufsize = -1;
+ break;
+ }
+ nflag = (O_RDWR | O_CTSPECIAL);
+ (void) close(ds_fd);
+ if ((ds_fd = open(device, nflag, 0666)) != -1) {
+ if (ioctl(ds_fd, STREAMON) != -1) {
+ (void) close(ds_fd);
+ nflag = (oflag == O_WRONLY) ?
+ O_WRONLY : O_RDONLY;
+ if ((ds_fd =
+ open(device, nflag, 0666)) == -1) {
+ rpterr();
+ progerr(
+ pkg_gt(ERR_TRANSFER));
+ logerr(pkg_gt(MSG_OPEN),
+ device, errno);
+ return (-1);
+ }
+ ds_bufsize = 15872;
+ }
+ } else
+ ds_bufsize = -1;
+ if (oflag == O_RDONLY && ds_header && ds_totread == 0)
+ /* Have already read in first block of header */
+ read(ds_fd, buf, BLK_SIZE);
+ ds_ctcflg = 1;
+
+ break;
+ case G_NO_DEV:
+ case G_3B2_HD:
+ case G_3B2_FD:
+ case G_TAPE:
+ case G_SCSI_HD: /* not developed yet */
+ case G_SCSI_FD:
+ case G_SCSI_9T:
+ case G_SCSI_Q24:
+ case G_SCSI_Q120:
+ case G_386_HD:
+ case G_386_FD:
+ case G_386_Q24:
+ ds_bufsize = pbufsize ? ds_bufsize : BLK_SIZE;
+ break;
+ default:
+ ds_bufsize = -1;
+ errno = ENODEV;
+ } /* devtype */
+lab:
+#endif /* u3b2 */
+ if (ds_bufsize > BLK_SIZE) {
+ if (oflag & O_WRONLY)
+ fd = 1;
+ else
+ fd = 0;
+ fd2 = fcntl(fd, F_DUPFD, fd);
+ (void) close(fd);
+ fcntl(ds_fd, F_DUPFD, fd);
+ if (fd)
+ sprintf(cmd, "%s obs=%d 2>/dev/null", DDPROC,
+ ds_bufsize);
+ else
+ sprintf(cmd, "%s ibs=%d 2>/dev/null", DDPROC,
+ ds_bufsize);
+ if ((ds_pp = popen(cmd, fd ? "w" : "r")) == NULL) {
+ progerr(pkg_gt(ERR_TRANSFER));
+ logerr(pkg_gt(MSG_POPEN), cmd, errno);
+ return (-1);
+ }
+ (void) close(fd);
+ fcntl(fd2, F_DUPFD, fd);
+ (void) close(fd2);
+ ds_realfd = ds_fd;
+ ds_fd = fileno(ds_pp);
+ }
+ return (ds_bufsize);
+}
+
+int
+ds_close(int pkgendflg)
+{
+#ifdef u3b2
+ int cnt, mode;
+ char *ptr;
+ struct stat statbuf;
+#endif /* u3b2 */
+ int n, ret = 0;
+
+#ifdef u3b2
+ if (ds_pp && ds_ctcflg) {
+ ds_ctcflg = 0;
+ if ((mode = fcntl(ds_realfd, F_GETFL, 0)) < 0) {
+ ret = -1;
+ } else if (mode & O_WRONLY) {
+ /*
+ * pipe to dd write process,
+ * make sure one more buffer
+ * gets written out
+ */
+ if ((ptr = calloc(BLK_SIZE, 1)) == NULL) {
+ ret = -1;
+ /* pad to bufsize */
+ } else {
+ cnt = ds_bufsize;
+ while (cnt > 0) {
+ if ((n = write(ds_fd, ptr,
+ BLK_SIZE)) < 0) {
+ ret = -1;
+ break;
+ }
+ cnt -= n;
+ }
+ (void) free(ptr);
+ }
+ }
+ }
+#endif
+ if (pkgendflg) {
+ if (ds_header)
+ (void) free(ds_header);
+ ds_header = (char *)NULL;
+ ds_totread = 0;
+ }
+
+ if (ds_pp) {
+ (void) pclose(ds_pp);
+ ds_pp = 0;
+ (void) close(ds_realfd);
+ ds_realfd = -1;
+ ds_fd = -1;
+ } else if (ds_fd >= 0) {
+ (void) close(ds_fd);
+ ds_fd = -1;
+ }
+
+ if (ds_device) {
+ /* rewind device */
+ if ((n = open(ds_device, 0)) >= 0)
+ (void) close(n);
+ ds_device = NULL;
+ }
+ return (ret);
+}