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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <dirent.h>
37 #include <sys/types.h>
38 #include <pkgstrct.h>
39 #include <pkginfo.h>
40 #include <locale.h>
41 #include <libintl.h>
42 #include <pkglib.h>
43 #include "libinst.h"
44 #include "libadm.h"
45 #include "messages.h"
46
47 #define LSIZE 256
48 #define NVERS 50
49
50 /*
51 * internal global variables
52 */
53
54 static struct pkginfo info;
55
56 static char type;
57 static char *alist[NVERS];
58 static char *rmpkginst;
59 static char *vlist[NVERS];
60 static char file[128];
61 static char name[128];
62 static char rmpkg[PKGSIZ+1];
63 static char wabbrev[128];
64
65 static int errflg = 0;
66 static int nlist;
67 static int pkgexist;
68 static int pkgokay;
69 static int is_update;
70 static int is_patch_update;
71
72 /*
73 * IMPORTANT NOTE: THE SIZE OF 'abbrev' IS HARD CODED INTO THE CHARACTER
74 * ARRAY SSCANF_FORMAT -- YOU MUST UPDATE BOTH VALUES AT THE SAME TIME!!
75 */
76
77 static char abbrev[128+1];
78 static char *SSCANF_FORMAT = "%c %128s %[^\n]";
79
80 /*
81 * forward declarations
82 */
83
84 static void ckrdeps(boolean_t a_preinstallCheck);
85 static void ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck);
86 static void deponme(char *pkginst, char *pkgname,
87 boolean_t a_preinstallCheck);
88 static void prereq(char *pkginst, char *pkgname,
89 boolean_t a_preinstallCheck);
90 static void incompat(char *pkginst, char *pkgname,
91 boolean_t a_preinstallCheck);
92 static int getaline(FILE *fp);
93
94 /*
95 * *****************************************************************************
96 * global external (public) functions
97 * *****************************************************************************
98 */
99
100 int
dockdeps(char * a_depfile,int a_removeFlag,boolean_t a_preinstallCheck)101 dockdeps(char *a_depfile, int a_removeFlag, boolean_t a_preinstallCheck)
102 {
103 FILE *fp;
104 int i;
105 char *inst;
106
107 if (a_removeFlag) {
108 /* check removal dependencies */
109 rmpkginst = a_depfile;
110 (void) strncpy(rmpkg, rmpkginst, PKGSIZ);
111 (void) strtok(rmpkg, ".");
112 (void) snprintf(file, sizeof (file),
113 "%s/%s/%s", pkgdir, rmpkginst, DEPEND_FILE);
114 if ((fp = fopen(file, "r")) == NULL)
115 goto done;
116 } else {
117 if ((fp = fopen(a_depfile, "r")) == NULL) {
118 progerr(ERR_CANNOT_OPEN_DEPEND_FILE, a_depfile,
119 strerror(errno));
120 quit(99);
121 }
122 }
123
124 while (getaline(fp)) {
125 switch (type) {
126 case 'I':
127 case 'P':
128 if (a_removeFlag) {
129 continue;
130 }
131 break;
132
133 case 'R':
134 if (!a_removeFlag) {
135 continue;
136 }
137 break;
138
139 default:
140 errflg++;
141 progerr(ERR_UNKNOWN_DEPENDENCY, type);
142 break;
143 }
144
145 /* check to see if any versions listed are installed */
146 pkgexist = pkgokay = 0;
147 i = 0;
148 if (strchr(abbrev, '.')) {
149 progerr(ERR_PKGABRV, abbrev);
150 }
151 (void) snprintf(wabbrev, sizeof (wabbrev), "%s.*", abbrev);
152
153 do {
154 inst = fpkginst(wabbrev, alist[i], vlist[i]);
155 if (inst && (pkginfo(&info, inst, NULL, NULL) == 0)) {
156 pkgexist++;
157 if ((info.status == PI_INSTALLED) ||
158 (info.status == PI_PRESVR4))
159 pkgokay++;
160 }
161 } while (++i < nlist);
162 (void) fpkginst(NULL); /* force closing/rewind of files */
163
164 if (!info.name) {
165 info.name = name;
166 }
167
168 switch (type) {
169 case 'I':
170 incompat(abbrev, info.name, a_preinstallCheck);
171 break;
172
173 case 'P':
174 prereq(abbrev, name, a_preinstallCheck);
175 break;
176
177 case 'R':
178 deponme(abbrev, info.name, a_preinstallCheck);
179 }
180 }
181 (void) fclose(fp);
182
183 done:
184 if (a_removeFlag) {
185 ckrdeps(a_preinstallCheck);
186 }
187
188 return (errflg);
189 }
190
191 void
setPatchUpdate(void)192 setPatchUpdate(void)
193 {
194 is_patch_update = 1;
195 }
196
197 int
isPatchUpdate(void)198 isPatchUpdate(void)
199 {
200 return ((is_patch_update) ? 1 : 0);
201 }
202
203 void
setUpdate(void)204 setUpdate(void)
205 {
206 is_update = 1;
207 }
208
209 int
isUpdate(void)210 isUpdate(void)
211 {
212 return ((is_update) ? 1 : 0);
213 }
214
215 /*
216 * *****************************************************************************
217 * static internal (private) functions
218 * *****************************************************************************
219 */
220
221 static void
incompat(char * pkginst,char * pkgname,boolean_t a_preinstallCheck)222 incompat(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
223 {
224 char buf[512];
225
226 if (!pkgexist)
227 return;
228
229 errflg++;
230 if (a_preinstallCheck == B_TRUE) {
231 (void) fprintf(stdout, "incompat=%s\n", pkginst);
232 return;
233 }
234
235 logerr(ERR_WARNING);
236 (void) snprintf(buf, sizeof (buf), ERR_INCOMP_VERS, pkginst, pkgname);
237 puttext(stderr, buf, 4, 0);
238 (void) putc('\n', stderr);
239 }
240
241 static void
prereq(char * pkginst,char * pkgname,boolean_t a_preinstallCheck)242 prereq(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
243 {
244 register int i;
245 char buf[512];
246
247 if (pkgokay) {
248 return;
249 }
250
251 errflg++;
252
253 if (a_preinstallCheck == B_TRUE) {
254 if (pkgexist) {
255 (void) fprintf(stdout,
256 "prerequisite-incomplete=%s\n", pkginst);
257 } else {
258 (void) fprintf(stdout,
259 "prerequisite-installed=%s\n", pkginst);
260 }
261 return;
262 }
263
264 logerr(ERR_WARNING);
265 if (pkgexist) {
266 (void) snprintf(buf, sizeof (buf), ERR_PRENCI, pkginst,
267 pkgname);
268 puttext(stderr, buf, 4, 0);
269 (void) putc('\n', stderr);
270 } else {
271 (void) snprintf(buf, sizeof (buf), ERR_PREREQ, pkginst,
272 pkgname);
273 if (nlist) {
274 (void) strcat(buf, ERR_VALINST);
275 }
276 puttext(stderr, buf, 4, 0);
277 (void) putc('\n', stderr);
278 for (i = 0; i < nlist; i++) {
279 (void) printf(" ");
280 if (alist[i])
281 (void) printf("(%s) ", alist[i]);
282 if (vlist[i])
283 (void) printf("%s", vlist[i]);
284 (void) printf("\n");
285 }
286 }
287 }
288
289 static void
deponme(char * pkginst,char * pkgname,boolean_t a_preinstallCheck)290 deponme(char *pkginst, char *pkgname, boolean_t a_preinstallCheck)
291 {
292 char buf[512];
293
294 if (!pkgexist)
295 return;
296
297 errflg++;
298
299 if (a_preinstallCheck == B_TRUE) {
300 if (!pkgname || !pkgname[0]) {
301 (void) snprintf(buf, sizeof (buf),
302 "dependonme=%s", pkginst);
303 } else {
304 (void) snprintf(buf, sizeof (buf),
305 "dependsonme=%s:%s", pkginst, pkgname);
306 }
307 (void) fprintf(stdout, "%s\n", buf);
308 return;
309 }
310
311 logerr(ERR_WARNING);
312 if (!pkgname || !pkgname[0]) {
313 (void) snprintf(buf, sizeof (buf), ERR_DEPONME, pkginst);
314 } else {
315 (void) snprintf(buf, sizeof (buf), ERR_DEPNAM, pkginst,
316 pkgname);
317 }
318 puttext(stderr, buf, 4, 0);
319 (void) putc('\n', stderr);
320 }
321
322 static int
getaline(FILE * fp)323 getaline(FILE *fp)
324 {
325 register int i, c, found;
326 char *pt, *new, line[LSIZE];
327
328 abbrev[0] = name[0] = type = '\0';
329
330 for (i = 0; i < nlist; i++) {
331 if (alist[i]) {
332 free(alist[i]);
333 alist[i] = NULL;
334 }
335 if (vlist[i]) {
336 free(vlist[i]);
337 vlist[i] = NULL;
338 }
339 }
340 alist[0] = vlist[0] = NULL;
341
342 found = (-1);
343 nlist = 0;
344 while ((c = getc(fp)) != EOF) {
345 (void) ungetc(c, fp);
346 if ((found >= 0) && !isspace(c))
347 return (1);
348
349 if (!fgets(line, LSIZE, fp))
350 break;
351
352 for (pt = line; isspace(*pt); /* void */)
353 pt++;
354 if (!*pt || (*pt == '#'))
355 continue;
356
357 if (pt == line) {
358 /* begin new definition */
359 /* LINTED variable format specifier to sscanf(): */
360 (void) sscanf(line, SSCANF_FORMAT, &type, abbrev, name);
361 found++;
362 continue;
363 }
364 if (found < 0)
365 return (0);
366
367 if (*pt == '(') {
368 /* architecture is specified */
369 if (new = strchr(pt, ')'))
370 *new++ = '\0';
371 else
372 return (-1); /* bad specification */
373 alist[found] = qstrdup(pt+1);
374 pt = new;
375 }
376 while (isspace(*pt))
377 pt++;
378 if (*pt) {
379 vlist[found] = qstrdup(pt);
380 if (pt = strchr(vlist[found], '\n'))
381 *pt = '\0';
382 }
383 found++;
384 nlist++;
385 }
386 return ((found >= 0) ? 1 : 0);
387 }
388
389 static void
ckrdeps(boolean_t a_preinstallCheck)390 ckrdeps(boolean_t a_preinstallCheck)
391 {
392 struct dirent *drp;
393 DIR *dirfp;
394 FILE *fp;
395 char depfile[PATH_MAX+1];
396
397 if ((dirfp = opendir(pkgdir)) == NULL)
398 return;
399
400 while ((drp = readdir(dirfp)) != NULL) {
401 if (drp->d_name[0] == '.')
402 continue;
403
404 if (strcmp(drp->d_name, rmpkginst) == 0)
405 continue; /* others don't include me */
406 (void) snprintf(depfile, sizeof (depfile),
407 "%s/%s/%s", pkgdir, drp->d_name, DEPEND_FILE);
408 if ((fp = fopen(depfile, "r")) == NULL)
409 continue;
410
411 ckpreq(fp, drp->d_name, a_preinstallCheck);
412 }
413 (void) closedir(dirfp);
414 }
415
416 static void
ckpreq(FILE * fp,char * dname,boolean_t a_preinstallCheck)417 ckpreq(FILE *fp, char *dname, boolean_t a_preinstallCheck)
418 {
419 register int i;
420 char *inst;
421
422 while (getaline(fp)) {
423 if (type != 'P')
424 continue;
425
426 if (strcmp(abbrev, rmpkg))
427 continue;
428
429 /* see if package is installed */
430 i = 0;
431 if (strchr(abbrev, '.') == 0) {
432 (void) strcat(abbrev, ".*");
433 }
434 pkgexist = 1;
435
436 do {
437 if (inst = fpkginst(abbrev, alist[i], vlist[i])) {
438 if (strcmp(inst, rmpkginst) == 0) {
439 deponme(dname, "", a_preinstallCheck);
440 (void) fclose(fp);
441 (void) fpkginst(NULL);
442 return;
443 }
444 }
445 } while (++i < nlist);
446 (void) fpkginst(NULL);
447 }
448 (void) fclose(fp);
449 }
450