1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <stdio.h>
27#include <strings.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <sys/mount.h>
31#include <sys/mntent.h>
32#include <unistd.h>
33
34/*
35 * This program aids the Solaris 10 patch tools (specifically
36 * /usr/lib/patch/patch_common_lib) in DAP patching.
37 *
38 * Whenever the patch tools replace a critical system component (e.g.,
39 * /lib/libc.so.1), they move the old component to a temporary location,
40 * move the new component to where the old component was, and establish
41 * an overlay mount of the old component on top of the new component.
42 * The patch tools do this with a shell script; consequently, the three
43 * operations occur in three processes.
44 *
45 * This doesn't work inside Solaris 10 Containers (S10Cs).  Suppose the
46 * patch tools need to replace /lib/libc.so.1.  The tools will move the old
47 * libc.so.1 to a temporary location.  But when they try to move the new
48 * libc.so.1, they fork a mv(1) process, which loads the solaris10 brand's
49 * emulation library.  The emulation library will try to load the zone's
50 * libc.so.1, but the library no longer exists; consequently, the emulation
51 * library aborts and the zone's users won't be able to start any processes.
52 *
53 * This program solves the problem by combining the move and mount operations
54 * into a single process.  The emulation library will already have loaded
55 * libc.so.1 for the process by the time the process starts to replace
56 * libc.so.1.
57 *
58 * This program takes six parameters that correspond to six variables within
59 * /usr/lib/patch/patch_common_lib:InstallSafemodeObject():
60 *
61 *	argv[1] - dstActual (the path to the file that will be replaced)
62 *	argv[2] - tmp_file (the temporary location to which the file will be
63 *		moved)
64 *	argv[3] - tmpDst (the path to the replacement file)
65 *	argv[4] - tmpFile (the path to a temporary copy of the running system's
66 *		version of the file being replaced; the source [special] of
67 *		the overlay mount)
68 *	argv[5] - cksumTmpDst (checksum of the file represented by tmpDst)
69 *	argv[6] - cksumTmpFile (checksum of the file represented by tmpFile)
70 *
71 * NOTE: This program will only establish an overlay mount if argv[4] or argv[5]
72 * is emtpy or if argv[4] and argv[5] differ.
73 *
74 * This program returns zero when it succeeds.  Non-negative values indicate
75 * failure.
76 */
77int
78main(int argc, char **argv)
79{
80	struct stat statbuf;
81	char mntoptions[MAX_MNTOPT_STR];
82
83	/*
84	 * Check the number of arguments that were passed to s10_replacefile.
85	 */
86	if (argc != 7) {
87		(void) fprintf(stderr, "Usage: %s dstActual tmp_file tmpDst "
88		    "tmpFile cksumTmpDst cksumTmpFile\n", argv[0]);
89		return (1);
90	}
91
92	/*
93	 * Move the destination file (dstActual) out of the way and move the
94	 * new file (tmpDst) into its place.
95	 *
96	 * NOTE: s10_replacefile won't print error messages here because
97	 * the Solaris 10 patch tools will.
98	 */
99	if (rename(argv[1], argv[2]) != 0)
100		return (2);
101	if (rename(argv[3], argv[1]) != 0)
102		return (3);
103
104	/*
105	 * If there was a lofs mount on dstActual (which we just moved), then
106	 * s10_replacefile should reestablish the lofs mount.  A lofs mount
107	 * existed if tmpFile exists.
108	 */
109	if (stat(argv[4], &statbuf) == 0 && (statbuf.st_mode & S_IFREG)) {
110		/*
111		 * Create a lofs overlay mount only if the checksums of the
112		 * old file at dstActual and the new file at dstActual differ.
113		 */
114		if (argv[5][0] == '\0' || argv[6][0] == '\0' ||
115		    strcmp(argv[5], argv[6]) != 0) {
116			mntoptions[0] = '\0';
117			if (mount(argv[4], argv[1], MS_OVERLAY | MS_OPTIONSTR,
118			    MNTTYPE_LOFS, NULL, 0, mntoptions,
119			    sizeof (mntoptions)) != 0) {
120				/*
121				 * Although the patch tools will print error
122				 * messages, the tools won't know that
123				 * s10_replacefile failed to establish an
124				 * overlay mount.  Printing an error message
125				 * here clarifies the problem for the user.
126				 */
127				(void) fprintf(stderr, "ERROR: Failed to "
128				    "overlay mount %s onto %s\n", argv[4],
129				    argv[1]);
130				return (4);
131			}
132		} else {
133			/*
134			 * dstActual does not need an overlay mount.  Delete
135			 * tmpFile.
136			 */
137			(void) unlink(argv[4]);
138		}
139	}
140	return (0);
141}
142