sd: remove 'ssd' driver support
[unleashed/tickless.git] / usr / src / lib / libadm / common / pkginfo.c
blob838ce4b63d7e5c8c99186df526b98ca49933817d
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /*LINTLIBRARY*/
33 /* 5-20-92 added newroot functions */
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"
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 *);
60 * Globals:
61 * pkgdir - specifies the directory where information about packages
62 * resides, i.e. the pkginfo file is located in a subdirectory
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
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
82 /*VARARGS*/
83 int
84 pkginfo(struct pkginfo *info, char *pkginst, ...)
86 char *ckarch, *ckvers;
87 int check;
88 va_list ap;
90 va_start(ap, pkginst);
91 if (info == NULL) {
92 errno = EINVAL;
93 return (-1);
95 if (pkginst == NULL) {
96 info->pkginst = NULL;
97 (void) fpkginfo(info, NULL);
98 (void) fpkginst(NULL);
99 return (0);
101 ckarch = va_arg(ap, char *);
102 ckvers = va_arg(ap, char *);
103 va_end(ap);
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++;
117 info->pkginst = NULL;
118 if (fpkginfo(info, pkginst))
119 return (-1);
121 if (check) {
123 * verify that the provided instance matches
124 * any arch & vers specs that were provided
126 if (ckinst(pkginst, info->arch, info->version, ckarch,
127 ckvers)) {
128 errno = ESRCH;
129 return (-1);
132 return (0);
134 /*ARGSUSED*/
137 fpkginfo(struct pkginfo *info, char *pkginst)
140 if (info == NULL) {
141 errno = EINVAL;
142 return (-1);
145 initpkg(info);
147 if (pkginst == NULL)
148 return (0);
149 else if (pkgnmchk(pkginst, "all", 1)) {
150 errno = EINVAL; /* not an instance identifier */
151 return (-1);
153 if (pkgdir == NULL)
154 pkgdir = get_PKGLOC();
156 if (rdconfig(info, pkginst, NULL)) {
157 initpkg(info);
158 return (-1);
160 return (0);
163 static void
164 initpkg(struct pkginfo *info)
166 /* free previously allocated space */
167 if (info->pkginst) {
168 free(info->pkginst);
169 free(info->arch);
170 free(info->version);
171 free(info->basedir);
172 free(info->name);
173 free(info->vendor);
174 free(info->catg);
177 info->pkginst = NULL;
178 info->arch = info->version = NULL;
179 info->basedir = info->name = NULL;
180 info->vendor = info->catg = NULL;
181 info->status = PI_UNKNOWN;
184 static int
185 rdconfig(struct pkginfo *info, char *pkginst, char *ckvers)
187 FILE *fp;
188 char temp[256];
189 char *value, *pt, *copy, **memloc;
190 int count;
192 if ((fp = pkginfopen(pkgdir, pkginst)) == NULL) {
193 errno = EACCES;
194 return (-1);
197 *temp = '\0';
198 count = 0;
199 while (value = fpkgparam(fp, temp)) {
200 if (strcmp(temp, "ARCH") == 0 ||
201 strcmp(temp, "CATEGORY") == 0) {
202 /* remove all whitespace from value */
203 pt = copy = value;
204 while (*pt) {
205 if (!isspace((unsigned char)*pt))
206 *copy++ = *pt;
207 pt++;
209 *copy = '\0';
211 count++;
212 memloc = NULL;
213 if (strcmp(temp, "NAME") == 0)
214 memloc = &info->name;
215 else if (strcmp(temp, "VERSION") == 0)
216 memloc = &info->version;
217 else if (strcmp(temp, "ARCH") == 0)
218 memloc = &info->arch;
219 else if (strcmp(temp, "VENDOR") == 0)
220 memloc = &info->vendor;
221 else if (strcmp(temp, "BASEDIR") == 0)
222 memloc = &info->basedir;
223 else if (strcmp(temp, "CATEGORY") == 0)
224 memloc = &info->catg;
226 temp[0] = '\0';
227 if (memloc == NULL)
228 continue; /* not a parameter we're looking for */
230 *memloc = strdup(value);
231 if (!*memloc) {
232 (void) fclose(fp);
233 errno = ENOMEM;
234 return (-1); /* malloc from strdup failed */
237 (void) fclose(fp);
239 if (!count) {
240 errno = ESRCH;
241 return (-1);
244 info->status = (strcmp(pkgdir, get_PKGLOC()) ? PI_SPOOLED :
245 PI_INSTALLED);
247 if (info->status == PI_INSTALLED) {
248 (void) snprintf(temp, sizeof (temp),
249 "%s/%s/!I-Lock!", pkgdir, pkginst);
250 if (access(temp, 0) == 0)
251 info->status = PI_PARTIAL;
252 else {
253 (void) snprintf(temp, sizeof (temp),
254 "%s/%s/!R-Lock!", pkgdir, pkginst);
255 if (access(temp, 0) == 0)
256 info->status = PI_PARTIAL;
259 info->pkginst = strdup(pkginst);
260 return (0);
263 static int
264 ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers)
266 if (ckarch && archcmp(ckarch, pkgarch))
267 return (-1);
268 if (ckvers) {
269 /* Check for exact version match */
270 if (verscmp(ckvers, pkgvers)) {
271 /* Check for compatable version */
272 if (compver(pkginst, ckvers))
273 return (-1);
276 return (0);
279 /*VARARGS*/
280 char *
281 fpkginst(char *pkg, ...)
283 static char pkginst[PKGSIZ+1];
284 static DIR *pdirfp;
285 struct dirent64 *dp;
286 char *ckarch, *ckvers;
287 va_list ap;
289 va_start(ap, pkg);
291 if (pkg == NULL) {
292 /* request to close or rewind the file */
293 if (pdirfp) {
294 (void) closedir(pdirfp);
295 pdirfp = NULL;
297 return (NULL);
300 ckarch = va_arg(ap, char *);
301 ckvers = va_arg(ap, char *);
302 va_end(ap);
304 if (!pkgdir)
305 pkgdir = get_PKGLOC();
307 if (!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) {
308 errno = EACCES;
309 return (NULL);
312 while ((dp = readdir64(pdirfp)) != NULL) {
313 if (dp->d_name[0] == '.')
314 continue;
316 if (pkgnmchk(dp->d_name, pkg, 0))
317 continue; /* ignore invalid SVR4 package names */
319 if (ckinfo(dp->d_name, ckarch, ckvers))
320 continue;
323 * Leave directory open in case user requests another
324 * instance.
326 (void) strcpy(pkginst, dp->d_name);
327 return (pkginst);
330 errno = ESRCH;
331 /* close any file we might have open */
332 (void) closedir(pdirfp);
333 pdirfp = NULL;
334 return (NULL);
337 static int
338 verscmp(char *request, char *actual)
340 /* eat leading white space */
341 while (isspace((unsigned char)*actual))
342 actual++;
343 while (isspace((unsigned char)*request))
344 request++;
346 while (*request || *actual) {
348 * Once the pointers don't match, return an error condition.
351 if (*request++ != *actual++)
352 return (-1);
354 /* eat white space if any in both the strings */
355 if (isspace((unsigned char)*request)) {
356 if (*actual && !isspace((unsigned char)*actual))
357 return (-1);
358 while (isspace((unsigned char)*request))
359 request++;
360 while (isspace((unsigned char)*actual))
361 actual++;
365 return (0);
369 static int
370 compver(char *pkginst, char *version)
372 FILE *fp;
373 char temp[256];
375 (void) snprintf(temp, sizeof (temp),
376 "%s/%s/install/compver", get_PKGLOC(), pkginst);
377 if ((fp = fopen(temp, "r")) == NULL)
378 return (-1);
380 while (fgets(temp, 256, fp)) {
381 if (*temp == '#')
382 continue;
383 if (verscmp(temp, version) == 0) {
384 (void) fclose(fp);
385 return (0);
388 (void) fclose(fp);
389 return (-1);
392 static int
393 archcmp(char *arch, char *archlist)
395 char *pt;
397 if (arch == NULL)
398 return (0);
400 /* arch and archlist must not contain whitespace! */
402 while (*archlist) {
403 for (pt = arch; *pt && (*pt == *archlist); )
404 pt++, archlist++;
405 if (!*pt && (!*archlist || (*archlist == ',')))
406 return (0);
407 while (*archlist) {
408 if (*archlist++ == ',')
409 break;
412 return (-1);
415 static int
416 ckinfo(char *inst, char *arch, char *vers)
418 FILE *fp;
419 char temp[128];
420 char file[PATH_MAX];
421 char *pt, *copy, *value, *myarch, *myvers;
422 int errflg;
424 (void) snprintf(file, sizeof (file), "%s/%s/pkginfo", pkgdir, inst);
425 if ((fp = fopen(file, "r")) == NULL)
426 return (1);
428 if ((arch == NULL) && (vers == NULL)) {
429 (void) fclose(fp);
430 return (0);
432 temp[0] = '\0';
433 myarch = myvers = NULL;
434 while (value = fpkgparam(fp, temp)) {
435 if (strcmp(temp, "ARCH") == 0) {
436 /* remove all whitespace from value */
437 pt = copy = value;
438 while (*pt) {
439 if (!isspace((unsigned char)*pt))
440 *copy++ = *pt;
441 pt++;
443 *copy = '\0';
444 myarch = value;
445 if (myvers)
446 break;
447 } else if (strcmp(temp, "VERSION") == 0) {
448 myvers = value;
449 if (myarch)
450 break;
451 } else
452 free(value);
453 temp[0] = '\0';
455 (void) fclose(fp);
456 errflg = 0;
458 if (ckinst(inst, myarch, myvers, arch, vers))
459 errflg++;
461 free(myarch);
462 free(myvers);
464 return (errflg);