8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / svr4pkg / pkginstall / reqexec.c
blob86d369175c9b5f85d004a4883f626e1f3c7ac099
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <fcntl.h> /* creat() declaration */
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #include <locale.h>
42 #include <libintl.h>
43 #include <pkglib.h>
44 #include "install.h"
45 #include "libadm.h"
46 #include "libinst.h"
47 #include "pkginstall.h"
48 #include "messages.h"
50 extern char tmpdir[], instdir[];
51 extern int pkgverbose;
53 static int do_exec(int update, char *script, char *output,
54 char *inport, char *alt_user);
55 static char path[PATH_MAX];
56 static char *resppath = NULL;
57 static int fd;
58 static int respfile_defined = 0;
59 static int respfile_ro = 0; /* read only resp file */
62 * This informs the calling routine if a read-only response file has been
63 * provided on the command line.
65 int
66 rdonly_respfile(void)
68 return (respfile_ro);
71 int
72 is_a_respfile(void)
74 return (respfile_defined);
78 * This function creates a working copy of the checkinstall script.
79 * This is needed in situations where the packages parent directories modes
80 * are set too restrictively, i.e. 700.
82 * Returns: A pointer to the location of the copied checkinstall
83 * script or NULL
86 char *
87 dup_chkinstall(char *script)
89 char *dstpath;
90 size_t dstpathLen;
91 int r;
92 static char *tmpname = "checkinstallXXXXXX";
94 /* determine length for destination script path */
96 dstpathLen = strlen(tmpdir) + strlen(tmpname) + 3;
98 /* allocate storage to hold destination script path */
100 dstpath = (char *)malloc(dstpathLen);
101 if (dstpath == (char *)NULL) {
102 return ((char *)NULL);
105 /* create destination script path */
107 (void) snprintf(dstpath, dstpathLen, "%s/%s", tmpdir, tmpname);
109 if (mktemp(dstpath) == NULL) {
110 progerr(ERR_TMPFILE_CHK);
111 (void) free(dstpath);
112 return (NULL);
115 /* make copy of script */
117 r = copyf(script, dstpath, (time_t)0);
118 if (r != 0) {
119 progerr(ERR_CANNOT_COPY, script, dstpath);
120 return (NULL);
123 /* Make the copy of the script readable by all */
125 if (chmod(dstpath, 0444) != 0) {
126 progerr(ERR_CHMOD_CHK);
127 (void) free(dstpath);
128 return (NULL);
131 return (dstpath);
135 * This function creates a temporary working copy of a read-only response
136 * file. It changes the resppath pointer to point to the working copy.
138 static int
139 dup_respfile(void)
141 char tpath[PATH_MAX];
142 int r;
144 (void) strlcpy(tpath, path, sizeof (tpath));
146 (void) snprintf(path, sizeof (path), "%s/respXXXXXX", tmpdir);
148 resppath = mktemp(path);
149 if (resppath == NULL) {
150 progerr(ERR_TMPRESP);
151 return (99);
154 /* Copy the contents of the user's response file to the working copy. */
156 r = copyf(tpath, resppath, (time_t)0);
157 if (r != 0) {
158 progerr(ERR_NORESPCOPY, tpath, resppath);
159 return (99);
163 * Make it writable by the non-privileged installation user-id,
164 * but readable by the world.
167 if (chmod(resppath, 0644) != 0) {
168 progerr(ERR_CHMOD, resppath);
169 return (99);
172 respfile_ro = 0;
174 return (0);
178 * This function establishes the response file passed on the command line if
179 * it's called with a valid string. If called with NULL, it checks to see if
180 * there's a response file already. If there isn't, it creates a temporary.
183 set_respfile(char *respfile, char *pkginst, int resp_stat)
185 if (respfile == NULL && !respfile_defined) {
186 /* A temporary response file needs to be constructed. */
187 (void) snprintf(path, sizeof (path), "%s/respXXXXXX", tmpdir);
188 resppath = mktemp(path);
189 if (resppath == NULL) {
190 progerr(ERR_TMPRESP);
191 return (99);
193 } else {
194 /* OK, we're being passed a response file or directory. */
195 if (isdir(respfile) == 0) {
196 (void) snprintf(path, sizeof (path),
197 "%s/%s", respfile, pkginst);
198 } else {
199 (void) strlcpy(path, respfile, sizeof (path));
202 resppath = path;
203 respfile_ro = resp_stat;
206 respfile_defined++;
208 return (0);
211 /* This exposes the working response file. */
212 char *
213 get_respfile(void)
215 return (resppath);
219 * Execute the request script if present assuming the response file
220 * isn't read only.
223 reqexec(int update, char *script, int non_abi_scripts,
224 boolean_t enable_root_user)
226 char *req_user;
229 * determine which alternative user to execute the request script as
230 * if the default user "install" is not defined.
233 if (enable_root_user == B_TRUE) {
234 /* use the root user */
235 req_user = CHK_USER_ROOT;
236 } else if (non_abi_scripts != 0) {
237 /* non-compliant package user */
238 req_user = CHK_USER_NON;
239 } else {
240 /* standard non-privileged user */
241 req_user = CHK_USER_ALT;
245 * If we can't get to the the script or the response file, skip this.
247 if (access(script, F_OK) != 0 || respfile_ro)
248 return (0);
250 /* No interact means no interact. */
251 if (echoGetFlag() == B_FALSE) {
252 ptext(stderr, ERR_INTR);
253 return (5);
256 /* If there's no response file, create one. */
257 if (!respfile_defined)
258 if (set_respfile(NULL, NULL, 0))
259 return (99);
261 /* Clear out the old response file (if there is one). */
262 if ((access(resppath, F_OK) == 0) && unlink(resppath)) {
263 progerr(ERR_RMRESP, resppath);
264 return (99);
268 * Create a zero length response file which is only writable
269 * by the non-privileged installation user-id, but is readable
270 * by the world
272 if ((fd = open(resppath, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) < 0) {
273 progerr(ERR_CRERESP, resppath);
274 return (99);
276 (void) close(fd);
278 return (do_exec(update, script, resppath, REQ_STDIN, req_user));
282 chkexec(int update, char *script)
285 * If we're up against a read-only response file from the command
286 * line. Create a working copy.
288 if (respfile_ro) {
289 if (dup_respfile())
291 return (99);
293 /* Make sure we can get to it. */
294 if ((access(resppath, F_OK) != 0)) {
295 progerr(ERR_ACCRESP, resppath);
296 return (7);
300 /* If there's no response file, create a fresh one. */
301 else if (!respfile_defined) {
302 if (set_respfile(NULL, NULL, 0))
303 return (99);
306 * create a zero length response file which is only writable
307 * by the non-priveledged installation user-id, but is readable
308 * by the world
310 fd = open(resppath, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
311 if (fd < 0) {
312 progerr(ERR_CRERESP, resppath);
313 return (99);
315 (void) close(fd);
318 return (do_exec(update, script, resppath, CHK_STDIN, CHK_USER_ALT));
321 static int
322 do_exec(int update, char *script, char *output, char *inport, char *alt_user)
324 char *gname;
325 char *tmp_script;
326 char *uname;
327 gid_t instgid;
328 int retcode = 0;
329 struct group *grp;
330 struct passwd *pwp;
331 uid_t instuid;
334 * Determine which user to run the request script as:
335 * - if CHK_USER is a valid user, run the script as CHK_USER
336 * - otherwise, if alt_user is a valid user, run the script
337 * -- as alt_user
338 * - otherwise, output an error message and return failure
341 if ((pwp = getpwnam(CHK_USER)) != (struct passwd *)NULL) {
342 instuid = pwp->pw_uid;
343 uname = CHK_USER;
344 } else if ((pwp = getpwnam(alt_user)) != (struct passwd *)NULL) {
345 instuid = pwp->pw_uid;
346 uname = alt_user;
347 } else {
348 ptext(stderr, ERR_BADUSER, CHK_USER, CHK_USER_ALT);
349 return (1);
353 * Determine which group to run the request script as:
354 * - If CHK_GRP is a valid group, run the script as CHK_GRP
355 * - otherwise, assume group "1" user "other"
358 if ((grp = getgrnam(CHK_GRP)) != (struct group *)NULL) {
359 instgid = grp->gr_gid;
360 gname = CHK_GRP;
361 } else {
362 instgid = (gid_t)1; /* "other" group id */
363 gname = "other"; /* "other" group name */
366 echoDebug(DBG_DO_EXEC_REQUEST_USER, script, output, uname, instuid,
367 gname, instgid);
369 (void) chown(output, instuid, instgid);
372 * Copy the checkinstall script to tmpdir in case parent directories
373 * are restrictive, i.e. 700. Only do this for non updates, i.e.
374 * package installs and not patch package installs.
376 if (update) {
377 tmp_script = strdup(script);
378 } else if ((tmp_script = dup_chkinstall(script)) == NULL) {
379 /* Use the original checkinstall script */
380 tmp_script = strdup(script);
383 if (pkgverbose)
384 retcode = pkgexecl(inport, CHK_STDOUT, uname, CHK_GRP, SHELL,
385 "-x", tmp_script, output, NULL);
386 else
387 retcode = pkgexecl(inport, CHK_STDOUT, uname, CHK_GRP, SHELL,
388 tmp_script, output, NULL);
390 free(tmp_script);
391 return (retcode);