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 2009 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 46 extern struct cfextra **extlist; 47 extern struct cfent **eptlist; 48 49 extern char *pkginst; 50 51 #define ERR_WRITE "write of intermediate contents file failed" 52 53 static char *check_db_entry(VFP_T *, struct cfextra *, int, char *, int *); 54 55 /*ARGSUSED*/ 56 int 57 dofinal(PKGserver server, VFP_T *vfpo, int rmflag, char *myclass, char *prog) 58 { 59 struct cfextra entry; 60 int n, indx, dbchg; 61 char *save_path = NULL; 62 63 entry.cf_ent.pinfo = NULL; 64 entry.fsys_value = BADFSYS; 65 entry.fsys_base = BADFSYS; 66 indx = 0; 67 68 while (extlist && extlist[indx] && (extlist[indx]->cf_ent.ftype == 'i')) 69 indx++; 70 71 dbchg = 0; 72 73 if (pkgopenfilter(server, pkginst) != 0) 74 quit(99); 75 76 while (n = srchcfile(&(entry.cf_ent), "*", server)) { 77 if (n < 0) { 78 char *errstr = getErrstr(); 79 progerr(gettext("bad entry read in contents file")); 80 logerr(gettext("pathname=%s"), 81 (entry.cf_ent.path && *(entry.cf_ent.path)) ? 82 entry.cf_ent.path : "Unknown"); 83 logerr(gettext("problem=%s"), 84 (errstr && *errstr) ? errstr : "Unknown"); 85 quit(99); 86 } 87 save_path = check_db_entry(vfpo, &entry, rmflag, myclass, 88 &dbchg); 89 90 /* Restore original server-relative path, if needed */ 91 if (save_path != NULL) { 92 entry.cf_ent.path = save_path; 93 save_path = NULL; 94 } 95 } 96 97 pkgclosefilter(server); 98 99 return (dbchg); 100 } 101 102 static char * 103 check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass, 104 int *dbchg) 105 { 106 struct pinfo *pinfo; 107 int fs_entry; 108 char *save_path = NULL; 109 char *tp; 110 111 if (myclass && strcmp(myclass, entry->cf_ent.pkg_class)) { 112 /* 113 * We already have it in the database we don't want 114 * to modify it. 115 */ 116 return (NULL); 117 } 118 119 /* 120 * Now scan each package instance holding this file or 121 * directory and see if it matches the package we are 122 * updating here. 123 */ 124 pinfo = entry->cf_ent.pinfo; 125 while (pinfo) { 126 if (strcmp(pkginst, pinfo->pkg) == 0) 127 break; 128 pinfo = pinfo->next; 129 } 130 131 /* 132 * If pinfo == NULL at this point, then this file or 133 * directory isn't part of the package of interest. 134 * So the code below executes only on files in the package 135 * of interest. 136 */ 137 138 if (pinfo == NULL) 139 return (NULL); 140 141 if (rmflag && (pinfo->status == RM_RDY)) { 142 *dbchg = 1; 143 144 (void) eptstat(&(entry->cf_ent), pkginst, '@'); 145 146 if (entry->cf_ent.npkgs) { 147 if (putcvfpfile(&(entry->cf_ent), vfpo)) { 148 progerr(gettext(ERR_WRITE)); 149 quit(99); 150 } 151 } else if (entry->cf_ent.path != NULL) { 152 (void) vfpSetModified(vfpo); 153 /* add "-<path>" to the file */ 154 vfpPutc(vfpo, '-'); 155 vfpPuts(vfpo, entry->cf_ent.path); 156 vfpPutc(vfpo, '\n'); 157 } 158 return (NULL); 159 160 } else if (!rmflag && (pinfo->status == INST_RDY)) { 161 *dbchg = 1; 162 163 /* tp is the server-relative path */ 164 tp = fixpath(entry->cf_ent.path); 165 /* save_path is the cmd line path */ 166 save_path = entry->cf_ent.path; 167 /* entry has the server-relative path */ 168 entry->cf_ent.path = tp; 169 170 /* 171 * The next if statement figures out how 172 * the contents file entry should be 173 * annotated. 174 * 175 * Don't install or verify objects for 176 * remote, read-only filesystems. We 177 * need only verify their presence and 178 * flag them appropriately from some 179 * server. Otherwise, ok to do final 180 * check. 181 */ 182 fs_entry = fsys(entry->cf_ent.path); 183 184 if (is_remote_fs_n(fs_entry) && !is_fs_writeable_n(fs_entry)) { 185 /* 186 * Mark it shared whether it's present 187 * or not. life's too funny for me 188 * to explain. 189 */ 190 pinfo->status = SERVED_FILE; 191 192 /* 193 * restore for now. This may 194 * chg soon. 195 */ 196 entry->cf_ent.path = save_path; 197 } else { 198 /* 199 * If the object is accessible, check 200 * the new entry for existence and 201 * attributes. If there's a problem, 202 * mark it NOT_FND; otherwise, 203 * ENTRY_OK. 204 */ 205 if (is_mounted_n(fs_entry)) { 206 int n; 207 208 n = finalck((&entry->cf_ent), 1, 1, B_FALSE); 209 210 pinfo->status = ENTRY_OK; 211 if (n != 0) { 212 pinfo->status = NOT_FND; 213 } 214 } 215 216 /* 217 * It's not remote, read-only but it 218 * may look that way to the client. 219 * If it does, overwrite the above 220 * result - mark it shared. 221 */ 222 if (is_served_n(fs_entry)) 223 pinfo->status = SERVED_FILE; 224 225 /* restore original path */ 226 entry->cf_ent.path = save_path; 227 /* and clear save_path */ 228 save_path = NULL; 229 } 230 } 231 232 /* Output entry to contents file. */ 233 if (putcvfpfile(&(entry->cf_ent), vfpo)) { 234 progerr(gettext(ERR_WRITE)); 235 quit(99); 236 } 237 238 return (save_path); 239 } 240