98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv/*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * CDDL HEADER START
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * The contents of this file are subject to the terms of the
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Common Development and Distribution License (the "License").
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * You may not use this file except in compliance with the License.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * or http://www.opensolaris.org/os/licensing.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * See the License for the specific language governing permissions
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * and limitations under the License.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * When distributing Covered Code, include this CDDL HEADER in each
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * If applicable, add the following below this CDDL HEADER, with the
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * fields enclosed by brackets "[]" replaced with your own identifying
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * information: Portions Copyright [yyyy] [name of copyright owner]
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * CDDL HEADER END
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv/*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <stdio.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <strings.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <sys/stat.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <sys/types.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <sys/mount.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <sys/mntent.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv#include <unistd.h>
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv/*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * This program aids the Solaris 10 patch tools (specifically
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * /usr/lib/patch/patch_common_lib) in DAP patching.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Whenever the patch tools replace a critical system component (e.g.,
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * /lib/libc.so.1), they move the old component to a temporary location,
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * move the new component to where the old component was, and establish
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * an overlay mount of the old component on top of the new component.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * The patch tools do this with a shell script; consequently, the three
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * operations occur in three processes.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * This doesn't work inside Solaris 10 Containers (S10Cs). Suppose the
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * patch tools need to replace /lib/libc.so.1. The tools will move the old
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * libc.so.1 to a temporary location. But when they try to move the new
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * libc.so.1, they fork a mv(1) process, which loads the solaris10 brand's
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * emulation library. The emulation library will try to load the zone's
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * libc.so.1, but the library no longer exists; consequently, the emulation
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * library aborts and the zone's users won't be able to start any processes.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * This program solves the problem by combining the move and mount operations
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * into a single process. The emulation library will already have loaded
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * libc.so.1 for the process by the time the process starts to replace
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * libc.so.1.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * This program takes six parameters that correspond to six variables within
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * /usr/lib/patch/patch_common_lib:InstallSafemodeObject():
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[1] - dstActual (the path to the file that will be replaced)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[2] - tmp_file (the temporary location to which the file will be
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * moved)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[3] - tmpDst (the path to the replacement file)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[4] - tmpFile (the path to a temporary copy of the running system's
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * version of the file being replaced; the source [special] of
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * the overlay mount)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[5] - cksumTmpDst (checksum of the file represented by tmpDst)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * argv[6] - cksumTmpFile (checksum of the file represented by tmpFile)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * NOTE: This program will only establish an overlay mount if argv[4] or argv[5]
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * is emtpy or if argv[4] and argv[5] differ.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * This program returns zero when it succeeds. Non-negative values indicate
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * failure.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjvint
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjvmain(int argc, char **argv)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv{
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv struct stat statbuf;
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv char mntoptions[MAX_MNTOPT_STR];
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Check the number of arguments that were passed to s10_replacefile.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (argc != 7) {
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv (void) fprintf(stderr, "Usage: %s dstActual tmp_file tmpDst "
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv "tmpFile cksumTmpDst cksumTmpFile\n", argv[0]);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv return (1);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv }
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Move the destination file (dstActual) out of the way and move the
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * new file (tmpDst) into its place.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv *
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * NOTE: s10_replacefile won't print error messages here because
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * the Solaris 10 patch tools will.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (rename(argv[1], argv[2]) != 0)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv return (2);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (rename(argv[3], argv[1]) != 0)
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv return (3);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * If there was a lofs mount on dstActual (which we just moved), then
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * s10_replacefile should reestablish the lofs mount. A lofs mount
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * existed if tmpFile exists.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (stat(argv[4], &statbuf) == 0 && (statbuf.st_mode & S_IFREG)) {
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Create a lofs overlay mount only if the checksums of the
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * old file at dstActual and the new file at dstActual differ.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (argv[5][0] == '\0' || argv[6][0] == '\0' ||
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv strcmp(argv[5], argv[6]) != 0) {
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv mntoptions[0] = '\0';
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv if (mount(argv[4], argv[1], MS_OVERLAY | MS_OPTIONSTR,
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv MNTTYPE_LOFS, NULL, 0, mntoptions,
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv sizeof (mntoptions)) != 0) {
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * Although the patch tools will print error
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * messages, the tools won't know that
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * s10_replacefile failed to establish an
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * overlay mount. Printing an error message
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * here clarifies the problem for the user.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv (void) fprintf(stderr, "ERROR: Failed to "
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv "overlay mount %s onto %s\n", argv[4],
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv argv[1]);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv return (4);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv }
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv } else {
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv /*
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * dstActual does not need an overlay mount. Delete
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv * tmpFile.
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv */
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv (void) unlink(argv[4]);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv }
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv }
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv return (0);
98f4f4f656cf8a11e7013e69b0cc54f82fa9b79bjv}