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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /*LINTLIBRARY*/
32
33 /* 5-20-92 added newroot functions */
34
35 #include <stdio.h>
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <dirent.h>
45 #include <pkginfo.h>
46 #include <pkgstrct.h>
47 #include <pkglocs.h>
48 #include <errno.h>
49 #include "libadm.h"
50
51 static void initpkg(struct pkginfo *);
52 static int rdconfig(struct pkginfo *, char *, char *);
53 static int ckinfo(char *, char *, char *);
54 static int ckinst(char *, char *, char *, char *, char *);
55 static int verscmp(char *, char *);
56 static int archcmp(char *, char *);
57 static int compver(char *, char *);
58
59 /*
60 * Globals:
61 * pkgdir - specifies the directory where information about packages
62 * resides, i.e. the pkginfo file is located in a subdirectory
63 *
64 * Caveats:
65 * The structure provided via "info" will contain malloc'd information;
66 * this will be free'd upon the next call to pkginfo with this
67 * same structure. Application calls must make sure this structure
68 * is null on the first call, or else we'll free static memory areas
69 * If the "pkg" argument is a wildcard specification, the next found
70 * instance available which matches the request will be returned
71 * If the "pkg" argument is a NULL pointer, the structure pointed to
72 * via "info" will have its elements deallocated and all files
73 * associated with this routine will be closed
74 *
75 * Return codes:
76 * A non-zero exit code indicates error with "errno" appropriately set:
77 * EINVAL - invalid argument
78 * ESRCH - there are no more instances of this package around
79 * EACCESS - unable to access files which should have been there
80 */
81
82 /*VARARGS*/
83 int
pkginfo(struct pkginfo * info,char * pkginst,...)84 pkginfo(struct pkginfo *info, char *pkginst, ...)
85 {
86 char *ckarch, *ckvers;
87 int check;
88 va_list ap;
89
90 va_start(ap, pkginst);
91 if (info == NULL) {
92 errno = EINVAL;
93 return (-1);
94 }
95 if (pkginst == NULL) {
96 info->pkginst = NULL;
97 (void) fpkginfo(info, NULL);
98 (void) fpkginst(NULL);
99 return (0);
100 }
101 ckarch = va_arg(ap, char *);
102 ckvers = va_arg(ap, char *);
103 va_end(ap);
104
105 check = 0;
106 if (pkgnmchk(pkginst, "all", 1)) {
107 /* wild card specification */
108 pkginst = fpkginst(pkginst, ckarch, ckvers);
109 if (pkginst == NULL)
110 return (-1);
111 } else {
112 /* request to check indicated instance */
113 if (ckarch || ckvers)
114 check++;
115 }
116
117 info->pkginst = NULL;
118 if (fpkginfo(info, pkginst))
119 return (-1);
120
121 if (check) {
122 /*
123 * verify that the provided instance matches
124 * any arch & vers specs that were provided
125 */
126 if (ckinst(pkginst, info->arch, info->version, ckarch,
127 ckvers)) {
128 errno = ESRCH;
129 return (-1);
130 }
131 }
132 return (0);
133 }
134 /*ARGSUSED*/
135
136 int
fpkginfo(struct pkginfo * info,char * pkginst)137 fpkginfo(struct pkginfo *info, char *pkginst)
138 {
139
140 if (info == NULL) {
141 errno = EINVAL;
142 return (-1);
143 }
144
145 initpkg(info);
146
147 if (pkginst == NULL)
148 return (0);
149 else if (pkgnmchk(pkginst, "all", 1)) {
150 errno = EINVAL; /* not an instance identifier */
151 return (-1);
152 }
153 if (pkgdir == NULL)
154 pkgdir = get_PKGLOC();
155
156 if (rdconfig(info, pkginst, NULL)) {
157 initpkg(info);
158 return (-1);
159 }
160 return (0);
161 }
162
163 static void
initpkg(struct pkginfo * info)164 initpkg(struct pkginfo *info)
165 {
166 /* free previously allocated space */
167 if (info->pkginst) {
168 free(info->pkginst);
169 if (info->arch)
170 free(info->arch);
171 if (info->version)
172 free(info->version);
173 if (info->basedir)
174 free(info->basedir);
175 if (info->name)
176 free(info->name);
177 if (info->vendor)
178 free(info->vendor);
179 if (info->catg)
180 free(info->catg);
181 }
182
183 info->pkginst = NULL;
184 info->arch = info->version = NULL;
185 info->basedir = info->name = NULL;
186 info->vendor = info->catg = NULL;
187 info->status = PI_UNKNOWN;
188 }
189
190 static int
rdconfig(struct pkginfo * info,char * pkginst,char * ckvers)191 rdconfig(struct pkginfo *info, char *pkginst, char *ckvers)
192 {
193 FILE *fp;
194 char temp[256];
195 char *value, *pt, *copy, **memloc;
196 int count;
197
198 if ((fp = pkginfopen(pkgdir, pkginst)) == NULL) {
199 errno = EACCES;
200 return (-1);
201 }
202
203 *temp = '\0';
204 count = 0;
205 while (value = fpkgparam(fp, temp)) {
206 if (strcmp(temp, "ARCH") == 0 ||
207 strcmp(temp, "CATEGORY") == 0) {
208 /* remove all whitespace from value */
209 pt = copy = value;
210 while (*pt) {
211 if (!isspace((unsigned char)*pt))
212 *copy++ = *pt;
213 pt++;
214 }
215 *copy = '\0';
216 }
217 count++;
218 memloc = NULL;
219 if (strcmp(temp, "NAME") == 0)
220 memloc = &info->name;
221 else if (strcmp(temp, "VERSION") == 0)
222 memloc = &info->version;
223 else if (strcmp(temp, "ARCH") == 0)
224 memloc = &info->arch;
225 else if (strcmp(temp, "VENDOR") == 0)
226 memloc = &info->vendor;
227 else if (strcmp(temp, "BASEDIR") == 0)
228 memloc = &info->basedir;
229 else if (strcmp(temp, "CATEGORY") == 0)
230 memloc = &info->catg;
231
232 temp[0] = '\0';
233 if (memloc == NULL)
234 continue; /* not a parameter we're looking for */
235
236 *memloc = strdup(value);
237 if (!*memloc) {
238 (void) fclose(fp);
239 errno = ENOMEM;
240 return (-1); /* malloc from strdup failed */
241 }
242 }
243 (void) fclose(fp);
244
245 if (!count) {
246 errno = ESRCH;
247 return (-1);
248 }
249
250 info->status = (strcmp(pkgdir, get_PKGLOC()) ? PI_SPOOLED :
251 PI_INSTALLED);
252
253 if (info->status == PI_INSTALLED) {
254 (void) snprintf(temp, sizeof (temp),
255 "%s/%s/!I-Lock!", pkgdir, pkginst);
256 if (access(temp, 0) == 0)
257 info->status = PI_PARTIAL;
258 else {
259 (void) snprintf(temp, sizeof (temp),
260 "%s/%s/!R-Lock!", pkgdir, pkginst);
261 if (access(temp, 0) == 0)
262 info->status = PI_PARTIAL;
263 }
264 }
265 info->pkginst = strdup(pkginst);
266 return (0);
267 }
268
269 static int
ckinst(char * pkginst,char * pkgarch,char * pkgvers,char * ckarch,char * ckvers)270 ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers)
271 {
272 if (ckarch && archcmp(ckarch, pkgarch))
273 return (-1);
274 if (ckvers) {
275 /* Check for exact version match */
276 if (verscmp(ckvers, pkgvers)) {
277 /* Check for compatable version */
278 if (compver(pkginst, ckvers))
279 return (-1);
280 }
281 }
282 return (0);
283 }
284
285 /*VARARGS*/
286 char *
fpkginst(char * pkg,...)287 fpkginst(char *pkg, ...)
288 {
289 static char pkginst[PKGSIZ+1];
290 static DIR *pdirfp;
291 struct dirent64 *dp;
292 char *ckarch, *ckvers;
293 va_list ap;
294
295 va_start(ap, pkg);
296
297 if (pkg == NULL) {
298 /* request to close or rewind the file */
299 if (pdirfp) {
300 (void) closedir(pdirfp);
301 pdirfp = NULL;
302 }
303 return (NULL);
304 }
305
306 ckarch = va_arg(ap, char *);
307 ckvers = va_arg(ap, char *);
308 va_end(ap);
309
310 if (!pkgdir)
311 pkgdir = get_PKGLOC();
312
313 if (!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) {
314 errno = EACCES;
315 return (NULL);
316 }
317
318 while ((dp = readdir64(pdirfp)) != NULL) {
319 if (dp->d_name[0] == '.')
320 continue;
321
322 if (pkgnmchk(dp->d_name, pkg, 0))
323 continue; /* ignore invalid SVR4 package names */
324
325 if (ckinfo(dp->d_name, ckarch, ckvers))
326 continue;
327
328 /*
329 * Leave directory open in case user requests another
330 * instance.
331 */
332 (void) strcpy(pkginst, dp->d_name);
333 return (pkginst);
334 }
335
336 errno = ESRCH;
337 /* close any file we might have open */
338 (void) closedir(pdirfp);
339 pdirfp = NULL;
340 return (NULL);
341 }
342
343 static int
verscmp(char * request,char * actual)344 verscmp(char *request, char *actual)
345 {
346 /* eat leading white space */
347 while (isspace((unsigned char)*actual))
348 actual++;
349 while (isspace((unsigned char)*request))
350 request++;
351
352 while (*request || *actual) {
353 /*
354 * Once the pointers don't match, return an error condition.
355 */
356
357 if (*request++ != *actual++)
358 return (-1);
359
360 /* eat white space if any in both the strings */
361 if (isspace((unsigned char)*request)) {
362 if (*actual && !isspace((unsigned char)*actual))
363 return (-1);
364 while (isspace((unsigned char)*request))
365 request++;
366 while (isspace((unsigned char)*actual))
367 actual++;
368 }
369 }
370
371 return (0);
372
373 }
374
375 static int
compver(char * pkginst,char * version)376 compver(char *pkginst, char *version)
377 {
378 FILE *fp;
379 char temp[256];
380
381 (void) snprintf(temp, sizeof (temp),
382 "%s/%s/install/compver", get_PKGLOC(), pkginst);
383 if ((fp = fopen(temp, "r")) == NULL)
384 return (-1);
385
386 while (fgets(temp, 256, fp)) {
387 if (*temp == '#')
388 continue;
389 if (verscmp(temp, version) == 0) {
390 (void) fclose(fp);
391 return (0);
392 }
393 }
394 (void) fclose(fp);
395 return (-1);
396 }
397
398 static int
archcmp(char * arch,char * archlist)399 archcmp(char *arch, char *archlist)
400 {
401 char *pt;
402
403 if (arch == NULL)
404 return (0);
405
406 /* arch and archlist must not contain whitespace! */
407
408 while (*archlist) {
409 for (pt = arch; *pt && (*pt == *archlist); )
410 pt++, archlist++;
411 if (!*pt && (!*archlist || (*archlist == ',')))
412 return (0);
413 while (*archlist) {
414 if (*archlist++ == ',')
415 break;
416 }
417 }
418 return (-1);
419 }
420
421 static int
ckinfo(char * inst,char * arch,char * vers)422 ckinfo(char *inst, char *arch, char *vers)
423 {
424 FILE *fp;
425 char temp[128];
426 char file[PATH_MAX];
427 char *pt, *copy, *value, *myarch, *myvers;
428 int errflg;
429
430 (void) snprintf(file, sizeof (file), "%s/%s/pkginfo", pkgdir, inst);
431 if ((fp = fopen(file, "r")) == NULL)
432 return (1);
433
434 if ((arch == NULL) && (vers == NULL)) {
435 (void) fclose(fp);
436 return (0);
437 }
438 temp[0] = '\0';
439 myarch = myvers = NULL;
440 while (value = fpkgparam(fp, temp)) {
441 if (strcmp(temp, "ARCH") == 0) {
442 /* remove all whitespace from value */
443 pt = copy = value;
444 while (*pt) {
445 if (!isspace((unsigned char)*pt))
446 *copy++ = *pt;
447 pt++;
448 }
449 *copy = '\0';
450 myarch = value;
451 if (myvers)
452 break;
453 } else if (strcmp(temp, "VERSION") == 0) {
454 myvers = value;
455 if (myarch)
456 break;
457 } else
458 free(value);
459 temp[0] = '\0';
460 }
461 (void) fclose(fp);
462 errflg = 0;
463
464 if (ckinst(inst, myarch, myvers, arch, vers))
465 errflg++;
466
467 if (myarch)
468 free(myarch);
469 if (myvers)
470 free(myvers);
471
472 return (errflg);
473 }
474