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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <dirent.h>
36 #include <locale.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include "pkglib.h"
40 #include "install.h"
41 #include "libadm.h"
42 #include "libinst.h"
43 #include "pkginstall.h"
44 #include "messages.h"
45
46 extern char instdir[], pkgbin[], pkgloc[], savlog[], *pkginst, **environ;
47 extern char saveSpoolInstallDir[];
48 extern char pkgsav[]; /* pkginstall/main.c */
49 static char *infoloc;
50
51 /*
52 * flag definitions for each entry in table
53 */
54
55 typedef unsigned int TBL_FLAG_T;
56
57 /* no flag set */
58 #define FLAG_NONE ((TBL_FLAG_T)0x0000)
59
60 /* exclude this attribute if found */
61 #define FLAG_EXCLUDE ((TBL_FLAG_T)0x0001)
62
63 /* this attribute must not change if found */
64 #define FLAG_IDENTICAL ((TBL_FLAG_T)0x0002)
65
66 /*
67 * macro to generate an entry in the table:
68 * TBL_ENTRY("PKGINFO_ATTRIBUTE=", FLAG_XXX)
69 * where:
70 * "PKGINFO_ATTRIBUTE=" is the attribute to look for
71 * FLAG_XXX is the action to perform when the attribute is found
72 */
73
74 #define TBL_ENTRY(_Y_, _F_) { (_Y_), ((sizeof ((_Y_)))-1), (_F_) }
75
76 /*
77 * table containing attributes that require special handling
78 */
79
80 struct _namelist {
81 char *_nlName; /* attribute name */
82 int _nlLen; /* attribute length */
83 TBL_FLAG_T _nlFlag; /* attribute disposition flag */
84 };
85
86 typedef struct _namelist NAMELIST_T;
87
88 /*
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.
92 */
93
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),
110 };
111
112 #define ATTRTBL_SIZE (sizeof (attrTbl) / sizeof (NAMELIST_T))
113
114 /*
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.
118 */
119 void
set_infoloc(char * path)120 set_infoloc(char *path)
121 {
122 if (path && *path) {
123 if (is_an_inst_root()) {
124 /* Strip the server portion of the path. */
125 infoloc = orig_path(path);
126 } else {
127 infoloc = strdup(path);
128 }
129 }
130 }
131
132 void
merginfo(struct cl_attr ** pclass,int install_from_pspool)133 merginfo(struct cl_attr **pclass, int install_from_pspool)
134 {
135 DIR *pdirfp;
136 FILE *fp;
137 FILE *pkginfoFP;
138 char path[PATH_MAX];
139 char cmd[PATH_MAX];
140 char pkginfoPath[PATH_MAX];
141 char temp[PATH_MAX];
142 int i;
143 int nc;
144 int out;
145
146 /* remove savelog from previous attempts */
147
148 (void) unlink(savlog);
149
150 /*
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.
158 */
159
160 if (is_spool_create() == 0) {
161 /*
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.
166 */
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,
172 PKGINFO);
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() : "/",
178 pkginst);
179 quit(1);
180 }
181 } else {
182 /*
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.
187 */
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);
193 quit(1);
194 }
195 }
196
197 i = snprintf(path, PATH_MAX, "%s/%s", pkgloc, PKGINFO);
198 if (i > PATH_MAX) {
199 progerr(ERR_CREATE_PATH_2, pkgloc, PKGINFO);
200 quit(1);
201 }
202
203 /* entry debugging info */
204
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() : "??",
213 pkginfoPath, path);
214
215 /*
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"
220 */
221
222 if (strcmp(pkginfoPath, path) == 0) {
223 pkginfoFP = (FILE *)NULL;
224 echoDebug(DBG_MERGINFO_SAME, path);
225 } else {
226 echoDebug(DBG_MERGINFO_DIFFERENT, pkginfoPath, path);
227 pkginfoFP = fopen(pkginfoPath, "r");
228
229 if (pkginfoFP == (FILE *)NULL) {
230 echoDebug(ERR_NO_PKG_INFOFILE, pkginst, pkginfoPath,
231 strerror(errno));
232 }
233 }
234
235 /*
236 * output packaging environment to create a pkginfo file in pkgloc[]
237 */
238
239 if ((fp = fopen(path, "w")) == NULL) {
240 progerr(ERR_CANNOT_OPEN_FOR_WRITING, path, strerror(errno));
241 quit(99);
242 }
243
244 /*
245 * output CLASSES attribute
246 */
247
248 out = 0;
249 (void) fputs("CLASSES=", fp);
250 if (pclass) {
251 (void) fputs(pclass[0]->name, fp);
252 out++;
253 for (i = 1; pclass[i]; i++) {
254 (void) putc(' ', fp);
255 (void) fputs(pclass[i]->name, fp);
256 out++;
257 }
258 }
259 nc = cl_getn();
260 for (i = 0; i < nc; i++) {
261 int found = 0;
262
263 if (pclass) {
264 int j;
265
266 for (j = 0; pclass[j]; ++j) {
267 if (cl_nam(i) != NULL &&
268 strcmp(cl_nam(i),
269 pclass[j]->name) == 0) {
270 found++;
271 break;
272 }
273 }
274 }
275 if (!found) {
276 if (out > 0) {
277 (void) putc(' ', fp);
278 }
279 (void) fputs(cl_nam(i), fp);
280 out++;
281 }
282 }
283 (void) putc('\n', fp);
284
285 /*
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
290 */
291
292 if (is_a_basedir()) {
293 static char *txs1 = "BASEDIR=";
294
295 (void) fputs(txs1, fp);
296 (void) fputs(get_info_basedir(), fp);
297 (void) putc('\n', fp);
298 } else {
299 (void) fputs("BASEDIR=/", fp);
300 (void) putc('\n', fp);
301 }
302
303 /*
304 * output all other environment attributes except those which
305 * are relevant only to install.
306 */
307
308 for (i = 0; environ[i] != (char *)NULL; i++) {
309 char *ep = environ[i];
310 int attrPos = -1;
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;
314
315 /*
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.
319 */
320
321 if (strncmp(ep, attrTbl[0]._nlName, attrTbl[0]._nlLen) < 0) {
322
323 /* entry < first entry in attribute table */
324
325 echoDebug(DBG_MERGINFO_LESS_THAN, ep,
326 attrTbl[0]._nlName);
327
328 } else if (strncmp(ep, attrTbl[ATTRTBL_SIZE-1]._nlName,
329 attrTbl[ATTRTBL_SIZE-1]._nlLen) > 0) {
330
331 /* entry > last entry in attribute table */
332
333 echoDebug(DBG_MERGINFO_GREATER_THAN, ep,
334 attrTbl[ATTRTBL_SIZE-1]._nlName);
335
336 } else {
337 /* first entry < entry < last entry in table: search */
338
339 echoDebug(DBG_MERGINFO_SEARCHING, ep,
340 attrTbl[0]._nlName,
341 attrTbl[ATTRTBL_SIZE-1]._nlName);
342
343 while (incr > 0) { /* while possible to divide */
344 int r;
345
346 pp = &attrTbl[pos];
347
348 /* compare current attr with this table entry */
349 r = strncmp(pp->_nlName, ep, pp->_nlLen);
350
351 /* break out of loop if match */
352 if (r == 0) {
353 /* save location/break if match found */
354 attrPos = pos;
355 break;
356 }
357
358 /* no match search to next/prev half */
359 incr = incr >> 1;
360 pos += (r < 0) ? incr : -incr;
361 continue;
362 }
363 }
364
365 /* handle excluded attribute found */
366
367 if ((attrPos >= 0) && (pp->_nlFlag == FLAG_EXCLUDE)) {
368 /* attribute is excluded */
369 echoDebug(DBG_MERGINFO_EXCLUDING, ep);
370 continue;
371 }
372
373 /* handle fixed attribute found */
374
375 if ((pkginfoFP != (FILE *)NULL) && (attrPos >= 0) &&
376 (pp->_nlFlag == FLAG_IDENTICAL)) {
377 /* attribute must not change */
378
379 char *src = ep+pp->_nlLen;
380 char *trg;
381 char theAttr[PATH_MAX+1];
382
383 /* isolate attribute name only without '=' at end */
384
385 (void) strncpy(theAttr, pp->_nlName, pp->_nlLen-1);
386 theAttr[pp->_nlLen-1] = '\0';
387
388 /* lookup attribute in installed package pkginfo file */
389
390 rewind(pkginfoFP);
391 trg = fpkgparam(pkginfoFP, theAttr);
392
393 echoDebug(DBG_MERGINFO_ATTRCOMP, theAttr,
394 trg ? trg : "");
395
396 /* if target not found attribute is being added */
397
398 if (trg == (char *)NULL) {
399 progerr(ERR_PKGINFO_ATTR_ADDED, pkginst, ep);
400 quit(1);
401 }
402
403 /* error if two values are not the same */
404
405 if (strcmp(src, trg) != 0) {
406 progerr(ERR_PKGINFO_ATTR_CHANGED, pkginst,
407 theAttr, src, trg);
408 quit(1);
409 }
410 }
411
412 /* attribute not excluded/has not changed - process */
413
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);
420 continue;
421 }
422
423 if ((strncmp(ep, "UPDATE=", 7) == 0) &&
424 install_from_pspool != 0 &&
425 !isUpdate()) {
426 continue;
427 }
428
429 echoDebug(DBG_MERGINFO_FINAL, ep);
430
431 (void) fputs(ep, fp);
432 (void) putc('\n', fp);
433 }
434
435 (void) fclose(fp);
436 (void) fclose(pkginfoFP);
437
438 /*
439 * copy all packaging scripts to appropriate directory
440 */
441
442 i = snprintf(path, PATH_MAX, "%s/install", instdir);
443 if (i > PATH_MAX) {
444 progerr(ERR_CREATE_PATH_2, instdir, "/install");
445 quit(1);
446 }
447
448 if ((pdirfp = opendir(path)) != NULL) {
449 struct dirent *dp;
450
451 while ((dp = readdir(pdirfp)) != NULL) {
452 if (dp->d_name[0] == '.')
453 continue;
454
455 i = snprintf(path, PATH_MAX, "%s/install/%s",
456 instdir, dp->d_name);
457 if (i > PATH_MAX) {
458 progerr(ERR_CREATE_PATH_3, instdir, "/install/",
459 dp->d_name);
460 quit(1);
461 }
462
463 i = snprintf(temp, PATH_MAX, "%s/%s", pkgbin,
464 dp->d_name);
465 if (i > PATH_MAX) {
466 progerr(ERR_CREATE_PATH_2, pkgbin, dp->d_name);
467 quit(1);
468 }
469
470 if (cppath(MODE_SRC|DIR_DISPLAY, path, temp, 0644)) {
471 progerr(ERR_CANNOT_COPY, dp->d_name, pkgbin);
472 quit(99);
473 }
474 }
475 (void) closedir(pdirfp);
476 }
477
478 /*
479 * copy all packaging scripts to the partial spool directory
480 */
481
482 if (!is_spool_create()) {
483 /* packages are being spooled to ../save/pspool/.. */
484 i = snprintf(path, PATH_MAX, "%s/install", instdir);
485 if (i > PATH_MAX) {
486 progerr(ERR_CREATE_PATH_2, instdir, "/install");
487 quit(1);
488 }
489
490 if ((pdirfp = opendir(path)) != NULL) {
491 struct dirent *dp;
492
493
494 while ((dp = readdir(pdirfp)) != NULL) {
495 if (dp->d_name[0] == '.')
496 continue;
497 /*
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.
503 */
504 if (strcmp(dp->d_name, "i.none") == 0)
505 continue;
506
507 i = snprintf(path, PATH_MAX, "%s/install/%s",
508 instdir, dp->d_name);
509
510 if (i > PATH_MAX) {
511 progerr(ERR_CREATE_PATH_3, instdir,
512 "/install/", dp->d_name);
513 quit(1);
514 }
515
516 i = snprintf(temp, PATH_MAX, "%s/install/%s",
517 saveSpoolInstallDir,
518 dp->d_name);
519
520 if (i > PATH_MAX) {
521 progerr(ERR_CREATE_PATH_3,
522 saveSpoolInstallDir,
523 "/install/", dp->d_name);
524 quit(1);
525 }
526
527 if (cppath(MODE_SRC, path, temp, 0644)) {
528 progerr(ERR_CANNOT_COPY, path, temp);
529 (void) closedir(pdirfp);
530 quit(99);
531 }
532 }
533 (void) closedir(pdirfp);
534 }
535
536 /*
537 * Now copy the original pkginfo and pkgmap files from the
538 * installing package to the spooled directory.
539 */
540
541 i = snprintf(path, sizeof (path), "%s/%s", instdir, PKGINFO);
542 if (i > sizeof (path)) {
543 progerr(ERR_CREATE_PATH_2, instdir, PKGINFO);
544 quit(1);
545 }
546
547 i = snprintf(temp, sizeof (temp), "%s/%s",
548 saveSpoolInstallDir, PKGINFO);
549 if (i > sizeof (temp)) {
550 progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir,
551 PKGINFO);
552 quit(1);
553 }
554
555 if (cppath(MODE_SRC, path, temp, 0644)) {
556 progerr(ERR_CANNOT_COPY, path, temp);
557 quit(99);
558 }
559
560 i = snprintf(path, sizeof (path), "%s/pkgmap", instdir);
561 if (i > sizeof (path)) {
562 progerr(ERR_CREATE_PATH_2, instdir, "pkgmap");
563 quit(1);
564 }
565
566 i = snprintf(temp, sizeof (temp), "%s/pkgmap",
567 saveSpoolInstallDir);
568 if (i > sizeof (path)) {
569 progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir,
570 "pkgmap");
571 quit(1);
572 }
573
574 if (cppath(MODE_SRC, path, temp, 0644)) {
575 progerr(ERR_CANNOT_COPY, path, temp);
576 quit(99);
577 }
578 }
579
580 /*
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
585 * an alternate root.
586 */
587 if (strstr(instdir, "pspool") != NULL) {
588 struct stat status;
589
590 i = snprintf(path, sizeof (path), "%s/save", instdir);
591 if (i > sizeof (path)) {
592 progerr(ERR_CREATE_PATH_2, instdir, "save");
593 quit(1);
594 }
595
596 if ((stat(path, &status) == 0) && (status.st_mode & S_IFDIR)) {
597 i = snprintf(cmd, sizeof (cmd), "cp -pr %s/* %s",
598 path, pkgsav);
599 if (i > sizeof (cmd)) {
600 progerr(ERR_SNPRINTF, "cp -pr %s/* %s");
601 quit(1);
602 }
603
604 if (system(cmd)) {
605 progerr(ERR_PKGBINCP, path, pkgsav);
606 quit(99);
607 }
608 }
609 }
610 }
611