10eb10989Smrg/* 20eb10989Smrg 30eb10989SmrgCopyright (c) 1993, 1994, 1998 The Open Group 40eb10989Smrg 50eb10989SmrgPermission to use, copy, modify, distribute, and sell this software and its 60eb10989Smrgdocumentation for any purpose is hereby granted without fee, provided that 70eb10989Smrgthe above copyright notice appear in all copies and that both that 80eb10989Smrgcopyright notice and this permission notice appear in supporting 90eb10989Smrgdocumentation. 100eb10989Smrg 110eb10989SmrgThe above copyright notice and this permission notice shall be included in 120eb10989Smrgall copies or substantial portions of the Software. 130eb10989Smrg 140eb10989SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 150eb10989SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160eb10989SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 170eb10989SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 180eb10989SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 190eb10989SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 200eb10989Smrg 210eb10989SmrgExcept as contained in this notice, the name of The Open Group shall not be 220eb10989Smrgused in advertising or otherwise to promote the sale, use or other dealings 230eb10989Smrgin this Software without prior written authorization from The Open Group. 240eb10989Smrg 250eb10989Smrg*/ 260eb10989Smrg 270eb10989Smrg#include "def.h" 280eb10989Smrg 290eb10989Smrgstatic boolean 3063165362Smrgisdot(const char *p) 310eb10989Smrg{ 32fadff096Smrg if (p && *p++ == '.' && *p++ == '\0') 33fadff096Smrg return (TRUE); 34fadff096Smrg return (FALSE); 350eb10989Smrg} 360eb10989Smrg 370eb10989Smrgstatic boolean 3863165362Smrgisdotdot(const char *p) 390eb10989Smrg{ 40fadff096Smrg if (p && *p++ == '.' && *p++ == '.' && *p++ == '\0') 41fadff096Smrg return (TRUE); 42fadff096Smrg return (FALSE); 430eb10989Smrg} 440eb10989Smrg 450eb10989Smrgstatic boolean 4663165362Smrgissymbolic(const char *dir, const char *component) 470eb10989Smrg{ 480eb10989Smrg#ifdef S_IFLNK 49fadff096Smrg struct stat st; 50fadff096Smrg char buf[BUFSIZ], **pp; 51fadff096Smrg 52fadff096Smrg snprintf(buf, sizeof(buf), "%s%s%s", dir, *dir ? "/" : "", component); 53fadff096Smrg for (pp = notdotdot; *pp; pp++) 54fadff096Smrg if (strcmp(*pp, buf) == 0) 55fadff096Smrg return (TRUE); 56fadff096Smrg if (lstat(buf, &st) == 0 && (st.st_mode & S_IFMT) == S_IFLNK) { 57fadff096Smrg char *p = strdup(buf); 58fadff096Smrg if (p == NULL) 59fadff096Smrg fatalerr("strdup() failure in %s()\n", __func__); 60fadff096Smrg *pp++ = p; 61fadff096Smrg if (pp >= ¬dotdot[MAXDIRS]) 62fadff096Smrg fatalerr("out of .. dirs, increase MAXDIRS\n"); 63fadff096Smrg return (TRUE); 64fadff096Smrg } 650eb10989Smrg#endif 66fadff096Smrg return (FALSE); 670eb10989Smrg} 680eb10989Smrg 690eb10989Smrg/* 700eb10989Smrg * Occasionally, pathnames are created that look like .../x/../y 710eb10989Smrg * Any of the 'x/..' sequences within the name can be eliminated. 720eb10989Smrg * (but only if 'x' is not a symbolic link!!) 730eb10989Smrg */ 740eb10989Smrgstatic void 750eb10989Smrgremove_dotdot(char *path) 760eb10989Smrg{ 77fadff096Smrg char *end, *from, *to, **cp; 78fadff096Smrg char *components[MAXFILES], newpath[BUFSIZ]; 79fadff096Smrg boolean component_copied; 80fadff096Smrg 81fadff096Smrg /* 82fadff096Smrg * slice path up into components. 83fadff096Smrg */ 84fadff096Smrg to = newpath; 85fadff096Smrg if (*path == '/') 86fadff096Smrg *to++ = '/'; 87fadff096Smrg *to = '\0'; 88fadff096Smrg cp = components; 89fadff096Smrg for (from = end = path; *end; end++) 90fadff096Smrg if (*end == '/') { 91fadff096Smrg while (*end == '/') 92fadff096Smrg *end++ = '\0'; 93fadff096Smrg if (*from) 94fadff096Smrg *cp++ = from; 95fadff096Smrg from = end; 96fadff096Smrg } 97fadff096Smrg *cp++ = from; 98fadff096Smrg *cp = NULL; 99fadff096Smrg 100fadff096Smrg /* 101fadff096Smrg * Recursively remove all 'x/..' component pairs. 102fadff096Smrg */ 103fadff096Smrg cp = components; 104fadff096Smrg while (*cp) { 105fadff096Smrg if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp + 1)) 106fadff096Smrg && !issymbolic(newpath, *cp)) { 107fadff096Smrg char **fp = cp + 2; 108fadff096Smrg char **tp = cp; 109fadff096Smrg 110fadff096Smrg do 111fadff096Smrg *tp++ = *fp; /* move all the pointers down */ 112fadff096Smrg while (*fp++); 113fadff096Smrg if (cp != components) 114fadff096Smrg cp--; /* go back and check for nested ".." */ 115fadff096Smrg } 116fadff096Smrg else { 117fadff096Smrg cp++; 118fadff096Smrg } 119fadff096Smrg } 120fadff096Smrg /* 121fadff096Smrg * Concatenate the remaining path elements. 122fadff096Smrg */ 123fadff096Smrg cp = components; 124fadff096Smrg component_copied = FALSE; 125fadff096Smrg while (*cp) { 126fadff096Smrg if (component_copied) 127fadff096Smrg *to++ = '/'; 128fadff096Smrg component_copied = TRUE; 129fadff096Smrg for (from = *cp; *from;) 130fadff096Smrg *to++ = *from++; 131fadff096Smrg *to = '\0'; 132fadff096Smrg cp++; 133fadff096Smrg } 134fadff096Smrg *to++ = '\0'; 135fadff096Smrg 136fadff096Smrg /* 137fadff096Smrg * copy the reconstituted path back to our pointer. 138fadff096Smrg */ 139fadff096Smrg strcpy(path, newpath); 1400eb10989Smrg} 1410eb10989Smrg 1420eb10989Smrg/* 1430eb10989Smrg * Add an include file to the list of those included by 'file'. 1440eb10989Smrg */ 1450eb10989Smrgstruct inclist * 146fadff096Smrgnewinclude(const char *newfile, const char *incstring, const char *incpath) 1470eb10989Smrg{ 148fadff096Smrg struct inclist *ip; 149fadff096Smrg 150fadff096Smrg /* 151fadff096Smrg * First, put this file on the global list of include files. 152fadff096Smrg */ 153fadff096Smrg ip = inclistp++; 154fadff096Smrg if (inclistp == inclist + MAXFILES - 1) 155fadff096Smrg fatalerr("out of space: increase MAXFILES\n"); 156fadff096Smrg ip->i_file = strdup(newfile); 157fadff096Smrg if (ip->i_file == NULL) 158fadff096Smrg fatalerr("strdup() failure in %s()\n", __func__); 159fadff096Smrg 160fadff096Smrg if (incstring == NULL) 161fadff096Smrg ip->i_incstring = ip->i_file; 162fadff096Smrg else { 163fadff096Smrg ip->i_incstring = strdup(incstring); 164fadff096Smrg if (ip->i_incstring == NULL) 165fadff096Smrg fatalerr("strdup() failure in %s()\n", __func__); 166fadff096Smrg } 167fadff096Smrg 168fadff096Smrg if (incpath == NULL) { 169fadff096Smrg char r_include[PATHMAX + 1]; 170fadff096Smrg 171fadff096Smrg if (realpath(ip->i_file, r_include) == NULL) 172fadff096Smrg ip->i_realpath = ip->i_file; 173fadff096Smrg else 174fadff096Smrg ip->i_realpath = strdup(r_include); 175fadff096Smrg } 176fadff096Smrg else { 177fadff096Smrg ip->i_realpath = strdup(incpath); 178fadff096Smrg } 179fadff096Smrg if (ip->i_realpath == NULL) 180fadff096Smrg fatalerr("strdup() failure in %s()\n", __func__); 181fadff096Smrg 182fadff096Smrg inclistnext = inclistp; 183fadff096Smrg return (ip); 1840eb10989Smrg} 1850eb10989Smrg 1860eb10989Smrgvoid 1870eb10989Smrgincluded_by(struct inclist *ip, struct inclist *newfile) 1880eb10989Smrg{ 189fadff096Smrg if (ip == NULL) 190fadff096Smrg return; 191fadff096Smrg /* 192fadff096Smrg * Put this include file (newfile) on the list of files included 193fadff096Smrg * by 'file'. If 'file' is NULL, then it is not an include 194fadff096Smrg * file itself (i.e. was probably mentioned on the command line). 195fadff096Smrg * If it is already on the list, don't stick it on again. 196fadff096Smrg */ 197fadff096Smrg if (ip->i_list == NULL) { 198fadff096Smrg ip->i_listlen++; 199fadff096Smrg ip->i_list = mallocarray(ip->i_listlen, sizeof(struct inclist *)); 200fadff096Smrg ip->i_merged = mallocarray(ip->i_listlen, sizeof(boolean)); 201fadff096Smrg } 202fadff096Smrg else { 203fadff096Smrg for (unsigned int i = 0; i < ip->i_listlen; i++) { 204fadff096Smrg if (ip->i_list[i] == newfile) { 205fadff096Smrg size_t l = strlen(newfile->i_file); 206fadff096Smrg if (!(ip->i_flags & INCLUDED_SYM) && 207fadff096Smrg !(l > 2 && 208fadff096Smrg newfile->i_file[l - 1] == 'c' && 209fadff096Smrg newfile->i_file[l - 2] == '.')) { 210fadff096Smrg /* only bitch if ip has */ 211fadff096Smrg /* no #include SYMBOL lines */ 212fadff096Smrg /* and is not a .c file */ 213fadff096Smrg if (warn_multiple) { 214fadff096Smrg warning("%s includes %s more than once!\n", 215fadff096Smrg ip->i_file, newfile->i_file); 216fadff096Smrg warning1("Already have\n"); 217fadff096Smrg for (i = 0; i < ip->i_listlen; i++) 218fadff096Smrg warning1("\t%s\n", ip->i_list[i]->i_file); 219fadff096Smrg } 220fadff096Smrg } 221fadff096Smrg return; 222fadff096Smrg } 223fadff096Smrg } 224fadff096Smrg ip->i_listlen++; 225fadff096Smrg ip->i_list = reallocarray(ip->i_list, ip->i_listlen, 226fadff096Smrg sizeof(struct inclist *)); 227fadff096Smrg ip->i_merged = reallocarray(ip->i_merged, ip->i_listlen, 228fadff096Smrg sizeof(boolean)); 229fadff096Smrg } 230fadff096Smrg if ((ip->i_list == NULL) || (ip->i_merged == NULL)) 231fadff096Smrg fatalerr("malloc()/realloc() failure in %s()\n", __func__); 232fadff096Smrg 233fadff096Smrg ip->i_list[ip->i_listlen - 1] = newfile; 234fadff096Smrg ip->i_merged[ip->i_listlen - 1] = FALSE; 2350eb10989Smrg} 2360eb10989Smrg 2370eb10989Smrgvoid 238fadff096Smrginc_clean(void) 2390eb10989Smrg{ 240fadff096Smrg struct inclist *ip; 2410eb10989Smrg 242fadff096Smrg for (ip = inclist; ip < inclistp; ip++) { 243fadff096Smrg ip->i_flags &= ~MARKED; 244fadff096Smrg } 2450eb10989Smrg} 2460eb10989Smrg 247ee0db89dSmrg/* 248ee0db89dSmrg * Return full path for the "include" file of the given "type", 249ee0db89dSmrg * which may be found relative to the source file "file". 250ee0db89dSmrg */ 251ee0db89dSmrgstatic const char * 252ee0db89dSmrgfind_full_inc_path(const char *file, const char *include, int type) 2530eb10989Smrg{ 254fadff096Smrg static char path[BUFSIZ]; 255fadff096Smrg struct stat st; 256fadff096Smrg 257fadff096Smrg if (inclistnext == inclist) { 258fadff096Smrg /* 259fadff096Smrg * If the path was surrounded by "" or is an absolute path, 260fadff096Smrg * then check the exact path provided. 261fadff096Smrg */ 262fadff096Smrg if ((type == INCLUDEDOT) || 263fadff096Smrg (type == INCLUDENEXTDOT) || 264fadff096Smrg (*include == '/')) { 265fadff096Smrg if (stat(include, &st) == 0 && !S_ISDIR(st.st_mode)) 266fadff096Smrg return include; 267fadff096Smrg if (show_where_not) 268fadff096Smrg warning1("\tnot in %s\n", include); 269fadff096Smrg } 270fadff096Smrg 271fadff096Smrg /* 272fadff096Smrg * If the path was surrounded by "" see if this include file is 273fadff096Smrg * in the directory of the file being parsed. 274fadff096Smrg */ 275fadff096Smrg if ((type == INCLUDEDOT) || (type == INCLUDENEXTDOT)) { 276fadff096Smrg const char *p = strrchr(file, '/'); 277fadff096Smrg 278fadff096Smrg if ((p == NULL) || (p == file)) { 279fadff096Smrg strcpy(path, include); 280fadff096Smrg } 281fadff096Smrg else { 282fadff096Smrg strncpy(path, file, (p - file) + 1); 283fadff096Smrg path[(p - file) + 1] = '\0'; 284fadff096Smrg strcpy(path + (p - file) + 1, include); 285fadff096Smrg } 286fadff096Smrg remove_dotdot(path); 287fadff096Smrg if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) 288fadff096Smrg return path; 289fadff096Smrg if (show_where_not) 290fadff096Smrg warning1("\tnot in %s\n", path); 291fadff096Smrg } 292fadff096Smrg } 293fadff096Smrg 294fadff096Smrg /* 295fadff096Smrg * Check the include directories specified. Standard include dirs 296fadff096Smrg * should be at the end. 297fadff096Smrg */ 298fadff096Smrg if ((type == INCLUDE) || (type == INCLUDEDOT)) 299fadff096Smrg includedirsnext = includedirs; 300fadff096Smrg 301fadff096Smrg for (const char **pp = includedirsnext; *pp; pp++) { 302fadff096Smrg snprintf(path, sizeof(path), "%s/%s", *pp, include); 303fadff096Smrg remove_dotdot(path); 304fadff096Smrg if (stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { 305fadff096Smrg includedirsnext = pp + 1; 306fadff096Smrg return path; 307fadff096Smrg } 308fadff096Smrg if (show_where_not) 309fadff096Smrg warning1("\tnot in %s\n", path); 310fadff096Smrg } 311fadff096Smrg 312fadff096Smrg return NULL; 3130eb10989Smrg} 314ee0db89dSmrg 315ee0db89dSmrgstruct inclist * 316ee0db89dSmrginc_path(const char *file, const char *include, int type) 317ee0db89dSmrg{ 318fadff096Smrg const char *fp; 319fadff096Smrg struct inclist *ip; 320fadff096Smrg char r_include[PATHMAX + 1]; 321fadff096Smrg 322fadff096Smrg /* 323fadff096Smrg * Check all previously found include files for a path that 324fadff096Smrg * has already been expanded. 325fadff096Smrg */ 326fadff096Smrg if ((type == INCLUDE) || (type == INCLUDEDOT)) 327fadff096Smrg inclistnext = inclist; 328fadff096Smrg ip = inclistnext; 329fadff096Smrg 330fadff096Smrg fp = find_full_inc_path(file, include, type); 331fadff096Smrg if (fp == NULL) 332fadff096Smrg return NULL; 333fadff096Smrg if (realpath(fp, r_include) == NULL) 334fadff096Smrg return NULL; 335fadff096Smrg 336fadff096Smrg for (; ip->i_file; ip++) { 337fadff096Smrg if ((strcmp(ip->i_incstring, include) == 0) && 338fadff096Smrg !(ip->i_flags & INCLUDED_SYM)) { 339fadff096Smrg /* 340fadff096Smrg * Same filename but same file ? 341fadff096Smrg */ 342fadff096Smrg if (!strcmp(r_include, ip->i_realpath)) { 343fadff096Smrg inclistnext = ip + 1; 344fadff096Smrg return ip; 345fadff096Smrg } 346fadff096Smrg } 347fadff096Smrg } 348fadff096Smrg 349fadff096Smrg return newinclude(fp, include, r_include); 350ee0db89dSmrg} 351