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  */
77 int
main(int argc,char ** argv)78 main(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