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