#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/sysmacros.h>
#include <dirent.h>
#include <signal.h>
#include <devmgmt.h>
#include <note.h>
#include "pkginfo.h"
#include "pkgstrct.h"
#include "pkgtrans.h"
#include "pkgdev.h"
#include "pkglib.h"
#include "pkglibmsgs.h"
#include "pkglocale.h"
extern char *pkgdir;
extern char *devattr(char *device, char *attribute);
extern char *fpkginst(char *pkg, ...);
extern int fpkginfo(struct pkginfo *info, char *pkginst);
extern int getvol(char *device, char *label, int options, char *prompt);
extern int _getvol(char *device, char *label, int options, char *prompt,
char *norewind);
extern int ds_ginit(char *device);
extern int ds_close(int pkgendflg);
#define CPIOPROC "/usr/bin/cpio"
#define CMDSIZE 512
#define BLK_SIZE 512
#define ENTRY_MAX 256
#define PKGINFO "pkginfo"
#define PKGMAP "pkgmap"
#define MAP_STAT_SIZE 60
#define INSTALL "install"
#define RELOC "reloc"
#define ROOT "root"
#define ARCHIVE "archive"
static struct pkgdev srcdev, dstdev;
static char *tmpdir;
static char *tmppath;
static char *tmpsymdir = NULL;
static char dstinst[NON_ABI_NAMELNGTH];
static char *ids_name, *ods_name;
static int ds_volcnt;
static int ds_volno;
static int compressedsize, has_comp_size;
static void (*sigintHandler)();
static void (*sighupHandler)();
static void cleanup(void);
static void sigtrap(int signo);
static int rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize);
static int cat_and_count(struct dm_buf *, char *);
static int ckoverwrite(char *dir, char *inst, int options);
static int pkgxfer(char *srcinst, int options);
static int wdsheader(struct dm_buf *, char *device, char **pkg);
static struct dm_buf *genheader(char *, char **);
extern int ds_fd;
static char *root_names[] = {
"root",
"root.cpio",
"root.Z",
"root.cpio.Z",
0
};
static char *reloc_names[] = {
"reloc",
"reloc.cpio",
"reloc.Z",
"reloc.cpio.Z",
0
};
static int signal_received = 0;
char **xpkg;
int nxpkg;
static char *allpkg[] = {
"all",
NULL
};
static struct dm_buf hdrbuf;
static char *pinput, *nextpinput;
int
pkghead(char *device)
{
char *pt;
int n;
cleanup();
if (device == NULL)
return (0);
else if ((device[0] == '/') && !isdir(device)) {
pkgdir = device;
return (0);
} else if ((pt = devattr(device, "pathname")) != NULL && !isdir(pt)) {
pkgdir = pt;
return (0);
}
if (n = pkgtrans(device, (char *)0, allpkg, PT_SILENT|PT_INFO_ONLY)) {
cleanup();
return (n);
}
return (0);
}
static char *
mgets(char *buf, int size)
{
nextpinput = strchr(pinput, '\n');
if (nextpinput == NULL)
return (0);
*nextpinput = '\0';
if ((int)strlen(pinput) > size)
return (0);
(void) strncpy(buf, pinput, strlen(pinput));
buf[strlen(pinput)] = '\0';
pinput = nextpinput + 1;
return (buf);
}
static int
rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize)
{
int n;
char line_buffer[MAP_STAT_SIZE];
if (fgets(line_buffer, MAP_STAT_SIZE, fp) == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOSIZE));
(void) fclose(fp);
ecleanup();
return (0);
}
n = sscanf(line_buffer, ": %d %d %d", npts, maxpsz, cmpsize);
if (n == 3)
has_comp_size = 1;
else if (n == 2)
has_comp_size = 0;
else {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOSIZE));
(void) fclose(fp);
ecleanup();
return (0);
}
return (n);
}
static int
_pkgtrans(char *device1, char *device2, char **pkg, int options)
{
char *src, *dst;
int errflg, i, n;
struct dm_buf *hdr;
if (signal_received > 0) {
return (1);
}
if (devtype(device1, &srcdev)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_BADDEV), device1);
return (1);
}
srcdev.rdonly++;
ids_name = NULL;
if (srcdev.bdevice) {
if (n = _getvol(srcdev.bdevice, NULL, 0,
pkg_gt("Insert %v into %p."), srcdev.norewind)) {
cleanup();
if (n == 3)
return (3);
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_GETVOL));
return (1);
}
if (ds_readbuf(srcdev.cdevice))
ids_name = srcdev.cdevice;
}
if (srcdev.cdevice && !srcdev.bdevice)
ids_name = srcdev.cdevice;
else if (srcdev.pathname) {
ids_name = srcdev.pathname;
if (access(ids_name, 0) == -1) {
progerr(ERR_TRANSFER);
logerr(pkg_gt(MSG_GETVOL));
return (1);
}
}
if (!ids_name && device2 == (char *)0) {
if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) {
cleanup();
return (n);
}
if (srcdev.mount && *srcdev.mount)
pkgdir = strdup(srcdev.mount);
return (0);
}
if (ids_name && device2 == (char *)0) {
tmppath = tmpnam(NULL);
tmppath = strdup(tmppath);
if (tmppath == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
return (1);
}
if (mkdir(tmppath, 0755)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MKDIR), tmppath);
return (1);
}
device2 = tmppath;
}
if (devtype(device2, &dstdev)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_BADDEV), device2);
return (1);
}
if ((srcdev.cdevice && dstdev.cdevice) &&
strcmp(srcdev.cdevice, dstdev.cdevice) == 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_SAMEDEV));
return (1);
}
ods_name = NULL;
if (dstdev.cdevice && !dstdev.bdevice || dstdev.pathname)
options |= PT_ODTSTREAM;
if (options & PT_ODTSTREAM) {
if (!((ods_name = dstdev.cdevice) != NULL ||
(ods_name = dstdev.pathname) != NULL)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_BADDEV), device2);
return (1);
}
if (ids_name) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_TWODSTREAM));
return (1);
}
}
if ((srcdev.dirname && dstdev.dirname) &&
strcmp(srcdev.dirname, dstdev.dirname) == 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_SAMEDEV));
return (1);
}
if ((srcdev.pathname && dstdev.pathname) &&
strcmp(srcdev.pathname, dstdev.pathname) == 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_SAMEDEV));
return (1);
}
if (signal_received > 0) {
return (1);
}
if (ids_name) {
if (srcdev.cdevice && !srcdev.bdevice &&
(n = _getvol(srcdev.cdevice, NULL, 0, NULL,
srcdev.norewind))) {
cleanup();
if (n == 3)
return (3);
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_GETVOL));
return (1);
}
if (srcdev.dirname = tmpnam(NULL))
tmpdir = srcdev.dirname = strdup(srcdev.dirname);
if ((srcdev.dirname == NULL) || mkdir(srcdev.dirname, 0755) ||
chdir(srcdev.dirname)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOTEMP), srcdev.dirname);
cleanup();
return (1);
}
if (ds_init(ids_name, pkg, srcdev.norewind)) {
cleanup();
return (1);
}
} else if (srcdev.mount) {
if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) {
cleanup();
return (n);
}
}
src = srcdev.dirname;
dst = dstdev.dirname;
if (chdir(src)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHDIR), src);
cleanup();
return (1);
}
if (signal_received > 0) {
return (1);
}
xpkg = pkg = gpkglist(src, pkg, NULL);
if (!pkg) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOPKGS), src);
cleanup();
return (1);
}
for (nxpkg = 0; pkg[nxpkg]; ) {
nxpkg++;
}
if (ids_name) {
ds_order(pkg);
}
if (signal_received > 0) {
return (1);
}
if (options & PT_ODTSTREAM) {
char line[128];
if (!dstdev.pathname &&
(n = _getvol(ods_name, NULL, DM_FORMAT, NULL,
dstdev.norewind))) {
cleanup();
if (n == 3)
return (3);
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_GETVOL));
return (1);
}
if ((hdr = genheader(src, pkg)) == NULL) {
cleanup();
return (1);
}
if (wdsheader(hdr, ods_name, pkg)) {
cleanup();
return (1);
}
ds_volno = 1;
pinput = hdrbuf.text_buffer;
(void) mgets(line, 128);
}
if (signal_received > 0) {
return (1);
}
errflg = 0;
for (i = 0; pkg[i]; i++) {
if (signal_received > 0) {
return (1);
}
if (!(options & PT_ODTSTREAM) && dstdev.mount) {
if (n = pkgmount(&dstdev, NULL, 0, 0, 1)) {
cleanup();
return (n);
}
}
if (errflg = pkgxfer(pkg[i], options)) {
pkg[i] = NULL;
if ((options & PT_ODTSTREAM) || (errflg != 2))
break;
} else if (strcmp(dstinst, pkg[i]))
pkg[i] = strdup(dstinst);
}
if (!(options & PT_ODTSTREAM) && dst) {
pkgdir = strdup(dst);
}
return (signal_received > 0 ? 1 : errflg);
}
int
pkgtrans(char *device1, char *device2, char **pkg, int options)
{
int r;
struct sigaction nact;
struct sigaction oact;
(void) sighold(SIGHUP);
(void) sighold(SIGINT);
nact.sa_handler = sigtrap;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
if (sigaction(SIGINT, &nact, &oact) < 0) {
sigintHandler = SIG_DFL;
} else {
sigintHandler = oact.sa_handler;
}
nact.sa_handler = sigtrap;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
if (sigaction(SIGHUP, &nact, &oact) < 0) {
sighupHandler = SIG_DFL;
} else {
sighupHandler = oact.sa_handler;
}
signal_received = 0;
(void) sigrelse(SIGHUP);
(void) sigrelse(SIGINT);
r = _pkgtrans(device1, device2, pkg, options);
(void) sighold(SIGHUP);
(void) sighold(SIGINT);
nact.sa_handler = sigintHandler;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
(void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
nact.sa_handler = sighupHandler;
nact.sa_flags = SA_RESTART;
(void) sigemptyset(&nact.sa_mask);
(void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
if (signal_received > 0) {
if (r != 0) {
cleanup();
}
(void) kill(getpid(), SIGINT);
}
(void) sigrelse(SIGHUP);
(void) sigrelse(SIGINT);
return (r);
}
static int
cat_and_count(struct dm_buf *buf_ctrl, char *append)
{
while ((buf_ctrl->offset + (int)strlen(append))
>= buf_ctrl->allocation) {
if ((buf_ctrl->text_buffer =
(char *)realloc(buf_ctrl->text_buffer,
buf_ctrl->allocation + BLK_SIZE)) == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
free(buf_ctrl->text_buffer);
return (1);
}
(void) memset(buf_ctrl->text_buffer +
buf_ctrl->allocation, '\0', BLK_SIZE);
buf_ctrl->allocation += BLK_SIZE;
}
while (*append) {
*(buf_ctrl->text_buffer + buf_ctrl->offset) = *append++;
(buf_ctrl->offset)++;
}
return (0);
}
static struct dm_buf *
genheader(char *src, char **pkg)
{
FILE *fp;
char path[MAXPATHLEN], tmp_entry[ENTRY_MAX];
int i, n, nparts, maxpsize;
int partcnt;
long totsize;
struct stat statbuf;
if ((hdrbuf.text_buffer = (char *)malloc(BLK_SIZE)) == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
return (NULL);
}
(void) memset(hdrbuf.text_buffer, '\0', BLK_SIZE);
hdrbuf.offset = 0;
hdrbuf.allocation = BLK_SIZE;
(void) cat_and_count(&hdrbuf, HDR_PREFIX);
(void) cat_and_count(&hdrbuf, "\n");
nparts = maxpsize = 0;
totsize = 0;
for (i = 0; pkg[i]; i++) {
(void) snprintf(path, MAXPATHLEN, "%s/%s/%s",
src, pkg[i], PKGINFO);
if (stat(path, &statbuf) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_BADPKGINFO));
ecleanup();
return (NULL);
}
totsize += statbuf.st_size/BLK_SIZE + 1;
}
totsize += i/4 + 1;
if (dstdev.capacity && totsize > dstdev.capacity) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOSPACE), totsize, dstdev.capacity);
ecleanup();
return (NULL);
}
ds_volcnt = 1;
for (i = 0; pkg[i]; i++) {
partcnt = 0;
(void) snprintf(path, MAXPATHLEN, "%s/%s/%s",
src, pkg[i], PKGMAP);
if ((fp = fopen(path, "r")) == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOPKGMAP), pkg[i]);
ecleanup();
return (NULL);
}
n = rd_map_size(fp, &nparts, &maxpsize, &compressedsize);
if (n == 3)
maxpsize = compressedsize;
else if (n == 0)
return (NULL);
if (dstdev.capacity && maxpsize > dstdev.capacity) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOSPACE), (long)maxpsize,
dstdev.capacity);
(void) fclose(fp);
ecleanup();
return (NULL);
}
if (snprintf(tmp_entry, ENTRY_MAX, "%s %d %d",
pkg[i], nparts, maxpsize) >= ENTRY_MAX) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(ERR_MEM));
(void) fclose(fp);
ecleanup();
return (NULL);
}
if (cat_and_count(&hdrbuf, tmp_entry)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
(void) fclose(fp);
ecleanup();
return (NULL);
}
totsize += nparts * maxpsize;
if (dstdev.capacity && dstdev.capacity < totsize) {
int lastpartcnt = 0;
if (totsize)
totsize -= nparts * maxpsize;
while (partcnt < nparts) {
while (totsize <= dstdev.capacity &&
partcnt <= nparts) {
totsize += maxpsize;
partcnt++;
}
if (partcnt)
partcnt--;
(void) snprintf(tmp_entry, ENTRY_MAX,
" %d", partcnt - lastpartcnt);
if (cat_and_count(&hdrbuf, tmp_entry)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
(void) fclose(fp);
ecleanup();
return (NULL);
}
ds_volcnt++;
totsize = 0;
lastpartcnt = partcnt;
}
ds_volcnt--;
}
if (cat_and_count(&hdrbuf, "\n")) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
(void) fclose(fp);
ecleanup();
return (NULL);
}
(void) fclose(fp);
}
if (cat_and_count(&hdrbuf, HDR_SUFFIX) ||
cat_and_count(&hdrbuf, "\n")) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MEM));
(void) fclose(fp);
ecleanup();
return (NULL);
}
return (&hdrbuf);
}
static int
wdsheader(struct dm_buf *hdr, char *device, char **pkg)
{
char tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1];
int i, n;
int list_fd;
int block_cnt;
(void) ds_close(0);
if (dstdev.pathname)
ds_fd = creat(device, 0644);
else
ds_fd = open(device, 1);
if (ds_fd < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN), device, errno);
return (1);
}
if (ds_ginit(device) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN), device, errno);
(void) ds_close(0);
return (1);
}
for (block_cnt = 0; block_cnt < hdr->allocation;
block_cnt += BLK_SIZE) {
(void) write(ds_fd, (hdr->text_buffer + block_cnt), BLK_SIZE);
}
(void) tmpnam(tmp_file);
if ((list_fd = open(tmp_file, O_RDWR | O_CREAT, 0644)) == -1) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOTMPFIL), tmp_file);
return (1);
}
for (i = 0; pkg[i]; i++) {
register ssize_t entry_size;
entry_size = sprintf(tmp_entry,
(i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s",
pkg[i], PKGINFO, pkg[i], PKGMAP);
if (write(list_fd, tmp_entry,
entry_size) != entry_size) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOTMPFIL), tmp_file);
(void) close(list_fd);
ecleanup();
return (1);
}
}
(void) lseek(list_fd, 0, SEEK_SET);
(void) snprintf(tmp_entry, sizeof (tmp_entry),
"%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE);
if (n = esystem(tmp_entry, list_fd, ds_fd)) {
rpterr();
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CMDFAIL), tmp_entry, n);
(void) close(list_fd);
(void) unlink(tmp_file);
cleanup();
return (1);
}
(void) close(list_fd);
(void) unlink(tmp_file);
return (0);
}
static int
ckoverwrite(char *dir, char *inst, int options)
{
char path[PATH_MAX];
(void) snprintf(path, sizeof (path), "%s/%s", dir, inst);
if (access(path, 0) == 0) {
if (options & PT_OVERWRITE)
return (rrmdir(path));
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_EXISTS), path);
return (1);
}
return (0);
}
static int
pkgxfer(char *srcinst, int options)
{
int r;
struct pkginfo info;
FILE *fp, *pp;
char *pt, *src, *dst;
char dstdir[PATH_MAX], temp[PATH_MAX], srcdir[PATH_MAX];
char cmd[CMDSIZE], pkgname[NON_ABI_NAMELNGTH];
int i, n, part, nparts, maxpartsize, curpartcnt, iscomp;
char volnos[128], tmpvol[128];
struct statvfs64 svfsb;
longlong_t free_blocks;
struct stat srcstat;
info.pkginst = NULL;
src = srcdev.dirname;
dst = dstdev.dirname;
if (!(options & PT_SILENT))
(void) fprintf(stderr, pkg_gt(MSG_TRANSFER), srcinst);
(void) strlcpy(dstinst, srcinst, sizeof (dstinst));
if (!(options & PT_ODTSTREAM)) {
(void) snprintf(dstdir, sizeof (dstdir),
"%s/%s", dst, dstinst);
pkgdir = src;
if (fpkginfo(&info, srcinst)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOEXISTS), srcinst);
(void) fpkginfo(&info, NULL);
return (1);
}
pkgdir = dst;
(void) strlcpy(temp, srcinst, sizeof (temp));
if (pt = strchr(temp, '.'))
*pt = '\0';
(void) strlcat(temp, ".*", sizeof (temp));
if (pt = fpkginst(temp, info.arch, info.version)) {
if (options & PT_OVERWRITE) {
(void) strlcpy(dstinst, pt, sizeof (dstinst));
(void) snprintf(dstdir, sizeof (dstdir),
"%s/%s", dst, dstinst);
} else {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_DUPVERS), srcinst);
(void) fpkginfo(&info, NULL);
(void) fpkginst(NULL);
return (2);
}
} else if (options & PT_RENAME) {
if (pt = strchr(temp, '.'))
*pt = '\0';
for (i = 2; (access(dstdir, 0) == 0); i++) {
(void) snprintf(dstinst, sizeof (dstinst),
"%s.%d", temp, i);
(void) snprintf(dstdir, sizeof (dstdir),
"%s/%s", dst, dstinst);
}
} else if (options & PT_OVERWRITE) {
options &= (~PT_OVERWRITE);
}
(void) fpkginfo(&info, NULL);
(void) fpkginst(NULL);
if (ckoverwrite(dst, dstinst, options))
return (2);
if (isdir(dstdir) && mkdir(dstdir, 0755)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MKDIR), dstdir);
return (1);
}
(void) snprintf(srcdir, sizeof (srcdir),
"%s/%s", src, srcinst);
if (stat(srcdir, &srcstat) != -1) {
if (chmod(dstdir, (srcstat.st_mode & S_IAMB)) == -1) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHMODDIR), dstdir);
return (1);
}
} else {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_STATDIR), srcdir);
return (1);
}
}
if (!(options & PT_SILENT) && strcmp(dstinst, srcinst))
(void) fprintf(stderr, pkg_gt(MSG_RENAME), dstinst);
(void) snprintf(srcdir, sizeof (srcdir), "%s/%s", src, srcinst);
if (chdir(srcdir)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHDIR), srcdir);
return (1);
}
if (ids_name) {
(void) snprintf(cmd, sizeof (cmd),
"%s -pudm %s", CPIOPROC, dstdir);
if ((pp = epopen(cmd, "w")) == NULL) {
rpterr();
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_POPEN), cmd, errno);
return (1);
}
(void) fprintf(pp, "%s\n%s\n", PKGINFO, PKGMAP);
(void) sighold(SIGINT);
(void) sighold(SIGHUP);
r = epclose(pp);
(void) sigrelse(SIGINT);
(void) sigrelse(SIGHUP);
if (r != 0) {
rpterr();
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_PCLOSE), cmd, errno);
return (1);
}
if (options & PT_INFO_ONLY)
return (0);
if (chdir(dstdir)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHDIR), dstdir);
return (1);
}
nparts = ds_findpkg(srcdev.cdevice, srcinst);
if (nparts < 0) {
progerr(pkg_gt(ERR_TRANSFER));
return (1);
}
for (part = 1; part <= nparts; ) {
if (ds_getpkg(srcdev.cdevice, part, dstdir)) {
progerr(pkg_gt(ERR_TRANSFER));
return (1);
}
part++;
if (dstdev.mount) {
(void) chdir("/");
if (pkgumount(&dstdev))
return (1);
if (part <= nparts) {
if (n = pkgmount(&dstdev, NULL, part+1,
nparts, 1))
return (n);
if (ckoverwrite(dst, dstinst, options))
return (1);
if (isdir(dstdir) &&
mkdir(dstdir, 0755)) {
progerr(
pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MKDIR),
dstdir);
return (1);
}
if (chdir(srcdir)) {
progerr(
pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHDIR),
srcdir);
return (1);
}
if ((pp = epopen(cmd, "w")) == NULL) {
rpterr();
progerr(
pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_POPEN),
cmd, errno);
return (1);
}
(void) fprintf(pp, "pkginfo");
(void) sighold(SIGINT);
(void) sighold(SIGHUP);
r = epclose(pp);
(void) sigrelse(SIGINT);
(void) sigrelse(SIGHUP);
if (r != 0) {
rpterr();
progerr(
pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_PCLOSE),
cmd, errno);
return (1);
}
if (chdir(dstdir)) {
progerr(
pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CHDIR),
dstdir);
return (1);
}
}
}
}
return (0);
}
if ((fp = fopen(PKGMAP, "r")) == NULL) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOPKGMAP), srcinst);
return (1);
}
nparts = 1;
if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize))
return (1);
else
(void) fclose(fp);
if (srcdev.mount) {
if (ckvolseq(srcdir, 1, nparts)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_SEQUENCE));
return (1);
}
}
if (options & PT_ODTSTREAM) {
char line[128];
(void) mgets(line, 128);
curpartcnt = -1;
if (sscanf(line, "%s %d %d %[ 0-9]", pkgname, &nparts,
&maxpartsize, volnos) == 4) {
(void) sscanf(volnos,
"%d %[ 0-9]", &curpartcnt, tmpvol);
(void) strlcpy(volnos, tmpvol, sizeof (volnos));
}
}
for (part = 1; part <= nparts; ) {
if (curpartcnt == 0 && (options & PT_ODTSTREAM)) {
char prompt[128];
int index;
ds_volno++;
(void) ds_close(0);
(void) sprintf(prompt,
pkg_gt("Insert %%v %d of %d into %%p"),
ds_volno, ds_volcnt);
if (n = getvol(ods_name, NULL, DM_FORMAT, prompt))
return (n);
if ((ds_fd = open(dstdev.cdevice, O_WRONLY)) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN), dstdev.cdevice,
errno);
return (1);
}
if (ds_ginit(dstdev.cdevice) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN), dstdev.cdevice,
errno);
(void) ds_close(0);
return (1);
}
(void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol);
(void) strlcpy(volnos, tmpvol, sizeof (volnos));
curpartcnt += index;
}
if (options & PT_INFO_ONLY)
nparts = 0;
if (part == 1) {
(void) snprintf(cmd, sizeof (cmd),
"find %s %s", PKGINFO, PKGMAP);
if (nparts && (isdir(INSTALL) == 0)) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, INSTALL, sizeof (cmd));
}
} else
(void) snprintf(cmd, sizeof (cmd), "find %s", PKGINFO);
if (nparts > 1) {
(void) snprintf(temp, sizeof (temp),
"%s.%d", RELOC, part);
if (iscpio(temp, &iscomp) || isdir(temp) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, temp, sizeof (cmd));
}
(void) snprintf(temp, sizeof (temp),
"%s.%d", ROOT, part);
if (iscpio(temp, &iscomp) || isdir(temp) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, temp, sizeof (cmd));
}
(void) snprintf(temp, sizeof (temp),
"%s.%d", ARCHIVE, part);
if (isdir(temp) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, temp, sizeof (cmd));
}
} else if (nparts) {
for (i = 0; reloc_names[i] != NULL; i++) {
if (iscpio(reloc_names[i], &iscomp) ||
isdir(reloc_names[i]) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, reloc_names[i],
sizeof (cmd));
}
}
for (i = 0; root_names[i] != NULL; i++) {
if (iscpio(root_names[i], &iscomp) ||
isdir(root_names[i]) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, root_names[i],
sizeof (cmd));
}
}
if (isdir(ARCHIVE) == 0) {
(void) strlcat(cmd, " ", sizeof (cmd));
(void) strlcat(cmd, ARCHIVE, sizeof (cmd));
}
}
if (options & PT_ODTSTREAM) {
(void) snprintf(cmd + strlen(cmd),
sizeof (cmd) - strlen(cmd),
" -print | %s -ocD -C %d",
CPIOPROC, (int)BLK_SIZE);
} else {
if (statvfs64(dstdir, &svfsb) == -1) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_STATVFS), dstdir, errno);
return (1);
}
free_blocks = (((long)svfsb.f_frsize > 0) ?
howmany(svfsb.f_frsize, DEV_BSIZE) :
howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail;
if ((has_comp_size ? compressedsize : maxpartsize) >
free_blocks) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_NOSPACE),
has_comp_size ?
(long)compressedsize : (long)maxpartsize,
free_blocks);
return (1);
}
(void) snprintf(cmd + strlen(cmd),
sizeof (cmd) - strlen(cmd),
" -print | %s -pdum %s",
CPIOPROC, dstdir);
}
n = esystem(cmd, -1, (options & PT_ODTSTREAM) ? ds_fd : -1);
if (n) {
rpterr();
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CMDFAIL), cmd, n);
return (1);
}
part++;
if (srcdev.mount && (nparts > 1)) {
(void) chdir("/");
if (pkgumount(&srcdev))
return (1);
while (part <= nparts) {
n = pkgmount(&srcdev, NULL, part, nparts, 1);
if (n)
return (n);
if (chdir(srcdir)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_CORRUPT));
(void) chdir("/");
(void) pkgumount(&srcdev);
continue;
}
if (ckvolseq(srcdir, part, nparts)) {
(void) chdir("/");
(void) pkgumount(&srcdev);
continue;
}
break;
}
}
if (!(options & PT_ODTSTREAM) && dstdev.mount) {
if (pkgumount(&dstdev))
return (1);
while (part <= nparts) {
n = pkgmount(&dstdev, NULL, part, nparts, 1);
if (n)
return (n);
if (ckoverwrite(dst, dstinst, options))
continue;
if (isdir(dstdir) && mkdir(dstdir, 0755)) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_MKDIR), dstdir);
continue;
}
break;
}
}
if ((options & PT_ODTSTREAM) && part <= nparts) {
if (curpartcnt >= 0 && part > curpartcnt) {
char prompt[128];
int index;
ds_volno++;
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(ods_name, NULL, DM_FORMAT,
prompt))
return (n);
if ((ds_fd = open(dstdev.cdevice, 1)) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN),
dstdev.cdevice, errno);
return (1);
}
if (ds_ginit(dstdev.cdevice) < 0) {
progerr(pkg_gt(ERR_TRANSFER));
logerr(pkg_gt(MSG_OPEN),
dstdev.cdevice, errno);
(void) ds_close(0);
return (1);
}
(void) sscanf(volnos, "%d %[ 0-9]", &index,
tmpvol);
(void) strlcpy(volnos, tmpvol, sizeof (volnos));
curpartcnt += index;
}
}
}
return (0);
}
static void
sigtrap(int signo)
{
_NOTE(ARGUNUSED(signo));
signal_received++;
}
static void
cleanup(void)
{
(void) chdir("/");
if (tmpdir) {
(void) rrmdir(tmpdir);
free(tmpdir);
tmpdir = NULL;
}
if (tmppath) {
(void) rrmdir(tmppath);
free(tmppath);
tmppath = NULL;
}
if (tmpsymdir) {
(void) rrmdir(tmpsymdir);
free(tmpsymdir);
tmpsymdir = NULL;
}
if (srcdev.mount && !ids_name)
(void) pkgumount(&srcdev);
if (dstdev.mount && !ods_name)
(void) pkgumount(&dstdev);
(void) ds_close(1);
}