create.c revision a272125655938e902d5c7d99d182d3b1e35f70eb
/*
* 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.
*/
#include <signal.h>
#include <unistd.h>
#include "bart.h"
#include <aclutils.h>
static void output_manifest(void);
static char *sanitized_fname(const char *, boolean_t);
int *err_code);
/*
* The following globals are necessary due to the "walker" function
* provided by nftw(). Since there is no way to pass them through to the
* walker function, they must be global.
*/
static struct rule *subtree_root;
static char reloc_root[PATH_MAX];
static struct statvfs64 parent_vfs;
int
{
reloc_root[0] = '\0';
switch (c) {
case 'I':
usage();
}
break;
case 'n':
compute_chksum = 0;
break;
case 'r':
else
usage();
}
break;
case 'R':
sizeof (reloc_root));
if (ret == 0)
usage();
break;
case '?':
default :
usage();
}
}
if (pipe(output_pipe) < 0) {
perror("");
}
if (pid < 0) {
}
/*
* Break the creation of a manifest into two parts: the parent process
* generated the data whereas the child process sorts the data.
*
* The processes communicate through the pipe.
*/
if (pid > 0) {
/*
* Redirect the stdout of this process so it goes into
* output_pipe[0]. The output of this process will be read
* by the child, which will sort the output.
*/
}
(void) close(output_pipe[0]);
if (filelist_input == B_TRUE) {
} else {
}
/* Close stdout so the sort in the child proc will complete */
} else {
/*
* Redirect the stdin of this process so its read in from
* the pipe, which is the parent process in this case.
*/
}
(void) close(output_pipe[0]);
}
/* Wait for the child proc (the sort) to complete */
(void) wait(0);
return (ret);
}
/*
* Handle the -R option and sets 'root' to be the absolute path of the
* relocatable root. This is useful when the user specifies '-R ../../foo'.
*
* Return code is whether or not the location spec'd by the -R flag is a
* directory or not.
*/
static int
{
/*
* First, save the current directory and go to the location
* specified with the -R option.
*/
/* Failed to change directory, something is wrong.... */
return (0);
}
/*
* Save the absolute path of the relocatable root directory.
*/
/*
* Now, go back to where we started, necessary for picking up a rules
* file.
*/
/* Failed to change directory, something is wrong.... */
return (0);
}
/*
* Make sure the path returned does not have a trailing /. This
* can only happen when the entire pathname is "/".
*/
root[0] = '\0';
/*
* Since the earlier chdir() succeeded, return success.
*/
return (1);
}
/*
* This is the worker bee which creates the manifest based upon the command
* line options supplied by the user.
*
* NOTE: create_manifest() eventually outputs data to a pipe, which is read in
* by the child process. The child process is running output_manifest(), which
* is responsible for generating sorted output.
*/
static int
{
int ret_status = EXIT;
if (compute_chksum)
else
flags = 0;
/* Loop through every single subtree */
/*
* Check to see if this subtree should have contents
* checking turned on or off.
*
* NOTE: The 'compute_chksum' and 'parent_vfs'
* are a necessary hack: the variables are used in
* walker(), both directly and indirectly. Since
* the parameters to walker() are defined by nftw(),
* the globals are really a backdoor mechanism.
*/
if (ret_status < 0) {
continue;
}
/*
* Walk the subtree and invoke the callback function
* walker()
*/
subtree_root = root;
/*
* Ugly but necessary:
*
* walker() must return 0, or the tree walk will stop,
* so warning flags must be set through a global.
*/
if (eval_err == WARNING_EXIT)
}
return (ret_status);
}
static int
{
int ret_status = EXIT;
char input_fname[PATH_MAX];
int ret;
if (ret < 0) {
} else {
if (ret == WARNING_EXIT)
}
}
return (ret_status);
}
/*
* output_manifest() the child process. It reads in the output from
* create_manifest() and sorts it.
*/
static void
output_manifest(void)
{
char time_buf[1024];
/*
* Simply run sort and read from the the current stdin, which is really
* the output of create_manifest().
* Also, make sure the output is unique, since a given file may be
* included by several stanzas.
*/
perror("");
}
/*NOTREACHED*/
}
/*
* Callback function for nftw()
*/
static int
{
int ret;
switch (type) {
case FTW_F: /* file */
compute_chksum = 1;
else
compute_chksum = 0;
}
break;
case FTW_SL: /* symbolic link */
case FTW_DP: /* end of directory */
case FTW_DNR: /* unreadable directory */
case FTW_NS: /* unstatable file */
break;
case FTW_D: /* enter directory */
if (ret < 0)
break;
default:
break;
}
/* This is the function which really processes the file */
/*
* Since the parameters to walker() are constrained by nftw(),
* need to use a global to reflect a WARNING. Sigh.
*/
if (ret == WARNING_EXIT)
/*
* This is a case of a directory which crosses into a mounted
* filesystem of a different type, e.g., UFS -> NFS.
* BART should not walk the new filesystem (by specification), so
* set this consolidation-private flag so the rest of the subtree
* under this directory is not waled.
*/
if (dir_flag &&
return (0);
}
/*
* This file does the per-file evaluation and is run to generate every entry
* in the manifest.
*
* All output is written to a pipe which is read by the child process,
* which is running output_manifest().
*/
static int
{
char *quoted_name;
/* Regular file */
/* Directory */
/* Block Device */
/* Character Device */
/* Named Pipe */
/* Socket */
/* Door */
/* Symbolic link */
default: ftype = '-'; break;
}
/* First, make sure this file should be cataloged */
if ((subtree_root != NULL) &&
return (err_code);
for (i = 0; i < PATH_MAX; i++)
last_field[i] = '\0';
/*
* Regular files, compute the MD5 checksum and put it into 'last_field'
* UNLESS instructed to ignore the checksums.
*/
if (ftype == 'F') {
if (compute_chksum) {
if (fd < 0) {
/* default value since the computution failed */
} else {
fname);
}
}
}
/* Instructed to ignore checksums, just put in a '-' */
else
}
/*
* For symbolic links, put the destination of the symbolic link into
* 'last_field'
*/
if (ftype == 'L') {
if (ret < 0) {
/* default value since the computation failed */
}
else
(void) strlcpy(last_field,
sizeof (last_field));
/*
* Boundary condition: possible for a symlink to point to
* nothing [ ln -s '' link_name ]. For this case, set the
* destination to "\000".
*/
if (strlen(last_field) == 0)
}
/* Sanitize 'fname', so its in the proper format for the manifest */
/* Start to build the entry.... */
/* Finish it off based upon whether or not it's a device node */
else if (strlen(last_field) > 0)
else
(void) printf("\n");
/* free the memory consumed */
return (err_code);
}
/*
* When creating a manifest, make sure all '?', tabs, space, newline, '/'
* and '[' are all properly quoted. Convert them to a "\ooo" where the 'ooo'
* represents their octal value. For filesystem objects, as opposed to symlink
* targets, also canonicalize the pathname.
*/
static char *
{
const char *ip;
unsigned char ch;
char *op, *quoted_name;
/* Initialize everything */
op = quoted_name;
if (canon_path) {
/*
* In the case when a relocatable root was used, the relocatable
* root should *not* be part of the manifest.
*/
/*
* In the case when the '-I' option was used, make sure
* the quoted_name starts with a '/'.
*/
if (*ip != '/')
*op++ = '/';
}
/* Now walk through 'fname' and build the quoted string */
switch (ch) {
/* Quote the following characters */
case ' ':
case '*':
case '\n':
case '?':
case '[':
case '\\':
case '\t':
break;
/* Otherwise, simply append them */
default:
break;
}
}
*op = 0;
return (quoted_name);
}
/*
* Function responsible for generating the ACL information for a given
* file. Note, the string is put into buffer malloc'd by this function.
* It's the responsibility of the caller to free the buffer. This function
* should never return a NULL pointer.
*/
static char *
{
char *acltext;
int error;
return (safe_strdup("-"));
}
/*
* Include trivial acl's
*/
if (error != 0) {
*err_code = WARNING_EXIT;
return (safe_strdup("-"));
} else {
return (safe_strdup("-"));
else
return (acltext);
}
}
/*
*
* description: This routine reads stdin in BUF_SIZE chunks, uses the bits
* to update the md5 hash buffer, and outputs the chunks
* to stdout. When stdin is exhausted, the hash is computed,
* converted to a hexadecimal string, and returned.
*
* returns: The md5 hash of stdin, or NULL if unsuccessful for any reason.
*/
static int
{
unsigned char hash[MD5_DIGEST_LENGTH];
int i, amtread;
for (;;) {
if (amtread == 0)
break;
if (amtread < 0)
return (1);
/* got some data. Now update hash */
}
/* done passing through data, calculate hash */
for (i = 0; i < MD5_DIGEST_LENGTH; i++)
return (0);
}
/*
* Used by 'bart create' with the '-I' option. Return each entry into a 'buf'
* with the appropriate exit code: '0' for success and '-1' for failure.
*/
static int
{
static int argv_index = -1;
char *cp;
/*
* INITIALIZATION:
* Setup this code so it knows whether or not to read sdtin.
* Also, if reading from argv, setup the index, "argv_index"
*/
if (argv_index == -1) {
argv_index = 0;
/* In this case, no args after '-I', so read stdin */
}
buf[0] = '\0';
if (read_stdinput) {
return (-1);
} else {
}
return (-1);
/*
* Unlike similar code elsewhere, avoid adding a leading
* slash for relative pathnames.
*/
reloc_root, cp);
return (0);
}