1*5c51f124SMoriah Waterland /* 2*5c51f124SMoriah Waterland * CDDL HEADER START 3*5c51f124SMoriah Waterland * 4*5c51f124SMoriah Waterland * The contents of this file are subject to the terms of the 5*5c51f124SMoriah Waterland * Common Development and Distribution License (the "License"). 6*5c51f124SMoriah Waterland * You may not use this file except in compliance with the License. 7*5c51f124SMoriah Waterland * 8*5c51f124SMoriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5c51f124SMoriah Waterland * or http://www.opensolaris.org/os/licensing. 10*5c51f124SMoriah Waterland * See the License for the specific language governing permissions 11*5c51f124SMoriah Waterland * and limitations under the License. 12*5c51f124SMoriah Waterland * 13*5c51f124SMoriah Waterland * When distributing Covered Code, include this CDDL HEADER in each 14*5c51f124SMoriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5c51f124SMoriah Waterland * If applicable, add the following below this CDDL HEADER, with the 16*5c51f124SMoriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying 17*5c51f124SMoriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner] 18*5c51f124SMoriah Waterland * 19*5c51f124SMoriah Waterland * CDDL HEADER END 20*5c51f124SMoriah Waterland */ 21*5c51f124SMoriah Waterland 22*5c51f124SMoriah Waterland /* 23*5c51f124SMoriah Waterland * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*5c51f124SMoriah Waterland * Use is subject to license terms. 25*5c51f124SMoriah Waterland */ 26*5c51f124SMoriah Waterland 27*5c51f124SMoriah Waterland 28*5c51f124SMoriah Waterland /* 29*5c51f124SMoriah Waterland * special.c 30*5c51f124SMoriah Waterland * 31*5c51f124SMoriah Waterland * This module contains code required to remove special contents from 32*5c51f124SMoriah Waterland * the contents file when a pkgrm is done on a system upgraded to use 33*5c51f124SMoriah Waterland * the new database. 34*5c51f124SMoriah Waterland */ 35*5c51f124SMoriah Waterland 36*5c51f124SMoriah Waterland #include <stdio.h> 37*5c51f124SMoriah Waterland #include <stdlib.h> 38*5c51f124SMoriah Waterland #include <assert.h> 39*5c51f124SMoriah Waterland #include <errno.h> 40*5c51f124SMoriah Waterland #include <unistd.h> 41*5c51f124SMoriah Waterland #include <string.h> 42*5c51f124SMoriah Waterland #include <time.h> 43*5c51f124SMoriah Waterland #include <limits.h> 44*5c51f124SMoriah Waterland #include <fnmatch.h> 45*5c51f124SMoriah Waterland #include <sys/types.h> 46*5c51f124SMoriah Waterland #include <sys/stat.h> 47*5c51f124SMoriah Waterland #include <pkgstrct.h> 48*5c51f124SMoriah Waterland #include "pkglib.h" 49*5c51f124SMoriah Waterland #include <libintl.h> 50*5c51f124SMoriah Waterland 51*5c51f124SMoriah Waterland /* This specifies the maximum length of a contents file line read in. */ 52*5c51f124SMoriah Waterland #define LINESZ 8192 53*5c51f124SMoriah Waterland 54*5c51f124SMoriah Waterland #define SPECIAL_MALLOC "unable to maintain package contents text due to "\ 55*5c51f124SMoriah Waterland "insufficient memory." 56*5c51f124SMoriah Waterland #define SPECIAL_ACCESS "unable to maintain package contents text due to "\ 57*5c51f124SMoriah Waterland "an access failure." 58*5c51f124SMoriah Waterland #define SPECIAL_INPUT "unable to maintain package contents text: alternate "\ 59*5c51f124SMoriah Waterland "root path too long" 60*5c51f124SMoriah Waterland 61*5c51f124SMoriah Waterland /* 62*5c51f124SMoriah Waterland * strcompare 63*5c51f124SMoriah Waterland * 64*5c51f124SMoriah Waterland * This function is used by qsort to sort an array of special contents 65*5c51f124SMoriah Waterland * rule strings. This array must be sorted to facilitate efficient 66*5c51f124SMoriah Waterland * rule processing. See qsort(3c) regarding qsort compare functions. 67*5c51f124SMoriah Waterland */ 68*5c51f124SMoriah Waterland static int 69*5c51f124SMoriah Waterland strcompare(const void *pv1, const void *pv2) 70*5c51f124SMoriah Waterland { 71*5c51f124SMoriah Waterland char **ppc1 = (char **) pv1; 72*5c51f124SMoriah Waterland char **ppc2 = (char **) pv2; 73*5c51f124SMoriah Waterland int i = strcmp(*ppc1, *ppc2); 74*5c51f124SMoriah Waterland if (i < 0) 75*5c51f124SMoriah Waterland return (-1); 76*5c51f124SMoriah Waterland if (i > 0) 77*5c51f124SMoriah Waterland return (1); 78*5c51f124SMoriah Waterland return (0); 79*5c51f124SMoriah Waterland } 80*5c51f124SMoriah Waterland 81*5c51f124SMoriah Waterland /* 82*5c51f124SMoriah Waterland * match 83*5c51f124SMoriah Waterland * 84*5c51f124SMoriah Waterland * This function determines whether a file name (pc) matches a rule 85*5c51f124SMoriah Waterland * from the special contents file (pcrule). We assume that neither 86*5c51f124SMoriah Waterland * string is ever NULL. 87*5c51f124SMoriah Waterland * 88*5c51f124SMoriah Waterland * Return: 1 on match, 0 on no match. 89*5c51f124SMoriah Waterland * Side effects: none. 90*5c51f124SMoriah Waterland */ 91*5c51f124SMoriah Waterland static int 92*5c51f124SMoriah Waterland match(const char *pc, char *pcrule) 93*5c51f124SMoriah Waterland { 94*5c51f124SMoriah Waterland int n = strlen(pcrule); 95*5c51f124SMoriah Waterland int wild = 0; 96*5c51f124SMoriah Waterland if (pcrule[n - 1] == '*') { 97*5c51f124SMoriah Waterland wild = 1; 98*5c51f124SMoriah Waterland pcrule[n - 1] = '\0'; 99*5c51f124SMoriah Waterland } 100*5c51f124SMoriah Waterland 101*5c51f124SMoriah Waterland if (!wild) { 102*5c51f124SMoriah Waterland if (fnmatch(pc, pcrule, FNM_PATHNAME) == 0 || 103*5c51f124SMoriah Waterland fnmatch(pc, pcrule, 0) == 0) 104*5c51f124SMoriah Waterland return (1); 105*5c51f124SMoriah Waterland } else { 106*5c51f124SMoriah Waterland int j; 107*5c51f124SMoriah Waterland j = strncmp(pc, pcrule, n - 1); 108*5c51f124SMoriah Waterland pcrule[n - 1] = '*'; 109*5c51f124SMoriah Waterland if (j == 0) 110*5c51f124SMoriah Waterland return (1); 111*5c51f124SMoriah Waterland } 112*5c51f124SMoriah Waterland return (0); 113*5c51f124SMoriah Waterland } 114*5c51f124SMoriah Waterland 115*5c51f124SMoriah Waterland /* 116*5c51f124SMoriah Waterland * search_special_contents 117*5c51f124SMoriah Waterland * 118*5c51f124SMoriah Waterland * This function assumes that a series of calls will be made requesting 119*5c51f124SMoriah Waterland * whether a given path matches the special contents rules or not. We 120*5c51f124SMoriah Waterland * assume that 121*5c51f124SMoriah Waterland * 122*5c51f124SMoriah Waterland * a) the special_contents array is sorted 123*5c51f124SMoriah Waterland * b) the calls will be made with paths in a sorted order 124*5c51f124SMoriah Waterland * 125*5c51f124SMoriah Waterland * Given that, we can keep track of where the last search ended and 126*5c51f124SMoriah Waterland * begin the new search at that point. This reduces the cost of a 127*5c51f124SMoriah Waterland * special contents matching search to O(n) from O(n^2). 128*5c51f124SMoriah Waterland * 129*5c51f124SMoriah Waterland * ppcSC A pointer to an array of special contents obtained via 130*5c51f124SMoriah Waterland * get_special_contents(). 131*5c51f124SMoriah Waterland * path A path: determine whether it matches the special 132*5c51f124SMoriah Waterland * contents rules or not. 133*5c51f124SMoriah Waterland * piX The position in the special_contents array we have already 134*5c51f124SMoriah Waterland * arrived at through searching. This must be initialized to 135*5c51f124SMoriah Waterland * zero before initiating a series of search_special_contents 136*5c51f124SMoriah Waterland * operations. 137*5c51f124SMoriah Waterland * 138*5c51f124SMoriah Waterland * Example: 139*5c51f124SMoriah Waterland * { 140*5c51f124SMoriah Waterland * int i = 0, j, max; 141*5c51f124SMoriah Waterland * char **ppSC = NULL; 142*5c51f124SMoriah Waterland * if (get_special_contents(NULL, &ppcSC, &max) != 0) exit(1); 143*5c51f124SMoriah Waterland * for (j = 0; paths != NULL && paths[j] != NULL; j++) { 144*5c51f124SMoriah Waterland * if (search_special_contents(ppcSC, path[j], &i)) { 145*5c51f124SMoriah Waterland * do_something_with_special_path(path[j]); 146*5c51f124SMoriah Waterland * } 147*5c51f124SMoriah Waterland * } 148*5c51f124SMoriah Waterland * } 149*5c51f124SMoriah Waterland * 150*5c51f124SMoriah Waterland * Return: 1 if there is a match, 0 otherwise. 151*5c51f124SMoriah Waterland * Side effects: The value of *piX will be set between calls to this 152*5c51f124SMoriah Waterland * function. To make this function thread safe, use search arrays. 153*5c51f124SMoriah Waterland * Also: Nonmatching entries are eliminated, set to NULL. 154*5c51f124SMoriah Waterland */ 155*5c51f124SMoriah Waterland static int 156*5c51f124SMoriah Waterland search_special_contents(char **ppcSC, const char *pcpath, int *piX, int max) 157*5c51f124SMoriah Waterland { 158*5c51f124SMoriah Waterland int wild; 159*5c51f124SMoriah Waterland if (ppcSC == NULL || *piX == max) 160*5c51f124SMoriah Waterland return (0); 161*5c51f124SMoriah Waterland 162*5c51f124SMoriah Waterland while (*piX < max) { 163*5c51f124SMoriah Waterland 164*5c51f124SMoriah Waterland int j, k; 165*5c51f124SMoriah Waterland if (ppcSC[*piX] == NULL) { 166*5c51f124SMoriah Waterland (*piX)++; 167*5c51f124SMoriah Waterland continue; 168*5c51f124SMoriah Waterland } 169*5c51f124SMoriah Waterland 170*5c51f124SMoriah Waterland j = strlen(ppcSC[*piX]); 171*5c51f124SMoriah Waterland k = strcmp(pcpath, ppcSC[*piX]); 172*5c51f124SMoriah Waterland wild = (ppcSC[*piX][j - 1] == '*'); 173*5c51f124SMoriah Waterland 174*5c51f124SMoriah Waterland /* 175*5c51f124SMoriah Waterland * Depending on whether the path string compared with the 176*5c51f124SMoriah Waterland * rule, we take different actions. If the path is less 177*5c51f124SMoriah Waterland * than the rule, we keep the rule. If the path equals 178*5c51f124SMoriah Waterland * the rule, we advance the rule (as long as the rule is 179*5c51f124SMoriah Waterland * not a wild card). If the path is greater than the rule, 180*5c51f124SMoriah Waterland * we have to advance the rule list until we are less or equal 181*5c51f124SMoriah Waterland * again. This way we only have to make one pass through the 182*5c51f124SMoriah Waterland * rules, as we make one pass through the path strings. We 183*5c51f124SMoriah Waterland * assume that the rules and the path strings are sorted. 184*5c51f124SMoriah Waterland */ 185*5c51f124SMoriah Waterland if (k < 0) { 186*5c51f124SMoriah Waterland 187*5c51f124SMoriah Waterland if (wild == 0) 188*5c51f124SMoriah Waterland return (0); 189*5c51f124SMoriah Waterland 190*5c51f124SMoriah Waterland if (match(pcpath, ppcSC[*piX])) 191*5c51f124SMoriah Waterland return (1); 192*5c51f124SMoriah Waterland break; 193*5c51f124SMoriah Waterland 194*5c51f124SMoriah Waterland } else if (k == 0) { 195*5c51f124SMoriah Waterland 196*5c51f124SMoriah Waterland int x = match(pcpath, ppcSC[*piX]); 197*5c51f124SMoriah Waterland if (wild == 0) (*piX)++; 198*5c51f124SMoriah Waterland return (x); 199*5c51f124SMoriah Waterland 200*5c51f124SMoriah Waterland } else { 201*5c51f124SMoriah Waterland /* One last try. */ 202*5c51f124SMoriah Waterland if (match(pcpath, ppcSC[*piX])) 203*5c51f124SMoriah Waterland return (1); 204*5c51f124SMoriah Waterland 205*5c51f124SMoriah Waterland /* 206*5c51f124SMoriah Waterland * As pcpath > ppcSC[*piX] we have passed up this 207*5c51f124SMoriah Waterland * rule - it cannot apply. Therefore, we do not 208*5c51f124SMoriah Waterland * need to retain it. Removing the rule will make 209*5c51f124SMoriah Waterland * subsequent searching more efficient. 210*5c51f124SMoriah Waterland */ 211*5c51f124SMoriah Waterland free(ppcSC[*piX]); 212*5c51f124SMoriah Waterland ppcSC[*piX] = NULL; 213*5c51f124SMoriah Waterland 214*5c51f124SMoriah Waterland (*piX)++; 215*5c51f124SMoriah Waterland } 216*5c51f124SMoriah Waterland } 217*5c51f124SMoriah Waterland return (0); 218*5c51f124SMoriah Waterland } 219*5c51f124SMoriah Waterland 220*5c51f124SMoriah Waterland /* 221*5c51f124SMoriah Waterland * get_special_contents 222*5c51f124SMoriah Waterland * 223*5c51f124SMoriah Waterland * Retrieves the special contents file entries, if they exist. These 224*5c51f124SMoriah Waterland * are sorted. We do not assume the special_contents file is in sorted 225*5c51f124SMoriah Waterland * order. 226*5c51f124SMoriah Waterland * 227*5c51f124SMoriah Waterland * pcroot The root of the install database. If NULL assume '/'. 228*5c51f124SMoriah Waterland * pppcSC A pointer to a char **. This pointer will be set to 229*5c51f124SMoriah Waterland * point at NULL if there is no special_contents file or 230*5c51f124SMoriah Waterland * to a sorted array of strings, NULL terminated, otherwise. 231*5c51f124SMoriah Waterland * piMax The # of entries in the special contents result. 232*5c51f124SMoriah Waterland * 233*5c51f124SMoriah Waterland * Returns: 0 on no error, nonzero on error. 234*5c51f124SMoriah Waterland * Side effects: the pppcSC pointer is set to point at a newly 235*5c51f124SMoriah Waterland * allocated array of pointers to strings.. The caller must 236*5c51f124SMoriah Waterland * free this buffer. The value of *piMax is set to the # of 237*5c51f124SMoriah Waterland * entries in ppcSC. 238*5c51f124SMoriah Waterland */ 239*5c51f124SMoriah Waterland static int 240*5c51f124SMoriah Waterland get_special_contents(const char *pcroot, char ***pppcSC, int *piMax) 241*5c51f124SMoriah Waterland { 242*5c51f124SMoriah Waterland int e, i; 243*5c51f124SMoriah Waterland FILE *fp; 244*5c51f124SMoriah Waterland char line[2048]; 245*5c51f124SMoriah Waterland char **ppc; 246*5c51f124SMoriah Waterland char *pc = "var/sadm/install/special_contents"; 247*5c51f124SMoriah Waterland char path[PATH_MAX]; 248*5c51f124SMoriah Waterland struct stat s; 249*5c51f124SMoriah Waterland 250*5c51f124SMoriah Waterland /* Initialize the return values. */ 251*5c51f124SMoriah Waterland *piMax = 0; 252*5c51f124SMoriah Waterland *pppcSC = NULL; 253*5c51f124SMoriah Waterland 254*5c51f124SMoriah Waterland if (pcroot == NULL) { 255*5c51f124SMoriah Waterland pcroot = "/"; 256*5c51f124SMoriah Waterland } 257*5c51f124SMoriah Waterland 258*5c51f124SMoriah Waterland if (pcroot[strlen(pcroot) - 1] == '/') { 259*5c51f124SMoriah Waterland if (snprintf(path, PATH_MAX, "%s%s", pcroot, pc) >= PATH_MAX) { 260*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_INPUT)); 261*5c51f124SMoriah Waterland return (1); 262*5c51f124SMoriah Waterland } 263*5c51f124SMoriah Waterland } else { 264*5c51f124SMoriah Waterland if (snprintf(path, PATH_MAX, "%s/%s", pcroot, pc) 265*5c51f124SMoriah Waterland >= PATH_MAX) { 266*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_INPUT)); 267*5c51f124SMoriah Waterland return (1); 268*5c51f124SMoriah Waterland } 269*5c51f124SMoriah Waterland } 270*5c51f124SMoriah Waterland 271*5c51f124SMoriah Waterland errno = 0; 272*5c51f124SMoriah Waterland e = stat(path, &s); 273*5c51f124SMoriah Waterland if (e != 0 && errno == ENOENT) 274*5c51f124SMoriah Waterland return (0); /* No special contents file. Do nothing. */ 275*5c51f124SMoriah Waterland 276*5c51f124SMoriah Waterland if (access(path, R_OK) != 0 || (fp = fopen(path, "r")) == NULL) { 277*5c51f124SMoriah Waterland /* Could not open special contents which exists */ 278*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 279*5c51f124SMoriah Waterland return (1); 280*5c51f124SMoriah Waterland } 281*5c51f124SMoriah Waterland 282*5c51f124SMoriah Waterland for (i = 0; fgets(line, 2048, fp) != NULL; i++); 283*5c51f124SMoriah Waterland rewind(fp); 284*5c51f124SMoriah Waterland if ((ppc = (char **) calloc(i + 1, sizeof (char *))) == NULL) { 285*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_MALLOC)); 286*5c51f124SMoriah Waterland return (1); 287*5c51f124SMoriah Waterland } 288*5c51f124SMoriah Waterland 289*5c51f124SMoriah Waterland for (i = 0; fgets(line, 2048, fp) != NULL; ) { 290*5c51f124SMoriah Waterland int n; 291*5c51f124SMoriah Waterland if (line[0] == '#' || line[0] == ' ' || line[0] == '\n' || 292*5c51f124SMoriah Waterland line[0] == '\t' || line[0] == '\r') 293*5c51f124SMoriah Waterland continue; 294*5c51f124SMoriah Waterland n = strlen(line); 295*5c51f124SMoriah Waterland if (line[n - 1] == '\n') 296*5c51f124SMoriah Waterland line[n - 1] = '\0'; 297*5c51f124SMoriah Waterland ppc[i++] = strdup(line); 298*5c51f124SMoriah Waterland } 299*5c51f124SMoriah Waterland 300*5c51f124SMoriah Waterland qsort(ppc, i, sizeof (char *), strcompare); 301*5c51f124SMoriah Waterland 302*5c51f124SMoriah Waterland *pppcSC = ppc; 303*5c51f124SMoriah Waterland *piMax = i; 304*5c51f124SMoriah Waterland return (0); 305*5c51f124SMoriah Waterland } 306*5c51f124SMoriah Waterland 307*5c51f124SMoriah Waterland /* 308*5c51f124SMoriah Waterland * free_special_contents 309*5c51f124SMoriah Waterland * 310*5c51f124SMoriah Waterland * This function frees special_contents which have been allocated using 311*5c51f124SMoriah Waterland * get_special_contents. 312*5c51f124SMoriah Waterland * 313*5c51f124SMoriah Waterland * pppcSC A pointer to a buffer allocated using get_special_contents. 314*5c51f124SMoriah Waterland * max The number of entries allocated. 315*5c51f124SMoriah Waterland * 316*5c51f124SMoriah Waterland * Result: None. 317*5c51f124SMoriah Waterland * Side effects: Frees memory allocated using get_special_contents and 318*5c51f124SMoriah Waterland * sets the pointer passed in to NULL. 319*5c51f124SMoriah Waterland */ 320*5c51f124SMoriah Waterland static void 321*5c51f124SMoriah Waterland free_special_contents(char ***pppcSC, int max) 322*5c51f124SMoriah Waterland { 323*5c51f124SMoriah Waterland int i; 324*5c51f124SMoriah Waterland char **ppc = NULL; 325*5c51f124SMoriah Waterland if (*pppcSC == NULL) 326*5c51f124SMoriah Waterland return; 327*5c51f124SMoriah Waterland 328*5c51f124SMoriah Waterland ppc = *pppcSC; 329*5c51f124SMoriah Waterland for (i = 0; ppc != NULL && i < max; i++) 330*5c51f124SMoriah Waterland if (ppc[i] == NULL) 331*5c51f124SMoriah Waterland free(ppc[i]); 332*5c51f124SMoriah Waterland 333*5c51f124SMoriah Waterland if (ppc != NULL) 334*5c51f124SMoriah Waterland free(ppc); 335*5c51f124SMoriah Waterland 336*5c51f124SMoriah Waterland *pppcSC = NULL; 337*5c51f124SMoriah Waterland } 338*5c51f124SMoriah Waterland 339*5c51f124SMoriah Waterland /* 340*5c51f124SMoriah Waterland * get_path 341*5c51f124SMoriah Waterland * 342*5c51f124SMoriah Waterland * Return the first field of a string delimited by a space. 343*5c51f124SMoriah Waterland * 344*5c51f124SMoriah Waterland * pcline A line from the contents file. 345*5c51f124SMoriah Waterland * 346*5c51f124SMoriah Waterland * Return: NULL if an error. Otherwise a string allocated by this 347*5c51f124SMoriah Waterland * function. The caller must free the string. 348*5c51f124SMoriah Waterland * Side effects: none. 349*5c51f124SMoriah Waterland */ 350*5c51f124SMoriah Waterland static char * 351*5c51f124SMoriah Waterland get_path(const char *pcline) 352*5c51f124SMoriah Waterland { 353*5c51f124SMoriah Waterland int i = strcspn(pcline, " "); 354*5c51f124SMoriah Waterland char *pc = NULL; 355*5c51f124SMoriah Waterland if (i <= 1 || (pc = (char *) calloc(i + 1, 1)) == NULL) 356*5c51f124SMoriah Waterland return (NULL); 357*5c51f124SMoriah Waterland (void) memcpy(pc, pcline, i); 358*5c51f124SMoriah Waterland return (pc); 359*5c51f124SMoriah Waterland } 360*5c51f124SMoriah Waterland 361*5c51f124SMoriah Waterland /* 362*5c51f124SMoriah Waterland * generate_special_contents_rules 363*5c51f124SMoriah Waterland * 364*5c51f124SMoriah Waterland * This procedure will generate an array of integers which will be a mask 365*5c51f124SMoriah Waterland * to apply to the ppcfextra array. If set to 1, then the content must be 366*5c51f124SMoriah Waterland * added to the contents file. Otherwise it will not be: The old contents 367*5c51f124SMoriah Waterland * file will be used for this path value, if one even exists. 368*5c51f124SMoriah Waterland * 369*5c51f124SMoriah Waterland * ient The number of ppcfextra contents installed. 370*5c51f124SMoriah Waterland * ppcfent The contents installed. 371*5c51f124SMoriah Waterland * ppcSC The rules (special contents) 372*5c51f124SMoriah Waterland * max The number of special contents rules. 373*5c51f124SMoriah Waterland * ppiIndex The array of integer values, determining whether 374*5c51f124SMoriah Waterland * individual ppcfextra items match special contents rules. 375*5c51f124SMoriah Waterland * This array will be created and set in this function and 376*5c51f124SMoriah Waterland * returned. 377*5c51f124SMoriah Waterland * 378*5c51f124SMoriah Waterland * Return: 0 success, nonzero failure 379*5c51f124SMoriah Waterland * Side effects: allocates an array of integers that the caller must free. 380*5c51f124SMoriah Waterland */ 381*5c51f124SMoriah Waterland static int 382*5c51f124SMoriah Waterland generate_special_contents_rules(int ient, struct cfent **ppcfent, 383*5c51f124SMoriah Waterland char **ppcSC, int max, int **ppiIndex) 384*5c51f124SMoriah Waterland { 385*5c51f124SMoriah Waterland int i, j; 386*5c51f124SMoriah Waterland int *pi = (int *) calloc(ient, sizeof (int)); 387*5c51f124SMoriah Waterland if (pi == NULL) { 388*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_MALLOC)); 389*5c51f124SMoriah Waterland return (1); 390*5c51f124SMoriah Waterland } 391*5c51f124SMoriah Waterland 392*5c51f124SMoriah Waterland /* 393*5c51f124SMoriah Waterland * For each entry in ppcfextra, check if it matches a rule. 394*5c51f124SMoriah Waterland * If it does not, set the entry in the index to -1. 395*5c51f124SMoriah Waterland */ 396*5c51f124SMoriah Waterland for (i = 0, j = 0; i < ient && j < max; i++) { 397*5c51f124SMoriah Waterland if (search_special_contents(ppcSC, ppcfent[i]->path, 398*5c51f124SMoriah Waterland &j, max) == 1) { 399*5c51f124SMoriah Waterland pi[i] = 1; 400*5c51f124SMoriah Waterland 401*5c51f124SMoriah Waterland } else { 402*5c51f124SMoriah Waterland pi[i] = 0; 403*5c51f124SMoriah Waterland } 404*5c51f124SMoriah Waterland } 405*5c51f124SMoriah Waterland 406*5c51f124SMoriah Waterland /* 407*5c51f124SMoriah Waterland * In case we ran out of rules before contents, we will not use 408*5c51f124SMoriah Waterland * those contents. Make sure these contents are set to 0 and 409*5c51f124SMoriah Waterland * will not be copied from the ppcfent array into the contents 410*5c51f124SMoriah Waterland * file. 411*5c51f124SMoriah Waterland */ 412*5c51f124SMoriah Waterland for (i = i; i < ient; i++) 413*5c51f124SMoriah Waterland pi[i] = 0; 414*5c51f124SMoriah Waterland 415*5c51f124SMoriah Waterland *ppiIndex = pi; 416*5c51f124SMoriah Waterland return (0); 417*5c51f124SMoriah Waterland } 418*5c51f124SMoriah Waterland 419*5c51f124SMoriah Waterland 420*5c51f124SMoriah Waterland /* 421*5c51f124SMoriah Waterland * pathcmp 422*5c51f124SMoriah Waterland * 423*5c51f124SMoriah Waterland * Compare a path to a cfent. It will match either if the path is 424*5c51f124SMoriah Waterland * equal to the cfent path, or if the cfent is a symbolic or link 425*5c51f124SMoriah Waterland * and *that* matches. 426*5c51f124SMoriah Waterland * 427*5c51f124SMoriah Waterland * path a path 428*5c51f124SMoriah Waterland * pent a contents entry 429*5c51f124SMoriah Waterland * 430*5c51f124SMoriah Waterland * Returns: as per strcmp 431*5c51f124SMoriah Waterland * Side effects: none. 432*5c51f124SMoriah Waterland */ 433*5c51f124SMoriah Waterland static int 434*5c51f124SMoriah Waterland pathcmp(const char *pc, const struct cfent *pent) 435*5c51f124SMoriah Waterland { 436*5c51f124SMoriah Waterland int i; 437*5c51f124SMoriah Waterland if ((pent->ftype == 's' || pent->ftype == 'l') && 438*5c51f124SMoriah Waterland pent->ainfo.local) { 439*5c51f124SMoriah Waterland char *p, *q; 440*5c51f124SMoriah Waterland if ((p = strstr(pc, "=")) == NULL) { 441*5c51f124SMoriah Waterland 442*5c51f124SMoriah Waterland i = strcmp(pc, pent->path); 443*5c51f124SMoriah Waterland 444*5c51f124SMoriah Waterland /* A path without additional chars strcmp's to less */ 445*5c51f124SMoriah Waterland if (i == 0) 446*5c51f124SMoriah Waterland i = -1; 447*5c51f124SMoriah Waterland 448*5c51f124SMoriah Waterland } else { 449*5c51f124SMoriah Waterland /* Break the link path into two pieces. */ 450*5c51f124SMoriah Waterland *p = '\0'; 451*5c51f124SMoriah Waterland 452*5c51f124SMoriah Waterland /* Compare the first piece. */ 453*5c51f124SMoriah Waterland i = strcmp(pc, pent->path); 454*5c51f124SMoriah Waterland 455*5c51f124SMoriah Waterland /* If equal we must compare the second piece. */ 456*5c51f124SMoriah Waterland if (i == 0) { 457*5c51f124SMoriah Waterland q = p + 1; 458*5c51f124SMoriah Waterland i = strcmp(q, pent->ainfo.local); 459*5c51f124SMoriah Waterland } 460*5c51f124SMoriah Waterland 461*5c51f124SMoriah Waterland /* Restore the link path. */ 462*5c51f124SMoriah Waterland *p = '='; 463*5c51f124SMoriah Waterland } 464*5c51f124SMoriah Waterland } else { 465*5c51f124SMoriah Waterland i = strcmp(pc, pent->path); 466*5c51f124SMoriah Waterland } 467*5c51f124SMoriah Waterland 468*5c51f124SMoriah Waterland return (i); 469*5c51f124SMoriah Waterland } 470*5c51f124SMoriah Waterland 471*5c51f124SMoriah Waterland /* 472*5c51f124SMoriah Waterland * ----------------------------------------------------------------------- 473*5c51f124SMoriah Waterland * Externally visible function. 474*5c51f124SMoriah Waterland */ 475*5c51f124SMoriah Waterland 476*5c51f124SMoriah Waterland /* 477*5c51f124SMoriah Waterland * special_contents_remove 478*5c51f124SMoriah Waterland * 479*5c51f124SMoriah Waterland * Given a set of entries to remove and an alternate root, this function 480*5c51f124SMoriah Waterland * will do everything required to ensure that the entries are removed 481*5c51f124SMoriah Waterland * from the contents file if they are listed in the special_contents 482*5c51f124SMoriah Waterland * file. The contents file will get changed only in the case that the 483*5c51f124SMoriah Waterland * entire operation has succeeded. 484*5c51f124SMoriah Waterland * 485*5c51f124SMoriah Waterland * ient The number of entries. 486*5c51f124SMoriah Waterland * ppcfent The entries to remove. 487*5c51f124SMoriah Waterland * pcroot The alternate install root. Could be NULL. In this 488*5c51f124SMoriah Waterland * case, assume root is '/' 489*5c51f124SMoriah Waterland * 490*5c51f124SMoriah Waterland * Result: 0 on success, nonzero on failure. If an error occurs, an 491*5c51f124SMoriah Waterland * error string will get output to standard error alerting the user. 492*5c51f124SMoriah Waterland * Side effects: The contents file may change as a result of this call, 493*5c51f124SMoriah Waterland * such that lines in the in the file will be changed or removed. 494*5c51f124SMoriah Waterland * If the call fails, a t.contents file may be left behind. This 495*5c51f124SMoriah Waterland * temporary file should be removed subsequently. 496*5c51f124SMoriah Waterland */ 497*5c51f124SMoriah Waterland int 498*5c51f124SMoriah Waterland special_contents_remove(int ient, struct cfent **ppcfent, const char *pcroot) 499*5c51f124SMoriah Waterland { 500*5c51f124SMoriah Waterland int result = 0; /* Assume we will succeed. Return result. */ 501*5c51f124SMoriah Waterland char **ppcSC = NULL; /* The special contents rules, sorted. */ 502*5c51f124SMoriah Waterland int i, j; /* Indexes into contents & special contents */ 503*5c51f124SMoriah Waterland FILE *fpi = NULL, /* Input of contents file */ 504*5c51f124SMoriah Waterland *fpo = NULL; /* Output to temp contents file */ 505*5c51f124SMoriah Waterland char cpath[PATH_MAX], /* Contents file path */ 506*5c51f124SMoriah Waterland tcpath[PATH_MAX]; /* Temp contents file path */ 507*5c51f124SMoriah Waterland const char *pccontents = "var/sadm/install/contents"; 508*5c51f124SMoriah Waterland const char *pctcontents = "var/sadm/install/t.contents"; 509*5c51f124SMoriah Waterland char line[LINESZ]; /* Reads in and writes out contents lines. */ 510*5c51f124SMoriah Waterland time_t t; /* Used to create a timestamp comment. */ 511*5c51f124SMoriah Waterland int max; /* Max number of special contents entries. */ 512*5c51f124SMoriah Waterland int *piIndex; /* An index to ppcfents to remove from cfile */ 513*5c51f124SMoriah Waterland 514*5c51f124SMoriah Waterland cpath[0] = tcpath[0] = '\0'; 515*5c51f124SMoriah Waterland 516*5c51f124SMoriah Waterland if (ient == 0 || ppcfent == NULL || ppcfent[0] == NULL) { 517*5c51f124SMoriah Waterland goto remove_done; 518*5c51f124SMoriah Waterland } 519*5c51f124SMoriah Waterland 520*5c51f124SMoriah Waterland if ((get_special_contents(pcroot, &ppcSC, &max)) != 0) { 521*5c51f124SMoriah Waterland result = 1; 522*5c51f124SMoriah Waterland goto remove_done; 523*5c51f124SMoriah Waterland } 524*5c51f124SMoriah Waterland 525*5c51f124SMoriah Waterland /* Check if there are no special contents actions to take. */ 526*5c51f124SMoriah Waterland if (ppcSC == NULL) { 527*5c51f124SMoriah Waterland goto remove_done; 528*5c51f124SMoriah Waterland } 529*5c51f124SMoriah Waterland 530*5c51f124SMoriah Waterland if (pcroot == NULL) pcroot = "/"; 531*5c51f124SMoriah Waterland if (pcroot[strlen(pcroot) - 1] == '/') { 532*5c51f124SMoriah Waterland if (snprintf(cpath, PATH_MAX, "%s%s", pcroot, pccontents) 533*5c51f124SMoriah Waterland >= PATH_MAX || 534*5c51f124SMoriah Waterland snprintf(tcpath, PATH_MAX, "%s%s", pcroot, pctcontents) 535*5c51f124SMoriah Waterland >= PATH_MAX) { 536*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_INPUT)); 537*5c51f124SMoriah Waterland result = -1; 538*5c51f124SMoriah Waterland goto remove_done; 539*5c51f124SMoriah Waterland } 540*5c51f124SMoriah Waterland } else { 541*5c51f124SMoriah Waterland if (snprintf(cpath, PATH_MAX, "%s/%s", pcroot, pccontents) 542*5c51f124SMoriah Waterland >= PATH_MAX || 543*5c51f124SMoriah Waterland snprintf(tcpath, PATH_MAX, "%s/%s", pcroot, pctcontents) 544*5c51f124SMoriah Waterland >= PATH_MAX) { 545*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_INPUT)); 546*5c51f124SMoriah Waterland result = -1; 547*5c51f124SMoriah Waterland goto remove_done; 548*5c51f124SMoriah Waterland } 549*5c51f124SMoriah Waterland } 550*5c51f124SMoriah Waterland 551*5c51f124SMoriah Waterland /* Open the temporary contents file to write, contents to read. */ 552*5c51f124SMoriah Waterland if (access(cpath, F_OK | R_OK) != 0) { 553*5c51f124SMoriah Waterland /* 554*5c51f124SMoriah Waterland * This is not a problem since no contents means nothing 555*5c51f124SMoriah Waterland * to remove due to special contents rules. 556*5c51f124SMoriah Waterland */ 557*5c51f124SMoriah Waterland result = 0; 558*5c51f124SMoriah Waterland cpath[0] = '\0'; /* This signals omission of 'rename cleanup' */ 559*5c51f124SMoriah Waterland goto remove_done; 560*5c51f124SMoriah Waterland } 561*5c51f124SMoriah Waterland 562*5c51f124SMoriah Waterland if (access(cpath, W_OK) != 0) { 563*5c51f124SMoriah Waterland /* can't write contents file, something is wrong. */ 564*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 565*5c51f124SMoriah Waterland result = 1; 566*5c51f124SMoriah Waterland goto remove_done; 567*5c51f124SMoriah Waterland 568*5c51f124SMoriah Waterland } 569*5c51f124SMoriah Waterland 570*5c51f124SMoriah Waterland if ((fpi = fopen(cpath, "r")) == NULL) { 571*5c51f124SMoriah Waterland /* Given the access test above, this should not happen. */ 572*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 573*5c51f124SMoriah Waterland result = 1; 574*5c51f124SMoriah Waterland goto remove_done; 575*5c51f124SMoriah Waterland } 576*5c51f124SMoriah Waterland 577*5c51f124SMoriah Waterland if ((fpo = fopen(tcpath, "w")) == NULL) { 578*5c51f124SMoriah Waterland /* open t.contents failed */ 579*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 580*5c51f124SMoriah Waterland result = 1; 581*5c51f124SMoriah Waterland goto remove_done; 582*5c51f124SMoriah Waterland } 583*5c51f124SMoriah Waterland 584*5c51f124SMoriah Waterland if (generate_special_contents_rules(ient, ppcfent, ppcSC, max, &piIndex) 585*5c51f124SMoriah Waterland != 0) { 586*5c51f124SMoriah Waterland result = 1; 587*5c51f124SMoriah Waterland goto remove_done; 588*5c51f124SMoriah Waterland } 589*5c51f124SMoriah Waterland 590*5c51f124SMoriah Waterland /* 591*5c51f124SMoriah Waterland * Copy contents to t.contents unless there is an entry in 592*5c51f124SMoriah Waterland * the ppcfent array which corresponds to an index set to 1. 593*5c51f124SMoriah Waterland * 594*5c51f124SMoriah Waterland * These items are the removed package contents which matche an 595*5c51f124SMoriah Waterland * entry in ppcSC (the special_contents rules). 596*5c51f124SMoriah Waterland * 597*5c51f124SMoriah Waterland * Since both the contents and rules are sorted, we can 598*5c51f124SMoriah Waterland * make a single efficient pass. 599*5c51f124SMoriah Waterland */ 600*5c51f124SMoriah Waterland (void) memset(line, 0, LINESZ); 601*5c51f124SMoriah Waterland 602*5c51f124SMoriah Waterland for (i = 0, j = 0; fgets(line, LINESZ, fpi) != NULL; ) { 603*5c51f124SMoriah Waterland 604*5c51f124SMoriah Waterland char *pcpath = NULL; 605*5c51f124SMoriah Waterland 606*5c51f124SMoriah Waterland /* 607*5c51f124SMoriah Waterland * Note: This could be done better: We should figure out 608*5c51f124SMoriah Waterland * which are the last 2 lines and only trim those off. 609*5c51f124SMoriah Waterland * This will suffice to do this and will only be done as 610*5c51f124SMoriah Waterland * part of special_contents handling. 611*5c51f124SMoriah Waterland */ 612*5c51f124SMoriah Waterland if (line[0] == '#') 613*5c51f124SMoriah Waterland continue; /* Do not copy the final 2 comment lines */ 614*5c51f124SMoriah Waterland 615*5c51f124SMoriah Waterland pcpath = get_path(line); 616*5c51f124SMoriah Waterland 617*5c51f124SMoriah Waterland if (pcpath != NULL && i < ient) { 618*5c51f124SMoriah Waterland int k; 619*5c51f124SMoriah Waterland while (piIndex[i] == 0) 620*5c51f124SMoriah Waterland i++; 621*5c51f124SMoriah Waterland 622*5c51f124SMoriah Waterland if (i < ient) 623*5c51f124SMoriah Waterland k = pathcmp(pcpath, ppcfent[i]); 624*5c51f124SMoriah Waterland 625*5c51f124SMoriah Waterland if (k < 0 || i >= ient) { 626*5c51f124SMoriah Waterland /* Just copy contents -> t.contents */ 627*5c51f124SMoriah Waterland /*EMPTY*/ 628*5c51f124SMoriah Waterland } else if (k == 0) { 629*5c51f124SMoriah Waterland /* We have a match. Do not copy the content. */ 630*5c51f124SMoriah Waterland i++; 631*5c51f124SMoriah Waterland free(pcpath); 632*5c51f124SMoriah Waterland (void) memset(line, 0, LINESZ); 633*5c51f124SMoriah Waterland continue; 634*5c51f124SMoriah Waterland } else while (i < ient) { 635*5c51f124SMoriah Waterland 636*5c51f124SMoriah Waterland /* 637*5c51f124SMoriah Waterland * This is a complex case: The content 638*5c51f124SMoriah Waterland * entry is further along alphabetically 639*5c51f124SMoriah Waterland * than the rule. Skip over all rules which 640*5c51f124SMoriah Waterland * apply until we come to a rule which is 641*5c51f124SMoriah Waterland * greater than the current entry, or equal 642*5c51f124SMoriah Waterland * to it. If equal, do not copy, otherwise 643*5c51f124SMoriah Waterland * do copy the entry. 644*5c51f124SMoriah Waterland */ 645*5c51f124SMoriah Waterland if (piIndex[i] == 0) { 646*5c51f124SMoriah Waterland i++; 647*5c51f124SMoriah Waterland continue; 648*5c51f124SMoriah Waterland } else if ((k = pathcmp(pcpath, ppcfent[i])) 649*5c51f124SMoriah Waterland >= 0) { 650*5c51f124SMoriah Waterland i++; 651*5c51f124SMoriah Waterland if (k == 0) { 652*5c51f124SMoriah Waterland free(pcpath); 653*5c51f124SMoriah Waterland (void) memset(line, 0, LINESZ); 654*5c51f124SMoriah Waterland break; 655*5c51f124SMoriah Waterland } 656*5c51f124SMoriah Waterland } else { 657*5c51f124SMoriah Waterland /* path < rule, end special case */ 658*5c51f124SMoriah Waterland break; 659*5c51f124SMoriah Waterland } 660*5c51f124SMoriah Waterland } 661*5c51f124SMoriah Waterland 662*5c51f124SMoriah Waterland /* 663*5c51f124SMoriah Waterland * Avoid copying the old content when path == rule 664*5c51f124SMoriah Waterland * This occurs when the complex case ends on a match. 665*5c51f124SMoriah Waterland */ 666*5c51f124SMoriah Waterland if (k == 0) 667*5c51f124SMoriah Waterland continue; 668*5c51f124SMoriah Waterland } 669*5c51f124SMoriah Waterland 670*5c51f124SMoriah Waterland if (fprintf(fpo, "%s", line) < 0) { 671*5c51f124SMoriah Waterland /* Failing to write output would be catastrophic. */ 672*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 673*5c51f124SMoriah Waterland result = 1; 674*5c51f124SMoriah Waterland break; 675*5c51f124SMoriah Waterland } 676*5c51f124SMoriah Waterland (void) memset(line, 0, LINESZ); 677*5c51f124SMoriah Waterland } 678*5c51f124SMoriah Waterland 679*5c51f124SMoriah Waterland t = time(NULL); 680*5c51f124SMoriah Waterland (void) fprintf(fpo, "# Last modified by pkgremove\n"); 681*5c51f124SMoriah Waterland (void) fprintf(fpo, "# %s", ctime(&t)); 682*5c51f124SMoriah Waterland 683*5c51f124SMoriah Waterland remove_done: 684*5c51f124SMoriah Waterland free_special_contents(&ppcSC, max); 685*5c51f124SMoriah Waterland 686*5c51f124SMoriah Waterland if (fpi != NULL) 687*5c51f124SMoriah Waterland (void) fclose(fpi); 688*5c51f124SMoriah Waterland 689*5c51f124SMoriah Waterland if (fpo != NULL) 690*5c51f124SMoriah Waterland (void) fclose(fpo); 691*5c51f124SMoriah Waterland 692*5c51f124SMoriah Waterland if (result == 0) { 693*5c51f124SMoriah Waterland if (tcpath[0] != '\0' && cpath[0] != '\0' && 694*5c51f124SMoriah Waterland rename(tcpath, cpath) != 0) { 695*5c51f124SMoriah Waterland progerr(gettext(SPECIAL_ACCESS)); 696*5c51f124SMoriah Waterland result = 1; 697*5c51f124SMoriah Waterland } 698*5c51f124SMoriah Waterland } else { 699*5c51f124SMoriah Waterland if (tcpath[0] != '\0' && remove(tcpath) != 0) { 700*5c51f124SMoriah Waterland /* 701*5c51f124SMoriah Waterland * Do not output a diagnostic message. This condition 702*5c51f124SMoriah Waterland * occurs only when we are unable to clean up after 703*5c51f124SMoriah Waterland * a failure. A temporary file will linger. 704*5c51f124SMoriah Waterland */ 705*5c51f124SMoriah Waterland result = 1; 706*5c51f124SMoriah Waterland } 707*5c51f124SMoriah Waterland } 708*5c51f124SMoriah Waterland 709*5c51f124SMoriah Waterland return (result); 710*5c51f124SMoriah Waterland } 711