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