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.
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.
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]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
35 #include <sys/types.h>
49 extern char *basedir
, *root
, *rootlist
[], **environ
;
52 * IMPORTANT NOTE: PLEASE SEE THE DEFINITION OF temp[] BELOW BEFORE
53 * CHANGING THE DEFINITION OF PATH_LGTH!!!!
56 #define PATH_LGTH 4096
61 #define MSG_BPARAMC "parametric class specification for <%s> not allowed"
62 #define MSG_SRCHLOC "no object for <%s> found in local path"
63 #define MSG_SRCHSRCH "no object for <%s> found in search path"
64 #define MSG_SRCHROOT "no object for <%s> found in root directory"
65 #define MSG_CONTENTS "unable to process contents of object <%s>"
66 #define MSG_WRITE "write of entry failed, errno=%d"
67 #define MSG_GARBDEFLT "garbled default settings: %s"
68 #define MSG_BANG "unknown directive: %s"
69 #define MSG_CHDIR "unable to change directory to <%s>"
70 #define MSG_INCOMPLETE "processing of <%s> may be incomplete"
71 #define MSG_NRECURS "too many levels of include (limit is %d)"
72 #define MSG_RDINCLUDE "unable to process include file <%s>, errno=%d"
73 #define MSG_IGNINCLUDE "ignoring include file <%s>"
74 #define MSG_NODEVICE "device numbers cannot be determined for <%s>"
76 #define WRN_BADATTR "WARNING: attributes set to %04o %s %s for <%s>"
77 #define WRN_BADATTRM "WARNING: attributes set to %s %s %s for <%s>"
78 #define WRN_FAKEBD "WARNING: parametric paths may ignore BASEDIR"
80 #define ERR_TEMP "unable to obtain temporary file resources, errno=%d"
81 #define ERR_ENVBUILD "unable to build parameter environment, errno=%d"
82 #define ERR_MAXPARAMS "too many parameter definitions (limit is %d)"
83 #define ERR_GETCWD "unable to get current directory, errno=%d"
84 #define ERR_PATHVAR "cannot resolve all build parameters associated with " \
87 static struct cfent entry
;
90 static char *dname
[NRECURS
],
98 static mode_t d_mod
[NRECURS
];
99 static int nfp
= (-1);
100 static int nrdonly
= 0;
101 static int errflg
= 0;
102 static char *separ
= " \t\n, ";
104 /* libpkg/gpkgmap.c */
105 extern void attrpreset(int mode
, char *owner
, char *group
);
106 extern void attrdefault();
107 static char *findfile(char *path
, char *local
);
108 static char *srchroot(char *path
, char *copy
);
110 static int popenv(void);
112 static int doattrib(void);
113 static void doinclude(void);
114 static void dorsearch(void);
115 static void dosearch(void);
116 static void error(int flag
);
117 static void lputenv(char *s
);
118 static void pushenv(char *file
);
119 static void translate(register char *pt
, register char *copy
);
122 mkpkgmap(char *outfile
, char *protofile
, char **envparam
)
125 char *pt
, *path
, mybuff
[PATH_LGTH
];
131 * NOTE: THE SIZE OF temp IS HARD CODED INTO CALLS TO fscanf.
132 * YOU *MUST* MAKE SURE TO CHANGE THOSE CALLS IF THE SIZE OF temp
133 * IS EVER CHANGED!!!!!!
135 char temp
[PATH_LGTH
];
137 if ((tmpfp
= fopen(outfile
, "w")) == NULL
) {
138 progerr(gettext(ERR_TEMP
), errno
);
142 environ
= params
; /* use only local environ */
143 attrdefault(); /* assume no default attributes */
146 * Environment parameters are optional, so variable
147 * (envparam[i]) could be NULL.
149 for (i
= 0; (envparam
[i
] != NULL
) &&
150 (pt
= strchr(envparam
[i
], '=')); i
++) {
152 rdonly
[nrdonly
++] = qstrdup(envparam
[i
]);
154 if (putenv(qstrdup(envparam
[i
]))) { /* bugid 1090920 */
155 progerr(gettext(ERR_ENVBUILD
), errno
);
158 if (nrdonly
>= MAXPARAMS
) {
159 progerr(gettext(ERR_MAXPARAMS
), MAXPARAMS
);
174 do c
= getc(fp
); while ((c
!= EOF
) && (c
!= '\n'));
182 * IMPORTANT NOTE: THE SIZE OF temp IS HARD CODED INTO
183 * the FOLLOWING CALL TO fscanf -- YOU MUST CHANGE THIS
184 * LINE IF THE SIZE OF fscanf IS EVER CHANGED!!!
186 (void) fscanf(fp
, "%4096s", temp
);
188 if (strcmp(temp
, "include") == 0)
190 else if (strcmp(temp
, "rsearch") == 0)
192 else if (strcmp(temp
, "search") == 0)
194 else if (strcmp(temp
, "default") == 0) {
197 } else if (strchr(temp
, '=')) {
198 translate(temp
, mybuff
);
199 /* put this into the local environment */
201 (void) fscanf(fp
, "%*[^\n]"); /* rest of line */
202 (void) fscanf(fp
, "\n"); /* rest of line */
205 logerr(gettext(MSG_BANG
), temp
);
206 (void) fscanf(fp
, "%*[^\n]"); /* read of line */
207 (void) fscanf(fp
, "\n"); /* read of line */
211 (void) ungetc(c
, fp
);
213 if ((n
= gpkgmap(&entry
, fp
)) < 0) {
217 errstr
= getErrstr();
218 logerr(gettext("garbled entry"));
219 logerr(gettext("- pathname: %s"),
220 (entry
.path
&& *entry
.path
) ? entry
.path
:
222 logerr(gettext("- problem: %s"),
223 (errstr
&& *errstr
) ? errstr
: "Unknown");
227 break; /* done with file */
229 /* don't allow classname to be parametric */
230 if (entry
.ftype
!= 'i') {
231 if (entry
.pkg_class
[0] == '$') {
233 logerr(gettext(MSG_BPARAMC
), entry
.path
);
237 if (strchr("dxlscbp", entry
.ftype
)) {
239 * We don't need to search for things without any
242 if (strchr("cb", entry
.ftype
)) {
243 if (entry
.ainfo
.major
== BADMAJOR
||
244 entry
.ainfo
.minor
== BADMINOR
) {
246 logerr(gettext(MSG_NODEVICE
),
252 path
= findfile(entry
.path
, entry
.ainfo
.local
);
256 entry
.ainfo
.local
= path
;
257 if (strchr("fevin?", entry
.ftype
)) {
258 if (cverify(0, &entry
.ftype
, path
,
261 logerr(gettext(MSG_CONTENTS
), path
);
266 /* Warn if attributes are not set correctly. */
267 if (!strchr("isl", entry
.ftype
)) {
271 if (entry
.ainfo
.mode
== NOMODE
) {
272 entry
.ainfo
.mode
= CURMODE
;
277 if (strcmp(entry
.ainfo
.owner
, NOOWNER
) == 0) {
278 (void) strlcpy(entry
.ainfo
.owner
, CUROWNER
,
279 sizeof (entry
.ainfo
.owner
));
283 if (strcmp(entry
.ainfo
.group
, NOGROUP
) == 0) {
284 (void) strlcpy(entry
.ainfo
.group
, CURGROUP
,
285 sizeof (entry
.ainfo
.group
));
292 logerr(gettext(WRN_BADATTRM
),
298 logerr(gettext(WRN_BADATTR
),
299 (int)entry
.ainfo
.mode
,
307 * Resolve build parameters (initial lower case) in
308 * the link and target paths.
310 if (strchr("ls", entry
.ftype
)) {
311 if (!RELATIVE(entry
.ainfo
.local
) ||
312 PARAMETRIC(entry
.ainfo
.local
)) {
313 if (mappath(1, entry
.ainfo
.local
)) {
315 logerr(gettext(ERR_PATHVAR
),
320 canonize(entry
.ainfo
.local
);
325 * Warn if top level file or directory is an install
328 if (entry
.ftype
!= 'i') {
329 if (entry
.path
[0] == '$' && isupper(entry
.path
[1]))
333 if (mappath(1, entry
.path
)) {
335 logerr(gettext(ERR_PATHVAR
), entry
.path
);
339 canonize(entry
.path
);
340 if (ppkgmap(&entry
, tmpfp
)) {
342 logerr(gettext(MSG_WRITE
), errno
);
348 logerr(gettext(WRN_FAKEBD
));
355 (void) fclose(tmpfp
);
356 environ
= envsave
; /* restore environment */
358 return (errflg
? 1 : 0);
362 findfile(char *path
, char *local
)
365 static char host
[PATH_MAX
];
367 char temp
[PATH_MAX
], *basename
;
371 * map any parameters specified in path to their corresponding values
372 * and make sure the path is in its canonical form; any parmeters for
373 * which a value is not defined will be left unexpanded. Since this
374 * is an actual search for a real file (which will not end up in the
375 * package) - we map ALL variables (both build and Install).
377 (void) strlcpy(temp
, (local
&& local
[0] ? local
: path
), sizeof (temp
));
382 if (rootlist
[0] || (basedir
&& (*temp
!= '/'))) {
384 * search for path in the pseudo-root/basedir directory; note
385 * that package information files should NOT be included in
388 if (entry
.ftype
!= 'i')
389 return (srchroot(temp
, host
));
392 /* looking for local object file */
393 if (local
&& *local
) {
394 basepath(temp
, dname
[nfp
], NULL
);
396 * If it equals "/dev/null", that just means it's an empty
397 * file. Otherwise, we'll really be writing stuff, so we need
398 * to verify the source.
400 if (strcmp(temp
, "/dev/null") != 0) {
401 if (stat(temp
, &statbuf
) ||
402 !(statbuf
.st_mode
& S_IFREG
)) {
404 logerr(gettext(MSG_SRCHLOC
), path
);
408 (void) strlcpy(host
, temp
, sizeof (host
));
412 for (i
= 0; rootp
[nfp
][i
]; i
++) {
413 (void) snprintf(host
, sizeof (host
), "%s/%s", rootp
[nfp
][i
],
414 temp
+ (*temp
== '/' ? 1 : 0));
415 if ((stat(host
, &statbuf
) == 0) &&
416 (statbuf
.st_mode
& S_IFREG
)) {
421 pt
= strrchr(temp
, '/');
427 for (i
= 0; srchp
[nfp
][i
]; i
++) {
428 (void) snprintf(host
, sizeof (host
), "%s/%s",
429 srchp
[nfp
][i
], basename
);
430 if ((stat(host
, &statbuf
) == 0) &&
431 (statbuf
.st_mode
& S_IFREG
)) {
436 /* check current directory as a last resort */
437 (void) snprintf(host
, sizeof (host
), "%s/%s", dname
[nfp
], basename
);
438 if ((stat(host
, &statbuf
) == 0) && (statbuf
.st_mode
& S_IFREG
))
442 logerr(gettext(MSG_SRCHSRCH
), path
);
449 char temp
[PATH_MAX
], lookpath
[PATH_MAX
], *pt
;
452 (void) fgets(temp
, PATH_MAX
, fp
);
453 translate(temp
, lookpath
);
455 for (n
= 0; srchp
[nfp
][n
]; n
++)
459 pt
= strtok(lookpath
, separ
);
463 /* make relative path an absolute directory */
464 (void) snprintf(temp
, sizeof (temp
),
465 "%s/%s", dname
[nfp
], pt
);
469 srchp
[nfp
][n
++] = qstrdup(pt
);
470 } while (pt
= strtok(NULL
, separ
));
471 srchp
[nfp
][n
] = NULL
;
478 char temp
[PATH_MAX
], lookpath
[PATH_MAX
], *pt
;
481 (void) fgets(temp
, PATH_MAX
, fp
);
482 translate(temp
, lookpath
);
484 for (n
= 0; rootp
[nfp
][n
]; n
++)
488 pt
= strtok(lookpath
, separ
);
491 /* make relative path an absolute directory */
492 (void) snprintf(temp
, sizeof (temp
),
493 "%s/%s", dname
[nfp
], pt
);
497 rootp
[nfp
][n
++] = qstrdup(pt
);
498 } while (pt
= strtok(NULL
, separ
));
499 rootp
[nfp
][n
] = NULL
;
503 * This function reads the default mode, owner and group from the prototype
504 * file and makes that available.
509 char *pt
, attrib
[PATH_MAX
], *mode_ptr
, *owner_ptr
, *group_ptr
, *eol
;
511 char owner
[ATRSIZ
+1], group
[ATRSIZ
+1], attrib_save
[(4*ATRSIZ
)];
513 (void) fgets(attrib
, PATH_MAX
, fp
);
515 (void) strlcpy(attrib_save
, attrib
, sizeof (attrib_save
));
518 * Now resolve any variables that may be present. Start on group and
519 * move backward since that keeps the resolved string from
520 * overwriting any of the other entries. This is required since
521 * mapvar() writes the resolved string over the string provided.
523 mode_ptr
= strtok(attrib
, " \t");
524 owner_ptr
= strtok(NULL
, " \t");
525 group_ptr
= strtok(NULL
, " \t\n");
526 eol
= strtok(NULL
, " \t\n");
527 if (strtok(NULL
, " \t\n")) {
528 /* extra tokens on the line */
530 logerr(gettext(MSG_GARBDEFLT
), (eol
) ? eol
:
531 gettext("unreadable at end of line"));
535 if (group_ptr
&& mapvar(1, group_ptr
) == 0)
536 (void) strncpy(group
, group_ptr
, ATRSIZ
);
539 logerr(gettext(MSG_GARBDEFLT
), (attrib_save
) ?
540 ((attrib_save
[0]) ? attrib_save
: gettext("none")) :
541 gettext("unreadable at group"));
545 if (owner_ptr
&& mapvar(1, owner_ptr
) == 0)
546 (void) strncpy(owner
, owner_ptr
, ATRSIZ
);
549 logerr(gettext(MSG_GARBDEFLT
), (attrib_save
) ?
550 ((attrib_save
[0]) ? attrib_save
: gettext("none")) :
551 gettext("unreadable at owner"));
556 * For mode, don't use scanf, since we want to force an octal
557 * interpretation and need to limit the length of the owner and group
560 if (mode_ptr
&& mapvar(1, mode_ptr
) == 0)
561 mode
= strtol(mode_ptr
, &pt
, 8);
564 logerr(gettext(MSG_GARBDEFLT
), (attrib_save
) ?
565 ((attrib_save
[0]) ? attrib_save
: gettext("none")) :
566 gettext("unreadable at mode"));
570 /* free any previous memory from qstrdup */
577 d_own
[nfp
] = qstrdup(owner
);
578 d_grp
[nfp
] = qstrdup(group
);
580 attrpreset(d_mod
[nfp
], d_own
[nfp
], d_grp
[nfp
]);
591 (void) fgets(temp
, PATH_MAX
, fp
);
594 * IMPORTANT NOTE: THE SIZE OF temp IS HARD CODED INTO THE
595 * FOLLOWING CALL TO fscanf -- YOU MUST CHANGE THIS LINE IF
596 * THE SIZE OF fscanf IS EVER CHANGED!!!
598 (void) sscanf(temp
, "%1024s", file
);
600 translate(file
, temp
);
605 else if (*temp
!= '/')
606 (void) snprintf(file
, sizeof (file
), "%s/%s", dname
[nfp
], temp
);
608 (void) strlcpy(file
, temp
, sizeof (file
));
615 * This does what mappath() does except that it does it for ALL variables
616 * using whitespace as a token separator. This is used to resolve search
617 * paths and assignment statements. It doesn't effect the build versus
618 * install decision made for pkgmap variables.
621 translate(register char *pt
, register char *copy
)
623 char *pt2
, varname
[MAX_PKG_PARAM_LENGTH
];
626 /* eat white space */
629 while (*pt
&& !isspace(*pt
)) {
632 while (*++pt
&& !strchr("/= \t\n\r", *pt
))
635 if (pt2
= getenv(varname
)) {
652 static char *lasterr
= NULL
;
654 if (lasterr
!= proto
[nfp
]) {
655 lasterr
= proto
[nfp
];
656 (void) fprintf(stderr
, gettext("ERROR in %s:\n"), lasterr
);
662 /* Set up defaults and change to the build directory. */
667 static char topdir
[PATH_MAX
];
669 if ((nfp
+1) >= NRECURS
) {
671 logerr(gettext(MSG_NRECURS
), NRECURS
);
672 logerr(gettext(MSG_IGNINCLUDE
), file
);
676 if (strcmp(file
, "-") == 0) {
678 } else if ((fp
= fopen(file
, "r")) == NULL
) {
680 logerr(gettext(MSG_RDINCLUDE
), file
, errno
);
682 logerr(gettext(MSG_IGNINCLUDE
), file
);
689 srchp
[nfp
][0] = NULL
;
690 rootp
[nfp
][0] = NULL
;
691 d_mod
[nfp
] = (mode_t
)(-1);
696 /* upper level proto file */
699 pt
= strcpy(topdir
, file
);
701 /* path is relative to the prototype file specified */
702 pt
= getcwd(NULL
, PATH_MAX
);
704 progerr(gettext(ERR_GETCWD
), errno
);
707 (void) snprintf(topdir
, sizeof (topdir
),
710 if (pt
= strrchr(topdir
, '/'))
711 *pt
= '\0'; /* should always happen */
712 if (topdir
[0] == '\0')
713 (void) strlcpy(topdir
, "/", sizeof (topdir
));
716 proto
[nfp
] = qstrdup(file
);
717 dname
[nfp
] = qstrdup(file
);
718 if (pt
= strrchr(dname
[nfp
], '/'))
721 /* same directory as the last prototype */
723 dname
[nfp
] = qstrdup(dname
[nfp
-1]);
724 return; /* no need to canonize() or chdir() */
728 canonize(dname
[nfp
]);
730 if (chdir(dname
[nfp
])) {
732 logerr(gettext(MSG_CHDIR
), dname
[nfp
]);
734 quit(1); /* must be able to cd to upper level */
735 logerr(gettext(MSG_IGNINCLUDE
), proto
[nfp
]);
740 /* Restore defaults and return to the prior directory. */
752 for (i
= 0; srchp
[nfp
][i
]; i
++)
754 for (i
= 0; rootp
[nfp
][i
]; i
++)
763 if (chdir(dname
[nfp
])) {
765 logerr(gettext(MSG_CHDIR
), dname
[nfp
]);
766 logerr(gettext(MSG_INCOMPLETE
), proto
[nfp
]);
775 * If this parameter isn't already in place, put it into the local
776 * environment. This means that command line directives override prototype
790 for (i
= 0; i
< nrdonly
; i
++) {
791 if (strcmp(rdonly
[i
], s
) == 0) {
798 if (putenv(qstrdup(s
))) {
799 progerr(gettext(ERR_ENVBUILD
), errno
);
805 srchroot(char *path
, char *copy
)
811 root
= rootlist
[i
++];
813 /* convert with root & basedir info */
815 /* make it pretty again */
818 if (stat(copy
, &statbuf
) || !(statbuf
.st_mode
& S_IFREG
)) {
819 root
= rootlist
[i
++];
820 continue; /* host source must be a regular file */
823 } while (root
!= NULL
);
825 logerr(gettext(MSG_SRCHROOT
), path
);