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) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26
27 #include <stdio.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <signal.h>
36 #include <errno.h>
37 #include <assert.h>
38 #include <pkgdev.h>
39 #include <pkginfo.h>
40 #include <pkglocs.h>
41 #include <locale.h>
42 #include <libintl.h>
43 #include <instzones_api.h>
44 #include <pkglib.h>
45 #include <install.h>
46 #include <libinst.h>
47 #include <libadm.h>
48 #include <messages.h>
49
50 /* commands to execute */
51
52 #define PKGINFO_CMD "/usr/bin/pkginfo"
53
54 #define GLOBALZONE_ONLY_PACKAGE_FILE_PATH \
55 "/var/sadm/install/gz-only-packages"
56
57 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
58 #define TEXT_DOMAIN "SYS_TEST"
59 #endif
60
61 /*
62 * forward declarations
63 */
64
65 static void _pkginfoInit(struct pkginfo *a_info);
66 static struct pkginfo *_pkginfoFactory(void);
67 static char **thisZonePackages;
68 static int numThisZonePackages;
69
70 /*
71 * *****************************************************************************
72 * global external (public) functions
73 * *****************************************************************************
74 */
75
76 /*
77 * Name: pkginfoFree
78 * Description: free pkginfo structure returned from various functions
79 * Arguments: r_info - pointer to pointer to pkginfo structure to free
80 * Returns: void
81 */
82
83 void
pkginfoFree(struct pkginfo ** r_info)84 pkginfoFree(struct pkginfo **r_info)
85 {
86 struct pkginfo *pinfo;
87
88 /* entry assertions */
89
90 assert(r_info != (struct pkginfo **)NULL);
91
92 /* localize reference to info structure to free */
93
94 pinfo = *r_info;
95
96 /* reset callers handle to info structure */
97
98 *r_info = (struct pkginfo *)NULL;
99
100 assert(pinfo != (struct pkginfo *)NULL);
101
102 /* free up contents of the structure */
103
104 _pkginfoInit(pinfo);
105
106 /* free up structure itself */
107
108 (void) free(pinfo);
109 }
110
111 /*
112 * Name: pkginfoIsPkgInstalled
113 * Description: determine if specified package is installed, return pkginfo
114 * structure describing package if package is installed
115 * Arguments: r_pinfo - pointer to pointer to pkginfo structure
116 * If this pointer is NOT null:
117 * -On success, this handle is filled in with a pointer
118 * --to a newly allocated pkginfo structure describing
119 * --the package discovered
120 * -On failure, this handle is filled with NULL
121 * If this pointer is NULL:
122 * -no pkginfo structure is returned on success.
123 * a_pkgInst - package instance (name) to lookup
124 * Returns: boolean_t
125 * B_TRUE - package installed, pkginfo returned
126 * B_FALSE - package not installed, no pkginfo returned
127 * NOTE: This function returns the first instance of package that
128 * is installed - see pkginfo() function for details
129 * NOTE: Any pkginfo structure returned is placed in new storage for the
130 * calling function. The caller must use 'pkginfoFree' to dispose
131 * of the storage once the pkginfo structure is no longer needed.
132 */
133
134 boolean_t
pkginfoIsPkgInstalled(struct pkginfo ** r_pinfo,char * a_pkgInst)135 pkginfoIsPkgInstalled(struct pkginfo **r_pinfo, char *a_pkgInst)
136 {
137 int r;
138 struct pkginfo *pinf;
139
140 /* entry assertions */
141
142 assert(a_pkgInst != (char *)NULL);
143 assert(*a_pkgInst != '\0');
144
145 /* reset returned pkginfo structure handle */
146
147 if (r_pinfo != (struct pkginfo **)NULL) {
148 *r_pinfo = (struct pkginfo *)NULL;
149 }
150
151 /* allocate a new pinfo structure for use in the call to pkginfo */
152
153 pinf = _pkginfoFactory();
154
155 /* lookup the specified package */
156
157 /* NOTE: required 'pkgdir' set to spool directory or NULL */
158 r = pkginfo(pinf, a_pkgInst, NULL, NULL);
159 echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, a_pkgInst, r);
160
161 if (r_pinfo != (struct pkginfo **)NULL) {
162 *r_pinfo = pinf;
163 } else {
164 /* free pkginfo structure */
165 pkginfoFree(&pinf);
166 }
167
168 return (r == 0 ? B_TRUE : B_FALSE);
169 }
170
171 /*
172 * Name: pkgOpenInGzOnlyFile
173 * Description: Open the global zone only package list file
174 * Arguments: a_rootPath - pointer to string representing the root path
175 * where the global zone only package list file is
176 * located - NULL is the same as "/"
177 * Returns: FILE *
178 * == NULL - failure - file not open
179 * != NULL - success - file pointer returned
180 * NOTE: This function will create the file if it does not exist.
181 */
182
183 FILE *
pkgOpenInGzOnlyFile(char * a_rootPath)184 pkgOpenInGzOnlyFile(char *a_rootPath)
185 {
186 FILE *pkgingzonlyFP;
187 char pkgingzonlyPath[PATH_MAX];
188 int len;
189
190 /* normalize root path */
191
192 if (a_rootPath == (char *)NULL) {
193 a_rootPath = "";
194 }
195
196 /* generate path to glocal zone only list file */
197
198 len = snprintf(pkgingzonlyPath, sizeof (pkgingzonlyPath), "%s/%s",
199 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
200 if (len > sizeof (pkgingzonlyPath)) {
201 progerr(ERR_CREATE_PATH_2, a_rootPath,
202 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
203 return ((FILE *)NULL);
204 }
205
206 /* open global zone only list file */
207
208 pkgingzonlyFP = fopen(pkgingzonlyPath, "r+");
209 if ((pkgingzonlyFP == (FILE *)NULL) && (errno == ENOENT)) {
210 pkgingzonlyFP = fopen(pkgingzonlyPath, "w+");
211 }
212
213 if ((pkgingzonlyFP == (FILE *)NULL) && (errno != ENOENT)) {
214 progerr(ERR_PKGOPS_OPEN_GZONLY, pkgingzonlyPath,
215 strerror(errno));
216 return ((FILE *)NULL);
217 }
218
219 /* success - return FILE pointer open on global zone only list file */
220
221 return (pkgingzonlyFP);
222 }
223
224 /*
225 * Name: pkgIsPkgInGzOnly
226 * Description: determine if package is recorded as "in global zone only"
227 * by opening the appropriate files and searching for the
228 * specified package
229 * Arguments: a_rootPath - pointer to string representing the root path
230 * where the global zone only package list file is
231 * located - NULL is the same as "/"
232 * a_pkgInst - pointer to string representing the package instance
233 * (name) of the package to lookup
234 * Returns: boolean_t
235 * B_TRUE - package is recorded as "in global zone only"
236 * B_FALSE - package is NOT recorded as "in gz only"
237 * NOTE: This function will create the file if it does not exist.
238 */
239
240 boolean_t
pkgIsPkgInGzOnly(char * a_rootPath,char * a_pkgInst)241 pkgIsPkgInGzOnly(char *a_rootPath, char *a_pkgInst)
242 {
243 FILE *fp;
244 boolean_t in_gz_only;
245
246 /* normalize root path */
247
248 if (a_rootPath == (char *)NULL) {
249 a_rootPath = "";
250 }
251
252 /* open the global zone only package list file */
253
254 fp = pkgOpenInGzOnlyFile(a_rootPath);
255 if (fp == (FILE *)NULL) {
256 echoDebug(ERR_PKGOPS_CANNOT_OPEN_GZONLY,
257 a_rootPath ? a_rootPath : "/");
258 return (B_FALSE);
259 }
260
261 /* is the package recorded as "in global zone only" ? */
262
263 in_gz_only = pkgIsPkgInGzOnlyFP(fp, a_pkgInst);
264
265 /* close the global zone only package list file */
266
267 (void) fclose(fp);
268
269 /* return results */
270
271 return (in_gz_only);
272 }
273
274 /*
275 * Name: pkgIsPkgInGzOnly
276 * Description: determine if package is recorded as "in global zone only"
277 * by searching the specified open FILE for the specified package
278 * Arguments: a_fp - pointer to FILE handle open on file to search
279 * a_pkgInst - pointer to string representing the package instance
280 * (name) of the package to lookup
281 * Returns: boolean_t
282 * B_TRUE - package is recorded as "in global zone only"
283 * B_FALSE - package is NOT recorded as "in gz only"
284 */
285
286 boolean_t
pkgIsPkgInGzOnlyFP(FILE * a_fp,char * a_pkgInst)287 pkgIsPkgInGzOnlyFP(FILE *a_fp, char *a_pkgInst)
288 {
289 char line[PATH_MAX+1];
290
291 /* entry assertions */
292
293 assert(a_fp != (FILE *)NULL);
294 assert(a_pkgInst != (char *)NULL);
295 assert(*a_pkgInst != '\0');
296
297 /* rewind the file to the beginning */
298
299 rewind(a_fp);
300
301 /* read the file line by line searching for the specified package */
302
303 while (fgets(line, sizeof (line), a_fp) != (char *)NULL) {
304 int len;
305
306 /* strip off trailing newlines */
307 len = strlen(line);
308 while ((len > 0) && (line[len-1] == '\n')) {
309 line[--len] = '\0';
310 }
311
312 /* ignore blank and comment lines */
313 if ((line[0] == '#') || (line[0] == '\0')) {
314 continue;
315 }
316
317 /* return true if this is the package we are looking for */
318 if (strcmp(a_pkgInst, line) == 0) {
319 echoDebug(DBG_PKGOPS_PKG_IS_GZONLY, a_pkgInst);
320 return (B_TRUE);
321 }
322 }
323
324 /* end of file - package not found */
325
326 echoDebug(DBG_PKGOPS_PKG_NOT_GZONLY, a_pkgInst);
327
328 return (B_FALSE);
329 }
330
331 /*
332 * Name: pkgRemovePackageFromGzonlyList
333 * Description: Remove specified package from the global zone only package list
334 * file located at a specified root path
335 * Arguments: a_rootPath - pointer to string representing the root path
336 * where the global zone only package list file is
337 * located - NULL is the same as "/"
338 * a_pkgInst - pointer to string representing the package instance
339 * (name) of the package to remove
340 * Returns: boolean_t
341 * B_TRUE - package is successfully removed
342 * B_FALSE - failed to remove package from file
343 * NOTE: This function will create the file if it does not exist.
344 */
345
346 boolean_t
pkgRemovePackageFromGzonlyList(char * a_rootPath,char * a_pkgInst)347 pkgRemovePackageFromGzonlyList(char *a_rootPath, char *a_pkgInst)
348 {
349 FILE *destFP;
350 FILE *srcFP;
351 boolean_t pkgremoved = B_FALSE;
352 char destPath[PATH_MAX];
353 char line[PATH_MAX+1];
354 char savePath[PATH_MAX];
355 char srcPath[PATH_MAX];
356 char timeb[BUFSIZ];
357 int len;
358 struct tm *timep;
359 time_t clock;
360
361 /* entry assertions */
362
363 assert(a_pkgInst != (char *)NULL);
364 assert(*a_pkgInst != '\0');
365
366 /* normalize root path */
367
368 if (a_rootPath == (char *)NULL) {
369 a_rootPath = "";
370 }
371
372 /*
373 * calculate paths to various objects
374 */
375
376 /* path to current "source" ingzonly file */
377
378 len = snprintf(srcPath, sizeof (srcPath), "%s/%s",
379 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
380 if (len > sizeof (srcPath)) {
381 progerr(ERR_CREATE_PATH_2, a_rootPath,
382 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
383 return (B_FALSE);
384 }
385
386 /* path to new "destination" ingzonly file */
387
388 len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp",
389 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
390 if (len > sizeof (srcPath)) {
391 progerr(ERR_CREATE_PATH_2, a_rootPath,
392 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
393 return (B_FALSE);
394 }
395
396 /* path to temporary "saved" ingzonly file */
397
398 len = snprintf(savePath, sizeof (savePath), "%s/%s.save",
399 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
400 if (len > sizeof (srcPath)) {
401 progerr(ERR_CREATE_PATH_2, a_rootPath,
402 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
403 return (B_FALSE);
404 }
405
406 /* open source file, creating if necessary */
407
408 srcFP = fopen(srcPath, "r+");
409 if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) {
410 srcFP = fopen(srcPath, "w+");
411 }
412
413 /* error if could not open/create file */
414
415 if (srcFP == (FILE *)NULL) {
416 progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno));
417 return (B_FALSE);
418 }
419
420 /* open/create new destination file */
421
422 (void) remove(destPath);
423 destFP = fopen(destPath, "w");
424 if (destFP == (FILE *)NULL) {
425 progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno));
426 if (srcFP != (FILE *)NULL) {
427 (void) fclose(srcFP);
428 }
429 return (B_FALSE);
430 }
431
432 /* add standard comment to beginning of file */
433
434 (void) time(&clock);
435 timep = localtime(&clock);
436
437 (void) strftime(timeb, sizeof (timeb), "%c\n", timep);
438
439 /* put standard header at the beginning of the file */
440
441 (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER,
442 get_prog_name(), "remove", a_pkgInst, timeb);
443
444 /* read source/write destination - removing specified package */
445
446 while (fgets(line, sizeof (line), srcFP) != (char *)NULL) {
447 int len;
448
449 /* strip off trailing newlines */
450 len = strlen(line);
451 while ((len > 0) && (line[len-1] == '\n')) {
452 line[--len] = '\0';
453 }
454
455 /* ignore blank and comment lines */
456 if ((line[0] == '#') || (line[0] == '\0')) {
457 continue;
458 }
459
460 /* add pkg if yet to add and pkg <= line */
461 if ((pkgremoved == B_FALSE) && (strcmp(a_pkgInst, line) == 0)) {
462 pkgremoved = B_TRUE;
463 } else {
464 (void) fprintf(destFP, "%s\n", line);
465 }
466 }
467
468 /* close both files */
469
470 (void) fclose(srcFP);
471
472 (void) fclose(destFP);
473
474 /*
475 * if package not found there is no need to update the original file
476 */
477
478 if (pkgremoved == B_FALSE) {
479 (void) unlink(destPath);
480 return (B_TRUE);
481 }
482
483 /*
484 * Now we want to make a copy of the old gzonly file as a
485 * fail-safe.
486 */
487
488 if ((access(savePath, F_OK) == 0) && remove(savePath)) {
489 progerr(ERR_REMOVE, savePath, strerror(errno));
490 (void) remove(destPath);
491 return (B_FALSE);
492 }
493
494 if (link(srcPath, savePath) != 0) {
495 progerr(ERR_LINK, savePath, srcPath, strerror(errno));
496 (void) remove(destPath);
497 return (B_FALSE);
498 }
499
500 if (rename(destPath, srcPath) != 0) {
501 progerr(ERR_RENAME, destPath, srcPath, strerror(errno));
502 if (rename(savePath, srcPath)) {
503 progerr(ERR_RENAME, savePath, srcPath, strerror(errno));
504 }
505 (void) remove(destPath);
506 return (B_FALSE);
507 }
508
509 if (remove(savePath) != 0) {
510 progerr(ERR_REMOVE, savePath, strerror(errno));
511 }
512
513 /* successfully removed package */
514
515 echoDebug(DBG_PKGOPS_REMOVED_GZPKG, a_pkgInst);
516
517 return (B_TRUE);
518 }
519
520 /*
521 * Name: pkgAddPackageFromGzonlyList
522 * Description: Add specified package to the global zone only package list
523 * file located at a specified root path
524 * Arguments: a_rootPath - pointer to string representing the root path
525 * where the global zone only package list file is
526 * located - NULL is the same as "/"
527 * a_pkgInst - pointer to string representing the package instance
528 * (name) of the package to add
529 * Returns: boolean_t
530 * B_TRUE - package is successfully added
531 * B_FALSE - failed to add package to the file
532 * NOTE: This function will create the file if it does not exist.
533 */
534
535 boolean_t
pkgAddPackageToGzonlyList(char * a_pkgInst,char * a_rootPath)536 pkgAddPackageToGzonlyList(char *a_pkgInst, char *a_rootPath)
537 {
538 FILE *destFP;
539 FILE *srcFP;
540 boolean_t pkgadded = B_FALSE;
541 char destPath[PATH_MAX];
542 char line[PATH_MAX+1];
543 char savePath[PATH_MAX];
544 char srcPath[PATH_MAX];
545 char timeb[BUFSIZ];
546 int len;
547 struct tm *timep;
548 time_t clock;
549
550 /* entry assertions */
551
552 assert(a_pkgInst != (char *)NULL);
553 assert(*a_pkgInst != '\0');
554
555 /* normalize root path */
556
557 if (a_rootPath == (char *)NULL) {
558 a_rootPath = "";
559 }
560
561 /* entry debugging info */
562
563 echoDebug(DBG_PKGOPS_ADDGZPKG, a_pkgInst, a_rootPath);
564
565 /*
566 * calculate paths to various objects
567 */
568
569 /* path to current "source" ingzonly file */
570
571 len = snprintf(srcPath, sizeof (srcPath), "%s/%s",
572 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
573 if (len > sizeof (srcPath)) {
574 progerr(ERR_CREATE_PATH_2, a_rootPath,
575 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
576 return (B_FALSE);
577 }
578
579 /* path to new "destination" ingzonly file */
580
581 len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp",
582 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
583 if (len > sizeof (srcPath)) {
584 progerr(ERR_CREATE_PATH_2, a_rootPath,
585 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
586 return (B_FALSE);
587 }
588
589 /* path to temporary "saved" ingzonly file */
590
591 len = snprintf(savePath, sizeof (savePath), "%s/%s.save",
592 a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
593 if (len > sizeof (srcPath)) {
594 progerr(ERR_CREATE_PATH_2, a_rootPath,
595 GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
596 return (B_FALSE);
597 }
598
599 /* open source file, creating if necessary */
600
601 srcFP = fopen(srcPath, "r+");
602 if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) {
603 srcFP = fopen(srcPath, "w+");
604 }
605
606 /* error if could not open/create file */
607
608 if (srcFP == (FILE *)NULL) {
609 progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno));
610 return (B_FALSE);
611 }
612
613 /* open/create new destination file */
614
615 (void) remove(destPath);
616 destFP = fopen(destPath, "w");
617 if (destFP == (FILE *)NULL) {
618 progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno));
619 if (srcFP != (FILE *)NULL) {
620 (void) fclose(srcFP);
621 }
622 return (B_FALSE);
623 }
624
625 /* add standard comment to beginning of file */
626
627 (void) time(&clock);
628 timep = localtime(&clock);
629
630 (void) strftime(timeb, sizeof (timeb), "%c\n", timep);
631
632 /* put standard header at the beginning of the file */
633
634 (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER,
635 get_prog_name(), "add", a_pkgInst, timeb);
636
637 /* read source/write destination; add package at appropriate location */
638
639 while (fgets(line, sizeof (line), srcFP) != (char *)NULL) {
640 int len;
641
642 /* strip off trailing newlines */
643 len = strlen(line);
644 while ((len > 0) && (line[len-1] == '\n')) {
645 line[--len] = '\0';
646 }
647
648 /* ignore blank and comment lines */
649 if ((line[0] == '#') || (line[0] == '\0')) {
650 continue;
651 }
652
653 /* add pkg if yet to add and pkg <= line */
654 if ((pkgadded == B_FALSE) && (strcmp(a_pkgInst, line) <= 0)) {
655 if (strcmp(a_pkgInst, line) != 0) {
656 (void) fprintf(destFP, "%s\n", a_pkgInst);
657 }
658 pkgadded = B_TRUE;
659 }
660
661 (void) fprintf(destFP, "%s\n", line);
662 }
663
664 /* if package not added yet, add to end of the file */
665
666 if (pkgadded == B_FALSE) {
667 (void) fprintf(destFP, "%s\n", a_pkgInst);
668 }
669
670 /* close both files */
671
672 (void) fclose(srcFP);
673
674 (void) fclose(destFP);
675
676 /*
677 * Now we want to make a copy of the old gzonly file as a
678 * fail-safe.
679 */
680
681 if ((access(savePath, F_OK) == 0) && remove(savePath)) {
682 progerr(ERR_REMOVE, savePath, strerror(errno));
683 (void) remove(destPath);
684 return (B_FALSE);
685 }
686
687 if (link(srcPath, savePath) != 0) {
688 progerr(ERR_LINK, savePath, srcPath, strerror(errno));
689 (void) remove(destPath);
690 return (B_FALSE);
691 }
692
693 if (rename(destPath, srcPath) != 0) {
694 progerr(ERR_RENAME, destPath, srcPath, strerror(errno));
695 if (rename(savePath, srcPath)) {
696 progerr(ERR_RENAME, savePath, srcPath, strerror(errno));
697 }
698 (void) remove(destPath);
699 return (B_FALSE);
700 }
701
702 if (remove(savePath) != 0) {
703 progerr(ERR_REMOVE, savePath, strerror(errno));
704 }
705
706 /* successfully added package */
707
708 echoDebug(DBG_PKGOPS_ADDED_GZPKG, a_pkgInst);
709
710 return (B_TRUE);
711 }
712
713 /*
714 * Name: pkginfoParamTruth
715 * Description: Search pkginfo file for specified parameter/value pair
716 * Arguments: a_fp - Pointer to FILE handle open on pkginfo file to search
717 * a_param - Pointer to string representing the parameter name
718 * to search for
719 * a_value - Pointer to string representing the "success" value
720 * being searched for
721 * a_default - determine results if parameter NOT found
722 * B_TRUE - parameter is TRUE if not found
723 * B_FALSE - parameter is FALSE if not found
724 * Returns: boolean_t
725 * B_TRUE - the parameter was found and matched the specified value
726 * OR the paramter was not found and a_default == B_TRUE
727 * B_FALSE - the parameter was found and did NOT match the value
728 * OR the paramter was not found and a_default == B_FALSE
729 */
730
731 boolean_t
pkginfoParamTruth(FILE * a_fp,char * a_param,char * a_value,boolean_t a_default)732 pkginfoParamTruth(FILE *a_fp, char *a_param, char *a_value, boolean_t a_default)
733 {
734 char *param;
735 boolean_t result;
736
737 /* entry assertions */
738
739 assert(a_fp != (FILE *)NULL);
740 assert(a_param != (char *)NULL);
741 assert(*a_param != '\0');
742 assert(a_value != (char *)NULL);
743 assert(*a_value != '\0');
744
745 /* rewind the file to the beginning */
746
747 rewind(a_fp);
748
749 /* search pkginfo file for the specified parameter */
750
751 param = fpkgparam(a_fp, a_param);
752
753 if (param == (char *)NULL) {
754 /* parameter not found - return default */
755 result = a_default;
756 } else if (*param == '\0') {
757 /* parameter found but no value - return default */
758 result = a_default;
759 } else if (strcasecmp(param, a_value) == 0) {
760 /* paramter found - matches value */
761 result = B_TRUE;
762 } else {
763 /* parameter found - does not match value */
764 result = B_FALSE;
765 }
766
767 /* exit debugging info */
768
769 echoDebug(DBG_PKGOPS_PARAMTRUTH_RESULTS,
770 a_param, a_value, a_default == B_TRUE ? "true" : "false",
771 param ? param : "?", result == B_TRUE ? "true" : "false");
772
773 /* if parameter value found, free results */
774
775 if (param != (char *)NULL) {
776 (void) free(param);
777 }
778
779 /* return results of search */
780
781 return (result);
782 }
783
784 /*
785 * Name: pkgGetPackageList
786 * Description: Determine list of packages based on list of packages that are
787 * available, category of packages to select, and list of packages
788 * to select.
789 * Arguments: r_pkgList - pointer to pointer to string array where the list
790 * of selected packages will be returned
791 * a_argv - pointer to string array containing list of packages
792 * to select
793 * a_optind - index into string array of first package to select
794 * a_categories - pointer to string representing the categories of
795 * packages to select
796 * a_categoryList - pointer to string array representing a list
797 * of categories to select
798 * a_pkgdev - package dev containing packages that can be selected
799 * Returns: int
800 * == 0 - packages found r_pkgList contains results package list retrieved
801 * == -1 - no packages found (errno == ENOPKG)
802 * != 0 - "quit" value entered by user
803 * NOTE: If both a category and a list of packages to select are provided
804 * the category is used over the list of packages provided
805 * NOTE: If neither a category nor a list of packages to select are
806 * provided, an error is returned
807 */
808
809 int
pkgGetPackageList(char *** r_pkgList,char ** a_argv,int a_optind,char * a_categories,char ** a_categoryList,struct pkgdev * a_pkgdev)810 pkgGetPackageList(char ***r_pkgList, char **a_argv, int a_optind,
811 char *a_categories, char **a_categoryList, struct pkgdev *a_pkgdev)
812 {
813 char *all_pkgs[4] = {"all", NULL};
814
815 /* entry assertions */
816
817 assert(a_pkgdev != (struct pkgdev *)NULL);
818 assert(a_pkgdev->dirname != (char *)NULL);
819 assert(*a_pkgdev->dirname != '\0');
820 assert(r_pkgList != (char ***)NULL);
821 assert(a_argv != (char **)NULL);
822
823 /* entry debugging info */
824
825 echoDebug(DBG_PKGOPS_GETPKGLIST_ENTRY);
826 echoDebug(DBG_PKGOPS_GETPKGLIST_ARGS, a_pkgdev->dirname,
827 a_categories ? a_categories : "?");
828
829 /* reset returned package list handle */
830
831 *r_pkgList = (char **)NULL;
832
833 /*
834 * generate list of packages to be removed: if removing by category,
835 * then generate package list based on all packages by category,
836 * else generate package list based on all packages specified.
837 */
838
839 if (a_categories != NULL) {
840 /* generate package list from all packages in given category */
841
842 *r_pkgList = gpkglist(a_pkgdev->dirname, &all_pkgs[0],
843 a_categoryList);
844
845 if (*r_pkgList == NULL) {
846 echoDebug(DBG_PKGOPS_GPKGLIST_CATFAILED, a_categories);
847 progerr(ERR_CAT_FND, a_categories);
848 return (1);
849 }
850
851 echoDebug(DBG_PKGOPS_GPKGLIST_CATOK, a_categories);
852
853 return (0);
854 }
855
856 /* generate package list from specified packages */
857
858 *r_pkgList = gpkglist(a_pkgdev->dirname, &a_argv[a_optind], NULL);
859
860 /* if list generated return results */
861
862 if (*r_pkgList != NULL) {
863 echoDebug(DBG_PKGOPS_GPKGLIST_OK);
864 return (0);
865 }
866
867 /* handle error from gpkglist */
868
869 switch (errno) {
870 case ENOPKG: /* no packages */
871 echoDebug(DBG_PKGOPS_GPKGLIST_ENOPKG);
872 return (-1);
873
874 case ESRCH:
875 echoDebug(DBG_PKGOPS_GPKGLIST_ESRCH);
876 return (1);
877
878 case EINTR:
879 echoDebug(DBG_PKGOPS_GPKGLIST_EINTR);
880 return (3);
881
882 default:
883 echoDebug(DBG_PKGOPS_GPKGLIST_UNKNOWN, errno);
884 progerr(ERR_GPKGLIST_ERROR);
885 return (99);
886 }
887 }
888
889 /*
890 * return string representing path to "global zone only file"
891 */
892
893 char *
pkgGetGzOnlyPath(void)894 pkgGetGzOnlyPath(void)
895 {
896 return (GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
897 }
898
899 /*
900 * Name: pkgAddThisZonePackage
901 * Description: Add specified package to internal list of "this zone only" pkgs
902 * Arguments: a_pkgInst - name of package to add to list
903 * Returns: void
904 */
905
906 void
pkgAddThisZonePackage(char * a_pkgInst)907 pkgAddThisZonePackage(char *a_pkgInst)
908 {
909 /* entry assertions */
910
911 assert(a_pkgInst != (char *)NULL);
912 assert(*a_pkgInst != '\0');
913
914 /* do not duplicate entries */
915
916 if (pkgPackageIsThisZone(a_pkgInst) == B_TRUE) {
917 return;
918 }
919
920 /* add package name to internal list */
921
922 if (thisZonePackages == (char **)NULL) {
923 thisZonePackages =
924 (char **)calloc(2, sizeof (char **));
925 } else {
926 thisZonePackages =
927 (char **)realloc(thisZonePackages,
928 sizeof (char **)*(numThisZonePackages+2));
929 }
930
931 /* handle out of memory error */
932
933 if (thisZonePackages == (char **)NULL) {
934 progerr(ERR_MEMORY, errno);
935 quit(99);
936 }
937
938 /* add this entry to the end of the list */
939
940 thisZonePackages[numThisZonePackages] = strdup(a_pkgInst);
941 if (thisZonePackages[numThisZonePackages] == (char *)NULL) {
942 progerr(ERR_MEMORY, errno);
943 quit(99);
944 }
945
946 numThisZonePackages++;
947
948 /* make sure end of the list is properly terminated */
949
950 thisZonePackages[numThisZonePackages] = (char *)NULL;
951
952 /* exit debugging info */
953
954 echoDebug(DBG_PKGOPS_ADD_TZP, numThisZonePackages,
955 thisZonePackages[numThisZonePackages-1]);
956 }
957
958 /*
959 * Name: pkgPackageIsThisZone
960 * Description: Determine if the specified package is marked to be installed
961 * in this zone only
962 * Arguments: a_pkgInst - pointer to string representing package name to check
963 * Returns: boolean_t
964 * B_TRUE - the package IS "this zone only"
965 * B_FALSE - the paackage is NOT "this zone only"
966 */
967
968 boolean_t
pkgPackageIsThisZone(char * a_pkgInst)969 pkgPackageIsThisZone(char *a_pkgInst)
970 {
971 int n;
972
973 /* entry assertions */
974
975 assert(a_pkgInst != (char *)NULL);
976 assert(*a_pkgInst != '\0');
977
978 /*
979 * see if this package is in the "this zone only" list
980 */
981
982 for (n = 0; n < numThisZonePackages; n++) {
983 if (strcmp(a_pkgInst, thisZonePackages[n]) == 0) {
984 echoDebug(DBG_PKGOPS_IS_THISZONE, a_pkgInst);
985 return (B_TRUE);
986 }
987 }
988
989 /* path is not in "this zone only" list */
990
991 echoDebug(DBG_PKGOPS_IS_NOT_THISZONE, a_pkgInst);
992
993 return (B_FALSE);
994 }
995
996 /*
997 * Name: pkgLocateHighestInst
998 * Description: Locate the highest installed instance of a package
999 * Arguments: r_path - [RO, *RW] - (char *)
1000 * Pointer to buffer where the full path to the top level
1001 * directory containing the latest instance of the
1002 * specified package is located is placed.
1003 * r_pathLen - [RO, *RO] - (int)
1004 * Integer representing the size of r_path in bytes.
1005 * r_pkgInst - [RO, *RW] - (char *)
1006 * Pointer to buffer where the package instance name of the
1007 * latest instance of the specified package is placed.
1008 * r_pkgInstLen - [RO, *RO] - (int)
1009 * Integer representing the size of r_pkgInst in bytes.
1010 * a_rootPath - [RO, *RO] - (char *)
1011 * Pointer to string representing the root path to look
1012 * for the latest instance of the specified package.
1013 * a_pkgInst - [RO, *RO] - (char *)
1014 * Pointer to string representing the name of the package
1015 * to locate the latest installed instance of.
1016 */
1017
1018 void
pkgLocateHighestInst(char * r_path,int r_pathLen,char * r_pkgInst,int r_pkgInstLen,char * a_rootPath,char * a_pkgInst)1019 pkgLocateHighestInst(char *r_path, int r_pathLen, char *r_pkgInst,
1020 int r_pkgInstLen, char *a_rootPath, char *a_pkgInst)
1021 {
1022 char pkgInstPath[PATH_MAX] = {'\0'};
1023 char pkgWild[PKGSIZ+1] = {'\0'};
1024 char pkgName[PKGSIZ+1] = {'\0'};
1025 int npkgs;
1026 struct pkginfo *pinf = (struct pkginfo *)NULL;
1027
1028 /* entry assertions */
1029
1030 assert(r_path != (char *)NULL);
1031 assert(r_pathLen > 0);
1032 assert(r_pkgInst != (char *)NULL);
1033 assert(r_pkgInstLen > 0);
1034 assert(a_pkgInst != (char *)NULL);
1035 assert(*a_pkgInst != '\0');
1036
1037 /* normalize root path */
1038
1039 if ((a_rootPath == (char *)NULL) || (strcmp(a_rootPath, "/") == 0)) {
1040 a_rootPath = "";
1041 }
1042
1043 /* construct path to package repository directory (eg. /var/sadm/pkg) */
1044
1045 (void) snprintf(pkgInstPath, sizeof (pkgInstPath), "%s%s", a_rootPath,
1046 PKGLOC);
1047
1048 /* entry debugging info */
1049
1050 echoDebug(DBG_PKGOPS_LOCHIGH_ENTRY);
1051 echoDebug(DBG_PKGOPS_LOCHIGH_ARGS, pkgInstPath, a_pkgInst);
1052
1053 /* reset returned path/package instance so both ares empty */
1054
1055 *r_path = '\0';
1056 *r_pkgInst = '\0';
1057
1058 /* remove any architecture extension */
1059
1060 pkgstrGetToken_r((char *)NULL, a_pkgInst, 0, ".",
1061 pkgName, sizeof (pkgName));
1062
1063 /* make sure that the package name is valid and can be wild carded */
1064
1065 if (pkgnmchk(pkgName, NULL, 0) || strchr(pkgName, '.')) {
1066 progerr(ERR_PKGOPS_LOCHIGH_BAD_PKGNAME, pkgName);
1067 quit(99);
1068 }
1069
1070 /* create wild card specification for this package instance */
1071
1072 (void) snprintf(pkgWild, sizeof (pkgWild), "%s.*", pkgName);
1073
1074 echoDebug(DBG_PKGOPS_LOCHIGH_WILDCARD, pkgName, pkgWild);
1075
1076 /*
1077 * inspect the system to determine if any instances of the
1078 * package being installed already exist on the system
1079 */
1080
1081 for (npkgs = 0; ; npkgs++) {
1082 char *savePkgdir;
1083 int r;
1084
1085 /* allocate new pinfo structure for use in the pkginfo call */
1086
1087 pinf = _pkginfoFactory();
1088
1089 /*
1090 * lookup the specified package; the first call will cause the
1091 * pkgdir directory to be opened - it will be closed when the
1092 * end of directory is read and pkginfo() returns != 0. You must
1093 * cycle through all instances until pkginfo() returns != 0.
1094 * NOTE: pkginfo() requires the global variable 'pkgdir' be set
1095 * to the package installed directory (<root>/var/sadm/pkg).
1096 */
1097
1098 savePkgdir = pkgdir;
1099 pkgdir = pkgInstPath;
1100
1101 r = pkginfo(pinf, pkgWild, NULL, NULL);
1102
1103 pkgdir = savePkgdir;
1104
1105 echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, pkgName, r);
1106
1107 /* break out of loop of no package found */
1108
1109 if (r != 0) {
1110 pkginfoFree(&pinf);
1111 break;
1112 }
1113
1114 echoDebug(DBG_PKGOPS_LOCHIGH_INSTANCE, npkgs,
1115 pinf->pkginst ? pinf->pkginst : "",
1116 pinf->name ? pinf->name : "",
1117 pinf->arch ? pinf->arch : "",
1118 pinf->version ? pinf->version : "",
1119 pinf->vendor ? pinf->vendor : "",
1120 pinf->basedir ? pinf->basedir : "",
1121 pinf->catg ? pinf->catg : "",
1122 pinf->status);
1123
1124 /* save path/instance name for this instance found */
1125
1126 (void) strlcpy(r_pkgInst, pinf->pkginst, r_pkgInstLen);
1127 pkgstrPrintf_r(r_path, r_pathLen, "%s%s/%s", a_rootPath,
1128 PKGLOC, pinf->pkginst);
1129
1130 pkginfoFree(&pinf);
1131 }
1132
1133 echoDebug(DBG_PKGOPS_LOCHIGH_RETURN, npkgs, r_pkgInst, r_path);
1134 }
1135
1136 /*
1137 * Name: pkgTestInstalled
1138 * Description: determine if package is installed at specified root path
1139 * Arguments: a_packageName - name of package to test
1140 * a_rootPath - root path of alternative root to test
1141 * Returns: B_TRUE - package is installed
1142 * B_FALSE - package is not installed
1143 */
1144
1145 boolean_t
pkgTestInstalled(char * a_packageName,char * a_rootPath)1146 pkgTestInstalled(char *a_packageName, char *a_rootPath)
1147 {
1148 char cmd[MAXPATHLEN+1];
1149 int rc;
1150
1151 /* entry assertions */
1152
1153 assert(a_packageName != NULL);
1154 assert(*a_packageName != '\0');
1155 assert(a_rootPath != NULL);
1156 assert(*a_rootPath != '\0');
1157
1158 /* entry debugging info */
1159
1160 echoDebug(DBG_PKG_TEST_EXISTENCE, a_packageName, a_rootPath);
1161
1162 /*
1163 * create pkginfo command to execute:
1164 * /usr/bin/pkginfo -q <packageName>
1165 */
1166 (void) snprintf(cmd, sizeof (cmd),
1167 "%s -q %s", PKGINFO_CMD, a_packageName);
1168
1169 /* execute command */
1170
1171 rc = system(cmd);
1172
1173 /* return success if pkginfo returns "0" */
1174
1175 if (rc == 0) {
1176 echoDebug(DBG_PKG_INSTALLED, a_packageName, a_rootPath);
1177 return (B_TRUE);
1178 }
1179
1180 /* package not installed */
1181
1182 echoDebug(DBG_PKG_NOT_INSTALLED, a_packageName, a_rootPath);
1183
1184 return (B_FALSE);
1185 }
1186
1187 /*
1188 * *****************************************************************************
1189 * static internal (private) functions
1190 * *****************************************************************************
1191 */
1192
1193 static void
_pkginfoInit(struct pkginfo * a_info)1194 _pkginfoInit(struct pkginfo *a_info)
1195 {
1196 /* entry assertions */
1197
1198 assert(a_info != (struct pkginfo *)NULL);
1199
1200 /* free previously allocated space */
1201
1202 if (a_info->pkginst) {
1203 free(a_info->pkginst);
1204 if (a_info->arch)
1205 free(a_info->arch);
1206 if (a_info->version)
1207 free(a_info->version);
1208 if (a_info->basedir)
1209 free(a_info->basedir);
1210 if (a_info->name)
1211 free(a_info->name);
1212 if (a_info->vendor)
1213 free(a_info->vendor);
1214 if (a_info->catg)
1215 free(a_info->catg);
1216 }
1217
1218 a_info->pkginst = NULL;
1219 a_info->arch = a_info->version = NULL;
1220 a_info->basedir = a_info->name = NULL;
1221 a_info->vendor = a_info->catg = NULL;
1222 a_info->status = PI_UNKNOWN;
1223 }
1224
1225 static struct pkginfo *
_pkginfoFactory(void)1226 _pkginfoFactory(void)
1227 {
1228 struct pkginfo *pinf;
1229
1230 pinf = (struct pkginfo *)calloc(1, sizeof (struct pkginfo));
1231 if (pinf == (struct pkginfo *)NULL) {
1232 progerr(ERR_MEM);
1233 exit(1);
1234 }
1235
1236 _pkginfoInit(pinf);
1237 return (pinf);
1238 }
1239