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 #include <stdio.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <pkgstrct.h>
39 #include <locale.h>
40 #include <libintl.h>
41 #include <pkglib.h>
42 #include <install.h>
43 #include <libinst.h>
44
45 #define ERR_MEMORY "memory allocation failure"
46 #define ERR_DUPPATH "duplicate pathname <%s>"
47
48 /* libpkg/gpkgmap */
49 extern int getmapmode(void);
50
51 #define EPTMALLOC 512
52
53 static struct cfent **eptlist;
54
55 static int eptnum;
56 static int errflg;
57 static int nparts;
58 static int space = -1;
59
60 static void procinit(void);
61 static int procassign(struct cfent *ept, char **server_local,
62 char **client_local, char **server_path,
63 char **client_path, char **map_path, int mapflag,
64 int nc);
65
66 static int ckdup(struct cfent *ept1, struct cfent *ept2);
67 static int sortentry(int index);
68
69 static void
procinit(void)70 procinit(void)
71 {
72 errflg = nparts = eptnum = 0;
73
74 if (space != -1) {
75 ar_free(space);
76 space = -1;
77 }
78
79 /*
80 * initialize dynamic memory used to store
81 * path information which is read in
82 */
83 (void) pathdup((char *)0);
84 }
85
86 /*
87 * This function assigns appropriate values based upon the pkgmap entry
88 * in the cfent structure.
89 */
90 static int
procassign(struct cfent * ept,char ** server_local,char ** client_local,char ** server_path,char ** client_path,char ** map_path,int mapflag,int nc)91 procassign(struct cfent *ept, char **server_local, char **client_local,
92 char **server_path, char **client_path, char **map_path, int mapflag,
93 int nc)
94 {
95 int path_duped = 0;
96 int local_duped = 0;
97 char source[PATH_MAX+1];
98
99 if (nc >= 0 && ept->ftype != 'i')
100 if ((ept->pkg_class_idx = cl_idx(ept->pkg_class)) == -1)
101 return (1);
102
103 if (ept->volno > nparts)
104 nparts++;
105
106 /*
107 * Generate local (delivered source) paths for files
108 * which need them so that the install routine will know
109 * where to get the file from the package. Note that we
110 * do not resolve path environment variables here since
111 * they won't be resolved in the reloc directory.
112 */
113 if ((mapflag > 1) && strchr("fve", ept->ftype)) {
114 if (ept->ainfo.local == NULL) {
115 source[0] = '~';
116 (void) strcpy(&source[1], ept->path);
117 ept->ainfo.local = pathdup(source);
118 *server_local = ept->ainfo.local;
119 *client_local = ept->ainfo.local;
120
121 local_duped = 1;
122 }
123 }
124
125 /*
126 * Evaluate the destination path based upon available
127 * environment, then produce a client-relative and
128 * server-relative canonized path.
129 */
130 if (mapflag && (ept->ftype != 'i')) {
131 mappath(getmapmode(), ept->path); /* evaluate variables */
132 canonize(ept->path); /* Fix path as necessary. */
133
134 (void) eval_path(server_path,
135 client_path,
136 map_path,
137 ept->path);
138 path_duped = 1; /* eval_path dup's it */
139 ept->path = *server_path; /* default */
140 }
141
142 /*
143 * Deal with source for hard and soft links.
144 */
145 if (strchr("sl", ept->ftype)) {
146 if (mapflag) {
147 mappath(getmapmode(), ept->ainfo.local);
148 if (!RELATIVE(ept->ainfo.local)) {
149 canonize(ept->ainfo.local);
150
151 /* check for hard link */
152 if (ept->ftype == 'l') {
153 (void) eval_path(
154 server_local,
155 client_local,
156 NULL,
157 ept->ainfo.local);
158 local_duped = 1;
159
160 /* Default to server. */
161 ept->ainfo.local = *server_local;
162 }
163 }
164 }
165 }
166
167 /*
168 * For the paths (both source and target) that were too mundane to
169 * have been copied into dup space yet, do that.
170 */
171 if (!path_duped) {
172 *server_path = pathdup(ept->path);
173 *client_path = *server_path;
174 ept->path = *server_path;
175
176 path_duped = 1;
177 }
178 if (ept->ainfo.local != NULL)
179 if (!local_duped) {
180 *server_local = pathdup(ept->ainfo.local);
181 ept->ainfo.local = *server_local;
182 *client_local = ept->ainfo.local;
183
184 local_duped = 1;
185 }
186
187 return (0);
188 }
189
190 /*
191 * This function reads the prototype file and returns a pointer to a list of
192 * struct cfent representing the contents of that file.
193 */
194 /*ARGSUSED*/
195 struct cfent **
procmap(VFP_T * vfp,int mapflag,char * ir)196 procmap(VFP_T *vfp, int mapflag, char *ir)
197 {
198 struct cfent *ept = (struct cfent *)NULL;
199 struct cfent map_entry;
200 struct cfent **ept_ptr;
201 int i;
202 int n;
203 int nc;
204 static char *server_local, *client_local;
205 static char *server_path, *client_path, *map_path;
206
207 procinit();
208
209 space = ar_create(EPTMALLOC, (unsigned)sizeof (struct cfent),
210 "prototype object");
211 if (space == -1) {
212 progerr(gettext(ERR_MEMORY));
213 return (NULL);
214 }
215
216 nc = cl_getn();
217 for (;;) {
218 /* Clear the buffer. */
219 (void) memset(&map_entry, '\000', sizeof (struct cfent));
220
221 n = gpkgmapvfp(&map_entry, vfp);
222
223 if (n == 0)
224 break; /* no more entries in pkgmap */
225 else if (n < 0) {
226 char *errstr = getErrstr();
227 progerr(gettext("bad entry read in pkgmap"));
228 logerr(gettext("pathname=%s"),
229 (ept && ept->path && *ept->path) ?
230 ept->path : "Unknown");
231 logerr(gettext("problem=%s"),
232 (errstr && *errstr) ? errstr : "Unknown");
233 return (NULL);
234 }
235
236 /*
237 * A valid entry was found in the map, so allocate an
238 * official record.
239 */
240 ept_ptr = (struct cfent **)ar_next_avail(space);
241 if (ept_ptr == NULL || *ept_ptr == NULL) {
242 progerr(gettext(ERR_MEMORY));
243 return (NULL);
244 }
245
246 ept = *ept_ptr;
247
248 /* Transfer what we just read in. */
249 (void) memcpy(ept, &map_entry, sizeof (struct cfent));
250
251 if (procassign(ept, &server_local, &client_local,
252 &server_path, &client_path, &map_path,
253 mapflag, nc)) {
254 /* It didn't take. */
255 (void) ar_delete(space, eptnum);
256 continue;
257 }
258
259 eptnum++;
260 }
261
262 /* setup a pointer array to point to malloc'd entries space */
263 eptlist = (struct cfent **)ar_get_head(space);
264 if (eptlist == NULL) {
265 progerr(gettext(ERR_MEMORY));
266 return (NULL);
267 }
268
269 (void) sortentry(-1);
270 for (i = 0; i < eptnum; /* void */) {
271 if (!sortentry(i))
272 i++;
273 }
274 return (errflg ? NULL : eptlist);
275 }
276
277 /*
278 * This function sorts the final list of cfent entries. If index = -1, the
279 * function is initialized. index = 0 doesn't get us anywhere because this
280 * sorts against index-1. Positive natural index values are compared and
281 * sorted into the array appropriately. Yes, it does seem we should use a
282 * quicksort on the whole array or something. The apparent reason for taking
283 * this approach is that there are enough special considerations to be
284 * applied to each package object that inserting them one-by-one doesn't cost
285 * that much.
286 */
287 static int
sortentry(int index)288 sortentry(int index)
289 {
290 struct cfent *ept, *ept_i;
291 static int last = 0;
292 int i, n, j;
293 int upper, lower;
294
295 if (index == 0)
296 return (0);
297 else if (index < 0) {
298 last = 0;
299 return (0);
300 }
301
302 /*
303 * Based on the index, this is the package object we're going to
304 * review. It may stay where it is or it may be repositioned in the
305 * array.
306 */
307 ept = eptlist[index];
308
309 /* quick comparison optimization for pre-sorted arrays */
310 if (strcmp(ept->path, eptlist[index-1]->path) > 0) {
311 /* do nothing */
312 last = index-1;
313 return (0);
314 }
315
316 lower = 0; /* lower bound of the unsorted elements */
317 upper = index; /* upper bound */
318 i = last;
319 do {
320 /*
321 * NOTE: This does a binary sort on path. There are lots of
322 * other worthy items in the array, but path is the key into
323 * the package database.
324 */
325 ept_i = eptlist[i];
326
327 n = strcmp(ept->path, ept_i->path);
328 if (n == 0) {
329 if (!ckdup(ept, ept_i)) {
330 progerr(gettext(ERR_DUPPATH),
331 ept->path);
332 errflg++;
333 }
334 /* remove the entry at index */
335 (void) ar_delete(space, index);
336
337 eptnum--;
338 return (1); /* Use this index again. */
339 } else if (n < 0) {
340 /*
341 * The path of interest is smaller than the path
342 * under test. Move down array using the method of
343 * division
344 */
345 upper = i;
346 i = lower + (upper-lower)/2;
347 } else {
348 /* Move up array */
349 lower = i+1;
350 i = upper - (upper-lower)/2 - 1;
351 }
352 } while (upper != lower);
353 last = i = upper;
354
355 /* expand to insert at i */
356 for (j = index; j > i; j--)
357 eptlist[j] = eptlist[j-1];
358
359 eptlist[i] = ept;
360
361 return (0);
362 }
363
364 /*
365 * Check duplicate entries in the package object list. If it's a directory,
366 * this just merges them, if not, it returns a 0 to force further processing.
367 */
368 static int
ckdup(struct cfent * ept1,struct cfent * ept2)369 ckdup(struct cfent *ept1, struct cfent *ept2)
370 {
371 /* ept2 will be modified to contain "merged" entries */
372
373 if (!strchr("?dx", ept1->ftype))
374 return (0);
375
376 if (!strchr("?dx", ept2->ftype))
377 return (0);
378
379 if (ept2->ainfo.mode == BADMODE)
380 ept2->ainfo.mode = ept1->ainfo.mode;
381 if ((ept1->ainfo.mode != ept2->ainfo.mode) &&
382 (ept1->ainfo.mode != BADMODE))
383 return (0);
384
385 if (strcmp(ept2->ainfo.owner, "?") == 0)
386 (void) strcpy(ept2->ainfo.owner, ept1->ainfo.owner);
387 if (strcmp(ept1->ainfo.owner, ept2->ainfo.owner) &&
388 strcmp(ept1->ainfo.owner, "?"))
389 return (0);
390
391 if (strcmp(ept2->ainfo.group, "?") == 0)
392 (void) strcpy(ept2->ainfo.group, ept1->ainfo.group);
393 if (strcmp(ept1->ainfo.group, ept2->ainfo.group) &&
394 strcmp(ept1->ainfo.group, "?"))
395 return (0);
396
397 if (ept1->pinfo) {
398 ept2->npkgs = ept1->npkgs;
399 ept2->pinfo = ept1->pinfo;
400 }
401
402 return (1);
403 }
404