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]
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 */
36 #include <fcntl.h> /* creat() declaration */
37 #include <sys/types.h>
47 #include "pkginstall.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
;
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.
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
87 dup_chkinstall(char *script
)
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
);
115 /* make copy of script */
117 r
= copyf(script
, dstpath
, (time_t)0);
119 progerr(ERR_CANNOT_COPY
, script
, dstpath
);
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
);
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.
141 char tpath
[PATH_MAX
];
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
);
154 /* Copy the contents of the user's response file to the working copy. */
156 r
= copyf(tpath
, resppath
, (time_t)0);
158 progerr(ERR_NORESPCOPY
, tpath
, resppath
);
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
);
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
);
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
);
199 (void) strlcpy(path
, respfile
, sizeof (path
));
203 respfile_ro
= resp_stat
;
211 /* This exposes the working response file. */
219 * Execute the request script if present assuming the response file
223 reqexec(int update
, char *script
, int non_abi_scripts
,
224 boolean_t enable_root_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
;
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
)
250 /* No interact means no interact. */
251 if (echoGetFlag() == B_FALSE
) {
252 ptext(stderr
, ERR_INTR
);
256 /* If there's no response file, create one. */
257 if (!respfile_defined
)
258 if (set_respfile(NULL
, NULL
, 0))
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
);
268 * Create a zero length response file which is only writable
269 * by the non-privileged installation user-id, but is readable
272 if ((fd
= open(resppath
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
, 0644)) < 0) {
273 progerr(ERR_CRERESP
, resppath
);
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.
293 /* Make sure we can get to it. */
294 if ((access(resppath
, F_OK
) != 0)) {
295 progerr(ERR_ACCRESP
, resppath
);
300 /* If there's no response file, create a fresh one. */
301 else if (!respfile_defined
) {
302 if (set_respfile(NULL
, NULL
, 0))
306 * create a zero length response file which is only writable
307 * by the non-priveledged installation user-id, but is readable
310 fd
= open(resppath
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_EXCL
, 0644);
312 progerr(ERR_CRERESP
, resppath
);
318 return (do_exec(update
, script
, resppath
, CHK_STDIN
, CHK_USER_ALT
));
322 do_exec(int update
, char *script
, char *output
, char *inport
, char *alt_user
)
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
338 * - otherwise, output an error message and return failure
341 if ((pwp
= getpwnam(CHK_USER
)) != (struct passwd
*)NULL
) {
342 instuid
= pwp
->pw_uid
;
344 } else if ((pwp
= getpwnam(alt_user
)) != (struct passwd
*)NULL
) {
345 instuid
= pwp
->pw_uid
;
348 ptext(stderr
, ERR_BADUSER
, CHK_USER
, CHK_USER_ALT
);
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
;
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
,
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.
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
);
384 retcode
= pkgexecl(inport
, CHK_STDOUT
, uname
, CHK_GRP
, SHELL
,
385 "-x", tmp_script
, output
, NULL
);
387 retcode
= pkgexecl(inport
, CHK_STDOUT
, uname
, CHK_GRP
, SHELL
,
388 tmp_script
, output
, NULL
);