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