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 2007 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 */
43 #include "pkginstall.h"
46 extern char instdir
[], pkgbin
[], pkgloc
[], savlog
[], *pkginst
, **environ
;
47 extern char saveSpoolInstallDir
[];
48 extern char pkgsav
[]; /* pkginstall/main.c */
52 * flag definitions for each entry in table
55 typedef unsigned int TBL_FLAG_T
;
58 #define FLAG_NONE ((TBL_FLAG_T)0x0000)
60 /* exclude this attribute if found */
61 #define FLAG_EXCLUDE ((TBL_FLAG_T)0x0001)
63 /* this attribute must not change if found */
64 #define FLAG_IDENTICAL ((TBL_FLAG_T)0x0002)
67 * macro to generate an entry in the table:
68 * TBL_ENTRY("PKGINFO_ATTRIBUTE=", FLAG_XXX)
70 * "PKGINFO_ATTRIBUTE=" is the attribute to look for
71 * FLAG_XXX is the action to perform when the attribute is found
74 #define TBL_ENTRY(_Y_, _F_) { (_Y_), ((sizeof ((_Y_)))-1), (_F_) }
77 * table containing attributes that require special handling
81 char *_nlName
; /* attribute name */
82 int _nlLen
; /* attribute length */
83 TBL_FLAG_T _nlFlag
; /* attribute disposition flag */
86 typedef struct _namelist NAMELIST_T
;
89 * These are attributes to be acted on in some way when a pkginfo file is
90 * merged. This table MUST be in alphabetical order because it is searched
91 * using a binary search algorithm.
94 static NAMELIST_T attrTbl
[] = {
95 TBL_ENTRY("BASEDIR=", FLAG_EXCLUDE
),
96 TBL_ENTRY("CLASSES=", FLAG_EXCLUDE
),
97 TBL_ENTRY("CLIENT_BASEDIR=", FLAG_EXCLUDE
),
98 TBL_ENTRY("INST_DATADIR=", FLAG_EXCLUDE
),
99 TBL_ENTRY("PKG_CAS_PASSRELATIVE=", FLAG_EXCLUDE
),
100 TBL_ENTRY("PKG_DST_QKVERIFY=", FLAG_EXCLUDE
),
101 TBL_ENTRY("PKG_INIT_INSTALL=", FLAG_EXCLUDE
),
102 TBL_ENTRY("PKG_INSTALL_ROOT=", FLAG_EXCLUDE
),
103 TBL_ENTRY("PKG_SRC_NOVERIFY=", FLAG_EXCLUDE
),
104 TBL_ENTRY("SUNW_PKGCOND_GLOBAL_DATA=", FLAG_EXCLUDE
),
105 TBL_ENTRY("SUNW_PKG_ALLZONES=", FLAG_IDENTICAL
),
106 TBL_ENTRY("SUNW_PKG_DIR=", FLAG_EXCLUDE
),
107 TBL_ENTRY("SUNW_PKG_HOLLOW=", FLAG_IDENTICAL
),
108 TBL_ENTRY("SUNW_PKG_INSTALL_ZONENAME=", FLAG_EXCLUDE
),
109 TBL_ENTRY("SUNW_PKG_THISZONE=", FLAG_IDENTICAL
),
112 #define ATTRTBL_SIZE (sizeof (attrTbl) / sizeof (NAMELIST_T))
115 * While pkgsav has to be set up with reference to the server for package
116 * scripts, it has to be client-relative in the pkginfo file. This function
117 * is used to set the client-relative value for use in the pkginfo file.
120 set_infoloc(char *path
)
123 if (is_an_inst_root()) {
124 /* Strip the server portion of the path. */
125 infoloc
= orig_path(path
);
127 infoloc
= strdup(path
);
133 merginfo(struct cl_attr
**pclass
, int install_from_pspool
)
140 char pkginfoPath
[PATH_MAX
];
146 /* remove savelog from previous attempts */
148 (void) unlink(savlog
);
151 * create path to appropriate pkginfo file for the package that is
152 * already installed - is_spool_create() will be set (!= 0) if the
153 * -t option is presented to pkginstall - the -t option is used to
154 * disable save spool area creation; do not spool any partial package
155 * contents, that is, suppress the creation and population of the
156 * package save spool area (var/sadm/pkg/PKG/save/pspool/PKG). This
157 * option is set only when a non-global zone is being created.
160 if (is_spool_create() == 0) {
162 * normal package install (not a non-global zone install);
163 * use the standard installed pkginfo file for this package:
164 * --> /var/sadm/pkg/PKGINST/pkginfo
165 * as the source pkginfo file to scan.
167 i
= snprintf(pkginfoPath
, sizeof (pkginfoPath
),
168 "%s/var/sadm/pkg/%s/%s",
169 ((get_inst_root()) &&
170 (strcmp(get_inst_root(), "/") != 0)) ?
171 get_inst_root() : "", pkginst
,
173 if (i
> sizeof (pkginfoPath
)) {
174 progerr(ERR_CREATE_PATH_2
,
175 ((get_inst_root()) &&
176 (strcmp(get_inst_root(), "/") != 0)) ?
177 get_inst_root() : "/",
183 * non-global zone installation - use the "saved" pspool
184 * pkginfo file in the global zone for this package:
185 * --> /var/sadm/install/PKG/save/pspool/PKG/pkginfo
186 * as the source pkginfo file to scan.
188 i
= snprintf(pkginfoPath
, sizeof (pkginfoPath
), "%s/%s",
189 saveSpoolInstallDir
, PKGINFO
);
190 if (i
> sizeof (pkginfoPath
)) {
191 progerr(ERR_CREATE_PATH_2
,
192 saveSpoolInstallDir
, PKGINFO
);
197 i
= snprintf(path
, PATH_MAX
, "%s/%s", pkgloc
, PKGINFO
);
199 progerr(ERR_CREATE_PATH_2
, pkgloc
, PKGINFO
);
203 /* entry debugging info */
205 echoDebug(DBG_MERGINFO_ENTRY
,
206 instdir
? instdir
: "??",
207 ((get_inst_root()) &&
208 (strcmp(get_inst_root(), "/") != 0)) ?
209 get_inst_root() : "??",
210 saveSpoolInstallDir
? saveSpoolInstallDir
: "??",
211 pkgloc
? pkgloc
: "??", is_spool_create(),
212 get_info_basedir() ? get_info_basedir() : "??",
216 * open the pkginfo file:
217 * if the source pkginfo file to check is the same as the merged one
218 * (e.g. /var/sadm/pkg/PKGINST/pkginfo) then do not open the source
219 * pkginfo file to "verify"
222 if (strcmp(pkginfoPath
, path
) == 0) {
223 pkginfoFP
= (FILE *)NULL
;
224 echoDebug(DBG_MERGINFO_SAME
, path
);
226 echoDebug(DBG_MERGINFO_DIFFERENT
, pkginfoPath
, path
);
227 pkginfoFP
= fopen(pkginfoPath
, "r");
229 if (pkginfoFP
== (FILE *)NULL
) {
230 echoDebug(ERR_NO_PKG_INFOFILE
, pkginst
, pkginfoPath
,
236 * output packaging environment to create a pkginfo file in pkgloc[]
239 if ((fp
= fopen(path
, "w")) == NULL
) {
240 progerr(ERR_CANNOT_OPEN_FOR_WRITING
, path
, strerror(errno
));
245 * output CLASSES attribute
249 (void) fputs("CLASSES=", fp
);
251 (void) fputs(pclass
[0]->name
, fp
);
253 for (i
= 1; pclass
[i
]; i
++) {
254 (void) putc(' ', fp
);
255 (void) fputs(pclass
[i
]->name
, fp
);
260 for (i
= 0; i
< nc
; i
++) {
266 for (j
= 0; pclass
[j
]; ++j
) {
267 if (cl_nam(i
) != NULL
&&
269 pclass
[j
]->name
) == 0) {
277 (void) putc(' ', fp
);
279 (void) fputs(cl_nam(i
), fp
);
283 (void) putc('\n', fp
);
286 * NOTE : BASEDIR below is relative to the machine that
287 * *runs* the package. If there's an install root, this
288 * is actually the CLIENT_BASEDIR wrt the machine
289 * doing the pkgadd'ing here. -- JST
292 if (is_a_basedir()) {
293 static char *txs1
= "BASEDIR=";
295 (void) fputs(txs1
, fp
);
296 (void) fputs(get_info_basedir(), fp
);
297 (void) putc('\n', fp
);
299 (void) fputs("BASEDIR=/", fp
);
300 (void) putc('\n', fp
);
304 * output all other environment attributes except those which
305 * are relevant only to install.
308 for (i
= 0; environ
[i
] != (char *)NULL
; i
++) {
309 char *ep
= environ
[i
];
311 int incr
= (ATTRTBL_SIZE
>> 1)+1; /* searches possible */
312 int pos
= ATTRTBL_SIZE
>> 1; /* start in middle */
313 NAMELIST_T
*pp
= (NAMELIST_T
*)NULL
;
316 * find this attribute in the table - accept the attribute if it
317 * is outside of the bounds of the table; otherwise, do a binary
318 * search looking for this attribute.
321 if (strncmp(ep
, attrTbl
[0]._nlName
, attrTbl
[0]._nlLen
) < 0) {
323 /* entry < first entry in attribute table */
325 echoDebug(DBG_MERGINFO_LESS_THAN
, ep
,
328 } else if (strncmp(ep
, attrTbl
[ATTRTBL_SIZE
-1]._nlName
,
329 attrTbl
[ATTRTBL_SIZE
-1]._nlLen
) > 0) {
331 /* entry > last entry in attribute table */
333 echoDebug(DBG_MERGINFO_GREATER_THAN
, ep
,
334 attrTbl
[ATTRTBL_SIZE
-1]._nlName
);
337 /* first entry < entry < last entry in table: search */
339 echoDebug(DBG_MERGINFO_SEARCHING
, ep
,
341 attrTbl
[ATTRTBL_SIZE
-1]._nlName
);
343 while (incr
> 0) { /* while possible to divide */
348 /* compare current attr with this table entry */
349 r
= strncmp(pp
->_nlName
, ep
, pp
->_nlLen
);
351 /* break out of loop if match */
353 /* save location/break if match found */
358 /* no match search to next/prev half */
360 pos
+= (r
< 0) ? incr
: -incr
;
365 /* handle excluded attribute found */
367 if ((attrPos
>= 0) && (pp
->_nlFlag
== FLAG_EXCLUDE
)) {
368 /* attribute is excluded */
369 echoDebug(DBG_MERGINFO_EXCLUDING
, ep
);
373 /* handle fixed attribute found */
375 if ((pkginfoFP
!= (FILE *)NULL
) && (attrPos
>= 0) &&
376 (pp
->_nlFlag
== FLAG_IDENTICAL
)) {
377 /* attribute must not change */
379 char *src
= ep
+pp
->_nlLen
;
381 char theAttr
[PATH_MAX
+1];
383 /* isolate attribute name only without '=' at end */
385 (void) strncpy(theAttr
, pp
->_nlName
, pp
->_nlLen
-1);
386 theAttr
[pp
->_nlLen
-1] = '\0';
388 /* lookup attribute in installed package pkginfo file */
391 trg
= fpkgparam(pkginfoFP
, theAttr
);
393 echoDebug(DBG_MERGINFO_ATTRCOMP
, theAttr
,
396 /* if target not found attribute is being added */
398 if (trg
== (char *)NULL
) {
399 progerr(ERR_PKGINFO_ATTR_ADDED
, pkginst
, ep
);
403 /* error if two values are not the same */
405 if (strcmp(src
, trg
) != 0) {
406 progerr(ERR_PKGINFO_ATTR_CHANGED
, pkginst
,
412 /* attribute not excluded/has not changed - process */
414 if ((strncmp(ep
, "PKGSAV=", 7) == 0)) {
415 (void) fputs("PKGSAV=", fp
);
416 (void) fputs(infoloc
, fp
);
417 (void) putc('/', fp
);
418 (void) fputs(pkginst
, fp
);
419 (void) fputs("/save\n", fp
);
423 if ((strncmp(ep
, "UPDATE=", 7) == 0) &&
424 install_from_pspool
!= 0 &&
429 echoDebug(DBG_MERGINFO_FINAL
, ep
);
431 (void) fputs(ep
, fp
);
432 (void) putc('\n', fp
);
436 (void) fclose(pkginfoFP
);
439 * copy all packaging scripts to appropriate directory
442 i
= snprintf(path
, PATH_MAX
, "%s/install", instdir
);
444 progerr(ERR_CREATE_PATH_2
, instdir
, "/install");
448 if ((pdirfp
= opendir(path
)) != NULL
) {
451 while ((dp
= readdir(pdirfp
)) != NULL
) {
452 if (dp
->d_name
[0] == '.')
455 i
= snprintf(path
, PATH_MAX
, "%s/install/%s",
456 instdir
, dp
->d_name
);
458 progerr(ERR_CREATE_PATH_3
, instdir
, "/install/",
463 i
= snprintf(temp
, PATH_MAX
, "%s/%s", pkgbin
,
466 progerr(ERR_CREATE_PATH_2
, pkgbin
, dp
->d_name
);
470 if (cppath(MODE_SRC
|DIR_DISPLAY
, path
, temp
, 0644)) {
471 progerr(ERR_CANNOT_COPY
, dp
->d_name
, pkgbin
);
475 (void) closedir(pdirfp
);
479 * copy all packaging scripts to the partial spool directory
482 if (!is_spool_create()) {
483 /* packages are being spooled to ../save/pspool/.. */
484 i
= snprintf(path
, PATH_MAX
, "%s/install", instdir
);
486 progerr(ERR_CREATE_PATH_2
, instdir
, "/install");
490 if ((pdirfp
= opendir(path
)) != NULL
) {
494 while ((dp
= readdir(pdirfp
)) != NULL
) {
495 if (dp
->d_name
[0] == '.')
498 * Don't copy i.none since if it exists it
499 * contains Class Archive Format procedure
500 * for installing archives. Only Directory
501 * Format packages can exist
502 * in a global spooled area.
504 if (strcmp(dp
->d_name
, "i.none") == 0)
507 i
= snprintf(path
, PATH_MAX
, "%s/install/%s",
508 instdir
, dp
->d_name
);
511 progerr(ERR_CREATE_PATH_3
, instdir
,
512 "/install/", dp
->d_name
);
516 i
= snprintf(temp
, PATH_MAX
, "%s/install/%s",
521 progerr(ERR_CREATE_PATH_3
,
523 "/install/", dp
->d_name
);
527 if (cppath(MODE_SRC
, path
, temp
, 0644)) {
528 progerr(ERR_CANNOT_COPY
, path
, temp
);
529 (void) closedir(pdirfp
);
533 (void) closedir(pdirfp
);
537 * Now copy the original pkginfo and pkgmap files from the
538 * installing package to the spooled directory.
541 i
= snprintf(path
, sizeof (path
), "%s/%s", instdir
, PKGINFO
);
542 if (i
> sizeof (path
)) {
543 progerr(ERR_CREATE_PATH_2
, instdir
, PKGINFO
);
547 i
= snprintf(temp
, sizeof (temp
), "%s/%s",
548 saveSpoolInstallDir
, PKGINFO
);
549 if (i
> sizeof (temp
)) {
550 progerr(ERR_CREATE_PATH_2
, saveSpoolInstallDir
,
555 if (cppath(MODE_SRC
, path
, temp
, 0644)) {
556 progerr(ERR_CANNOT_COPY
, path
, temp
);
560 i
= snprintf(path
, sizeof (path
), "%s/pkgmap", instdir
);
561 if (i
> sizeof (path
)) {
562 progerr(ERR_CREATE_PATH_2
, instdir
, "pkgmap");
566 i
= snprintf(temp
, sizeof (temp
), "%s/pkgmap",
567 saveSpoolInstallDir
);
568 if (i
> sizeof (path
)) {
569 progerr(ERR_CREATE_PATH_2
, saveSpoolInstallDir
,
574 if (cppath(MODE_SRC
, path
, temp
, 0644)) {
575 progerr(ERR_CANNOT_COPY
, path
, temp
);
581 * If we are installing from a spool directory
582 * copy the save directory from it, it may have
583 * been patched. Duplicate it only if this
584 * installation isn't an update and is not to
587 if (strstr(instdir
, "pspool") != NULL
) {
590 i
= snprintf(path
, sizeof (path
), "%s/save", instdir
);
591 if (i
> sizeof (path
)) {
592 progerr(ERR_CREATE_PATH_2
, instdir
, "save");
596 if ((stat(path
, &status
) == 0) && (status
.st_mode
& S_IFDIR
)) {
597 i
= snprintf(cmd
, sizeof (cmd
), "cp -pr %s/* %s",
599 if (i
> sizeof (cmd
)) {
600 progerr(ERR_SNPRINTF
, "cp -pr %s/* %s");
605 progerr(ERR_PKGBINCP
, path
, pkgsav
);