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