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 <errno.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <stdlib.h>
36 #include <unistd.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 #include <libadm.h>
45 #include "installf.h"
46
47 #define LSIZE 1024
48 #define MALSIZ 164
49
50 #define ERR_MAJOR "invalid major number <%s> specified for <%s>"
51 #define ERR_MINOR "invalid minor number <%s> specified for <%s>"
52 #define ERR_MODE "invalid mode <%s> specified for <%s>"
53 #define ERR_RELPATH "relative pathname <%s> not permitted"
54 #define ERR_NULLPATH "NULL or garbled pathname"
55 #define ERR_LINK "invalid link specification <%s>"
56 #define ERR_LINKFTYPE "ftype <%c> does not match link specification <%s>"
57 #define ERR_LINKARGS "extra arguments in link specification <%s>"
58 #define ERR_LINKREL "relative pathname in link specification <%s>"
59 #define ERR_FTYPE "invalid ftype <%c> for <%s>"
60 #define ERR_ARGC "invalid number of arguments for <%s>"
61 #define ERR_SPECALL "ftype <%c> requires all fields to be specified"
62
63 static int validate(struct cfextra *ext, int argc, char *argv[]);
64 static void checkPaths(char *argv[]);
65
66 int
installf(int argc,char * argv[])67 installf(int argc, char *argv[])
68 {
69 struct cfextra *new;
70 char line[LSIZE];
71 char *largv[8];
72 int myerror;
73
74 if (strcmp(argv[0], "-") != 0) {
75 if (argc < 1)
76 usage(); /* at least pathname is required */
77 extlist = calloc(2, sizeof (struct cfextra *));
78 extlist[0] = new = calloc(1, sizeof (struct cfextra));
79 eptnum = 1;
80
81 /* There is only one filename on the command line. */
82 checkPaths(argv);
83 if (validate(new, argc, argv))
84 quit(1);
85 return (0);
86 }
87
88 /* Read stdin to obtain entries, which need to be sorted. */
89 eptnum = 0;
90 myerror = 0;
91 extlist = calloc(MALSIZ, sizeof (struct cfextra *));
92 while (fgets(line, LSIZE, stdin) != NULL) {
93 argc = 0;
94 argv = largv;
95 argv[argc++] = strtok(line, " \t\n");
96 while (argv[argc] = strtok(NULL, " \t\n"))
97 argc++;
98
99 if (argc < 1)
100 usage(); /* at least pathname is required */
101
102 new = calloc(1, sizeof (struct cfextra));
103 if (new == NULL) {
104 progerr(strerror(errno));
105 quit(99);
106 }
107
108 checkPaths(argv);
109
110 if (validate(new, argc, argv))
111 myerror++;
112
113 extlist[eptnum] = new;
114 if ((++eptnum % MALSIZ) == 0) {
115 extlist = realloc(extlist,
116 (sizeof (struct cfextra *) * (eptnum+MALSIZ)));
117 if (!extlist) {
118 progerr(strerror(errno));
119 quit(99);
120 }
121 }
122 }
123 extlist[eptnum] = (struct cfextra *)NULL;
124 qsort((char *)extlist, (unsigned)eptnum, sizeof (struct cfextra *),
125 cfentcmp);
126 return (myerror);
127 }
128
129 static int
validate(struct cfextra * ext,int argc,char * argv[])130 validate(struct cfextra *ext, int argc, char *argv[])
131 {
132 char *ret, *pt;
133 int n, allspec, is_a_link;
134 struct cfent *ept;
135
136 ept = &(ext->cf_ent);
137
138 /* initialize cfent structure */
139 ept->pinfo = NULL;
140 (void) gpkgmapvfp(ept, (VFP_T *)NULL); /* This just clears stuff. */
141
142 n = allspec = 0;
143 if (classname)
144 (void) strncpy(ept->pkg_class, classname, CLSSIZ);
145
146 if (argv[n] == NULL || *(argv[n]) == '\000') {
147 progerr(gettext(ERR_NULLPATH));
148 return (1);
149 }
150
151 /*
152 * It would be a good idea to figure out how to get much of
153 * this done using facilities in procmap.c - JST
154 */
155 if (pt = strchr(argv[n], '=')) {
156 *pt = '\0'; /* cut off pathname at the = sign */
157 is_a_link = 1;
158 } else
159 is_a_link = 0;
160
161 if (RELATIVE(argv[n])) {
162 progerr(gettext(ERR_RELPATH),
163 (argv[n] == NULL) ? "unknown" : argv[n]);
164 return (1);
165 }
166
167 /* get the pathnames */
168 if (eval_path(&(ext->server_path), &(ext->client_path),
169 &(ext->map_path), argv[n++]) == 0)
170 return (1);
171
172 ept->path = ext->client_path;
173
174 /* This isn't likely to happen; but, better safe than sorry. */
175 if (RELATIVE(ept->path)) {
176 progerr(gettext(ERR_RELPATH), ept->path);
177 return (1);
178 }
179
180 if (is_a_link) {
181 /* links specifications should be handled right here */
182 ept->ftype = ((n >= argc) ? 'l' : argv[n++][0]);
183
184 /* If nothing follows the '=', it's invalid */
185 if (!pt[1]) {
186 progerr(gettext(ERR_LINK), ept->path);
187 return (1);
188 }
189
190 /* Test for an argument after the link. */
191 if (argc != n) {
192 progerr(gettext(ERR_LINKARGS), ept->path);
193 return (1);
194 }
195
196 /*
197 * If it's a link but it's neither hard nor symbolic then
198 * it's bad.
199 */
200 if (!strchr("sl", ept->ftype)) {
201 progerr(gettext(ERR_LINKFTYPE), ept->ftype, ept->path);
202 return (1);
203 }
204
205 ext->server_local = pathdup(pt+1);
206 ext->client_local = ext->server_local;
207
208 ept->ainfo.local = ext->client_local;
209
210 return (0);
211 } else if (n >= argc) {
212 /* we are expecting to change object's contents */
213 return (0);
214 }
215
216 ept->ftype = argv[n++][0];
217 if (strchr("sl", ept->ftype)) {
218 progerr(gettext(ERR_LINK), ept->path);
219 return (1);
220 } else if (!strchr("?fvedxcbp", ept->ftype)) {
221 progerr(gettext(ERR_FTYPE), ept->ftype, ept->path);
222 return (1);
223 }
224
225 if (ept->ftype == 'b' || ept->ftype == 'c') {
226 if (n < argc) {
227 ept->ainfo.major = strtol(argv[n++], &ret, 0);
228 if (ret && *ret) {
229 progerr(gettext(ERR_MAJOR), argv[n-1],
230 ept->path);
231 return (1);
232 }
233 }
234 if (n < argc) {
235 ept->ainfo.minor = strtol(argv[n++], &ret, 0);
236 if (ret && *ret) {
237 progerr(gettext(ERR_MINOR), argv[n-1],
238 ept->path);
239 return (1);
240 }
241 allspec++;
242 }
243 }
244
245 allspec = 0;
246 if (n < argc) {
247 ept->ainfo.mode = strtol(argv[n++], &ret, 8);
248 if (ret && *ret) {
249 progerr(gettext(ERR_MODE), argv[n-1], ept->path);
250 return (1);
251 }
252 }
253 if (n < argc)
254 (void) strncpy(ept->ainfo.owner, argv[n++], ATRSIZ);
255 if (n < argc) {
256 (void) strncpy(ept->ainfo.group, argv[n++], ATRSIZ);
257 allspec++;
258 }
259 if (strchr("dxbcp", ept->ftype) && !allspec) {
260 progerr(gettext(ERR_ARGC), ept->path);
261 progerr(gettext(ERR_SPECALL), ept->ftype);
262 return (1);
263 }
264 if (n < argc) {
265 progerr(gettext(ERR_ARGC), ept->path);
266 return (1);
267 }
268 return (0);
269 }
270
271 int
cfentcmp(const void * p1,const void * p2)272 cfentcmp(const void *p1, const void *p2)
273 {
274 struct cfextra *ext1 = *((struct cfextra **)p1);
275 struct cfextra *ext2 = *((struct cfextra **)p2);
276
277 return (strcmp(ext1->cf_ent.path, ext2->cf_ent.path));
278 }
279
280 /*
281 * If the path at argv[0] has the value of
282 * PKG_INSTALL_ROOT prepended, remove it
283 */
284 static void
checkPaths(char * argv[])285 checkPaths(char *argv[])
286 {
287 char *root;
288 int rootLen;
289
290 /*
291 * Note- No local copy of argv is needed since this
292 * function is guaranteed to replace argv with a subset of
293 * the original argv.
294 */
295
296 /* We only want to canonize the path if it contains multiple '/'s */
297
298 canonize_slashes(argv[0]);
299
300 if ((root = get_inst_root()) == NULL)
301 return;
302 if (strcmp(root, "/") != 0) {
303 rootLen = strlen(root);
304 if (strncmp(argv[0], root, rootLen) == 0) {
305 argv[0] += rootLen;
306 }
307 }
308 }
309