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 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 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 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 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