/*
* 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
* 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 <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/sysmacros.h>
#include <dirent.h>
#include <signal.h>
#include <devmgmt.h>
#include "pkginfo.h"
#include "pkgstrct.h"
#include "pkgtrans.h"
#include "pkgdev.h"
#include "pkglib.h"
#include "pkglibmsgs.h"
#include "keystore.h"
#include "pkglocale.h"
#include "pkgerr.h"
extern char *pkgdir; /* pkgparam.c */
/* libadm.a */
char *norewind);
/* dstream.c */
static char *tmpdir;
static char *tmppath;
static int ds_volcnt;
static int ds_volno;
static void (*sigintHandler)();
static void (*sighupHandler)();
static void cleanup(void);
static int cat_and_count(struct dm_buf *, char *);
extern int ds_fd; /* open file descriptor for data stream WHERE? */
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;
int nxpkg;
static char *allpkg[] = {
"all",
};
int
{
char *pt;
int n;
cleanup();
return (0);
return (0);
return (0);
}
/* check for datastream */
cleanup();
return (n);
}
/* pkgtrans has set pkgdir */
return (0);
}
static char *
{
if (nextpinput == NULL)
return (0);
*nextpinput = '\0';
return (0);
return (buf);
}
/*
* Here we construct the package size summaries for the headers. The
* pkgmap file associated with fp must be rewound to the beginning of the
* file. Note that we read three values from pkgmap first line in order
* to get the *actual* size if this package is compressed.
* This returns
* 0 : error
* 2 : not a compressed package
* 3 : compressed package
* and sets has_comp_size to indicate whether or not this is a compressed
* package.
*/
static int
{
int n;
/* First read the null terminated first line */
ecleanup();
return (0);
}
if (n == 3) /* A valid compressed package entry */
has_comp_size = 1;
else if (n == 2) /* A valid standard package entry */
has_comp_size = 0;
else { /* invalid entry */
ecleanup();
return (0);
}
return (n);
}
/* will return 0, 1, 3, or 99 */
static int
{
int errflg, i, n;
if (making_sig) {
/* new error object */
err = pkgerr_new();
/* find matching cert and key */
return (1);
}
/* get CA certificates */
return (1);
}
/* get CL (aka "chain") certificates */
return (1);
}
/* initialize PKCS7 object to be filled in later */
if (sec_signerinfo == NULL) {
return (1);
}
/* add signer cert into signature */
/* attempt to resolve cert chain starting at the signer cert */
&sec_chain) != 0) {
return (1);
}
/*
* add the verification chain of certs into the signature.
* The first cert is the user cert, which we don't need,
* since it's baked in already, so skip it
*/
sk_X509_value(sec_chain, i));
}
}
if (signal_received > 0) {
return (1);
}
/* transfer spool to appropriate device */
return (1);
}
/* check for datastream */
cleanup();
if (n == 3)
return (3);
return (1);
}
}
return (1);
}
}
cleanup();
return (n);
}
return (0);
}
return (1);
}
return (1);
}
}
return (1);
}
return (1);
}
options |= PT_ODTSTREAM;
if (options & PT_ODTSTREAM) {
return (1);
}
if (ids_name) {
return (1);
}
} else {
/*
* output device isn't a stream. If we're making a signed
* package, then fail, since we can't make signed,
* non-stream pkgs
*/
if (making_sig) {
return (1);
}
}
return (1);
}
return (1);
}
if (signal_received > 0) {
return (1);
}
if (ids_name) {
cleanup();
if (n == 3)
return (3);
return (1);
}
cleanup();
return (1);
}
cleanup();
return (1);
}
cleanup();
return (n);
}
}
cleanup();
return (1);
}
if (signal_received > 0) {
return (1);
}
if (!pkg) {
cleanup();
return (1);
}
nxpkg++; /* count */
}
if (ids_name) {
}
if (signal_received > 0) {
return (1);
}
if (options & PT_ODTSTREAM) {
cleanup();
if (n == 3)
return (3);
return (1);
}
cleanup();
return (1);
}
if (making_sig) {
/* start up signature data stream */
/*
* Here we generate all the data that will go into
* the package, and send it through the signature
* generator, essentially calculating the signature
* of the entire package so we can place it in the
* header. Otherwise we'd have to place it at the end
* of the pkg, which would break the ABI
*/
}
cleanup();
return (1);
}
/*
* now generate PKCS7 signature
*/
cleanup();
return (1);
}
}
/* write out header to stream, which includes signature */
cleanup();
return (1);
}
/* nuke in-memory signature for safety */
}
/* skip past first line in header */
}
if (signal_received > 0) {
return (1);
}
errflg = 0;
for (i = 0; pkg[i]; i++) {
if (signal_received > 0) {
return (1);
}
cleanup();
return (n);
}
}
break;
}
}
/*
* No cleanup of temporary directories created in this
* function is done here. The calling function must do
* the cleanup.
*/
}
int
{
int r;
/*
* setup signal handlers for SIGINT and SIGHUP and release hold
*/
/* hook SIGINT to sigtrap */
} else {
}
/* hook SIGHUP to sigtrap */
} else {
}
/* reset signal received count */
signal_received = 0;
/* release hold on signals */
/*
* perform the package translation
*/
/*
* reset signal handlers
*/
/* reset SIGINT */
/* reset SIGHUP */
/* if signal received and pkgtrans returned error, call cleanup */
if (signal_received > 0) {
if (r != 0) {
cleanup();
}
}
/* release hold on signals */
return (r);
}
/*
* This function concatenates append to the text described in the buf_ctrl
* structure. This code modifies data in this structure and handles all
* allocation issues. It returns '0' if everything was successful and '1'
* if not.
*/
static int
{
/* keep allocating until we have enough room to hold string */
>= buf_ctrl->allocation) {
/* reallocate (and maybe move) text buffer */
if ((buf_ctrl->text_buffer =
return (1);
}
/* clear the new memory */
/* adjust total allocation */
}
/* append new string to end of buffer */
while (*append) {
}
return (0);
}
static struct dm_buf *
{
return (NULL);
}
/* clear the new memory */
/* set up the buffer control structure for the header */
totsize = 0;
for (i = 0; pkg[i]; i++) {
ecleanup();
return (NULL);
}
}
/*
* totsize contains number of blocks used by the pkginfo files
*/
ecleanup();
return (NULL);
}
ds_volcnt = 1;
for (i = 0; pkg[i]; i++) {
partcnt = 0;
ecleanup();
return (NULL);
}
/* Evaluate the first entry in pkgmap */
if (n == 3) /* It's a compressed package */
/* The header needs the *real* size */
else if (n == 0) /* pkgmap is corrupt */
return (NULL);
ecleanup();
return (NULL);
}
/* add pkg name, number of parts and the max part size */
ecleanup();
return (NULL);
}
ecleanup();
return (NULL);
}
int lastpartcnt = 0;
#if 0
if (i != 0) {
ecleanup();
return (NULL);
}
#endif /* 0 */
if (totsize)
partcnt++;
}
/* partcnt == 0 means skip to next volume */
if (partcnt)
partcnt--;
ecleanup();
return (NULL);
}
ds_volcnt++;
totsize = 0;
}
ds_volcnt--;
}
ecleanup();
return (NULL);
}
}
ecleanup();
return (NULL);
}
return (&hdrbuf);
}
static int
{
int i, n;
int list_fd;
int block_cnt;
int len;
(void) ds_close(0);
else
if (ds_fd < 0) {
return (1);
}
(void) ds_close(0);
return (1);
}
/*
* The loop below assures compatibility with tapes that don't
* have a block size (e.g.: Exabyte) by forcing EOR at the end
* of each 512 bytes.
*/
}
/*
* write the first cpio() archive to the datastream
* which should contain the pkginfo & pkgmap files
* for all packages
*/
return (1);
}
/*
* Create a cpio-compatible list of the requisite files in
* the temporary file.
*/
if (!making_sig) {
for (i = 0; pkg[i]; i++) {
/*
* Copy pkginfo and pkgmap filenames into the
* temporary string allowing for the first line
* as a special case.
*/
(i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s",
entry_size) != entry_size) {
ecleanup();
return (1);
}
}
} else {
/*
* if we're making a signature, we must make a
* temporary area full of symlinks to the requisite
* files, plus an extra entry for the signature, so
* that cpio will put all files and signature in the
* same archive in a single invocation of cpio.
*/
return (1);
}
/* generate the signature */
len < 0) {
cleanup();
return (1);
}
cleanup();
return (1);
}
for (i = 0; pkg[i]; i++) {
cleanup();
return (1);
}
cleanup();
return (1);
}
cleanup();
return (1);
}
/*
* Copy pkginfo and pkgmap filenames into the
* temporary string allowing for the first line
* as a special case.
*/
(i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s",
entry_size) != entry_size) {
ecleanup();
cleanup();
return (1);
}
}
/* add signature to list of files */
ecleanup();
cleanup();
return (1);
}
}
if (!making_sig) {
#ifndef SUNOS41
#else
#endif
} else {
/*
* when making a signature, we must make sure to follow
* symlinks during the cpio so that we don't archive
* the links themselves
*/
#ifndef SUNOS41
#else
#endif
}
if (making_sig) {
/* save cwd and change to symlink dir for cpio invocation */
cleanup();
return (1);
}
cleanup();
return (1);
}
}
rpterr();
cleanup();
return (1);
}
if (making_sig) {
/* change to back to src dir for subsequent operations */
cleanup();
return (1);
}
}
return (0);
}
static int
{
if (options & PT_OVERWRITE)
return (1);
}
return (0);
}
static int
{
int r;
/*
* when this routine is entered, the first part of
* the package to transfer is already available in
* the directory indicated by 'src' --- unless the
* source device is a datstream, in which case only
* the pkginfo and pkgmap files are available in 'src'
*/
if (!(options & PT_ODTSTREAM)) {
/* destination is a (possibly mounted) directory */
/*
* need to check destination directory to assure
* that we will not be duplicating a package which
* already resides there (though we are allowed to
* overwrite the same version)
*/
return (1);
}
*pt = '\0';
/*
* the same instance already exists, although
* its pkgid might be different
*/
if (options & PT_OVERWRITE) {
} else {
return (2);
}
/*
* find next available instance by appending numbers
* to the package abbreviation until the instance
* does not exist in the destination directory
*/
*pt = '\0';
}
} else if (options & PT_OVERWRITE) {
/*
* we're allowed to overwrite, but there seems
* to be no valid package to overwrite, and we are
* not allowed to rename the destination, so act
* as if we weren't given permission to overwrite
* --- this keeps us from removing a destination
* instance which is named the same as the source
* instance, but really reflects a different pkg!
*/
options &= (~PT_OVERWRITE);
}
return (2);
return (1);
}
return (1);
}
} else {
return (1);
}
}
return (1);
}
if (ids_name) { /* unpack the datatstream into a directory */
/*
* transfer pkginfo & pkgmap first
*/
rpterr();
return (1);
}
if (r != 0) {
rpterr();
return (1);
}
if (options & PT_INFO_ONLY)
return (0); /* don't transfer objects */
return (1);
}
/*
* for each part of the package, use cpio() to
* unpack the archive into the destination directory
*/
if (nparts < 0) {
return (1);
}
return (1);
}
part++;
(void) chdir("/");
return (1);
nparts, 1))
return (n);
return (1);
dstdir);
return (1);
}
/*
* since volume is removable, each part
* must contain a duplicate of the
* pkginfo file to properly identify the
* volume
*/
srcdir);
return (1);
}
rpterr();
return (1);
}
if (r != 0) {
rpterr();
return (1);
}
dstdir);
return (1);
}
}
}
}
return (0);
}
return (1);
}
nparts = 1;
return (1);
else
return (1);
}
}
/* write each part of this package */
if (options & PT_ODTSTREAM) {
curpartcnt = -1;
}
}
int index;
ds_volno++;
(void) ds_close(0);
pkg_gt("Insert %%v %d of %d into %%p"),
return (n);
errno);
return (1);
}
errno);
(void) ds_close(0);
return (1);
}
curpartcnt += index;
}
if (options & PT_INFO_ONLY)
nparts = 0;
if (part == 1) {
}
} else
if (nparts > 1) {
}
}
}
} else if (nparts) {
for (i = 0; reloc_names[i] != NULL; i++) {
isdir(reloc_names[i]) == 0) {
}
}
for (i = 0; root_names[i] != NULL; i++) {
isdir(root_names[i]) == 0) {
}
}
}
}
if (options & PT_ODTSTREAM) {
#ifndef SUNOS41
" -print | %s -ocD -C %d",
#else
" -print | %s -oc -C %d",
#endif
} else {
return (1);
}
free_blocks) {
return (1);
}
}
if (n) {
rpterr();
return (1);
}
part++;
/* unmount current source volume */
(void) chdir("/");
return (1);
/* loop until volume is mounted successfully */
/* read only */
if (n)
return (n);
(void) chdir("/");
continue;
}
(void) chdir("/");
continue;
}
break;
}
}
/* unmount current volume */
return (1);
/* loop until next volume is mounted successfully */
/* writable */
if (n)
return (n);
continue;
continue;
}
break;
}
}
int index;
ds_volno++;
if (ds_close(0))
return (1);
pkg_gt("Insert %%v %d of %d into %%p"),
prompt))
return (n);
return (1);
}
(void) ds_close(0);
return (1);
}
tmpvol);
curpartcnt += index;
}
}
}
return (0);
}
/*
* Name: pkgdump
* Description: Dump a cpio archive of a package's contents to a BIO.
*
* Arguments: srcinst - Name of package, which resides on the
* device pointed to by the static 'srcdev' variable,
* to dump.
* bio - BIO object to dump data to
*
* Returns : 0 - success
* nonzero - failure. errors printed to screen.
*/
static int
{
char *src;
/*
* when this routine is entered, the entire package
* is already available at 'src' - including the
*/
/* read the pkgmap to get it's size information */
return (1);
}
nparts = 1;
return (1);
else
/* make sure the first volume is available */
return (1);
}
}
/*
* form cpio command that will output the contents of all of
* this package's parts
*/
if (part == 1) {
}
} else
if (nparts > 1) {
}
}
}
} else if (nparts) {
for (i = 0; reloc_names[i] != NULL; i++) {
isdir(reloc_names[i]) == 0) {
CMDSIZE);
}
}
for (i = 0; root_names[i] != NULL; i++) {
isdir(root_names[i]) == 0) {
CMDSIZE);
}
}
}
}
#ifndef SUNOS41
" -print | %s -ocD -C %d",
#else
" -print | %s -oc -C %d",
#endif
/*
* execute the command, dumping all standard output
* to the BIO.
*/
if (n != 0) {
rpterr();
return (1);
}
part++;
}
return (0);
}
static void
{
}
static void
cleanup(void)
{
chdir("/");
if (tmpdir) {
}
if (tmppath) {
/* remove any previous tmppath stuff */
}
if (tmpsymdir) {
/* remove temp symbolic links made for signed pkg */
}
(void) ds_close(1);
}
/*
* Name: dump_hdr_and_pkgs
* Description: Dumps datastream header and each package's contents
* to the supplied BIO
*
* Arguments: bio - BIO object to dump data to
* hdr - Header for the datastream being dumped
* pkglist - NULL-terminated list of packages
* to dump. The location of the packages are stored
* in the static 'srcdev' variable.
*
* Returns : 0 - success
* nonzero - failure. errors printed to screen.
*/
static int
{
int block_cnt, i;
char *src;
/* write out the header to the signature stream */
}
/* save current directory */
return (1);
}
/* now write out each package's contents */
for (i = 0; pkglist[i]; i++) {
/*
* change to the source dir, so we can find and dump
* the package(s) bits into the BIO
*
*/
/* change to the package source directory */
return (1);
}
return (1);
}
}
/* change back to directory we were in upon entering this routine */
return (1);
}
return (0);
}
/*
* Name: BIO_dump_cmd
* Description: Dump the output of invoking a command
* to a BIO.
*
* Arguments: cmd - Command to invoke
* bio - BIO to dump output of command to
* only 'stdout' is dumped.
* Returns : 0 - success
* nonzero - failure. errors printed to screen.
*/
int
{
int rc;
/* start up the process */
rpterr();
return (1);
}
/* read output in chunks, transfer to BIO */
rpterr();
return (1);
}
}
/* done with stream, make sure no errors were encountered */
rpterr();
return (1);
}
/* done, close stream, report any errors */
if (rc != 0) {
rpterr();
return (1);
}
return (rc);
}