1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#import <libc.h>
25#import <ctype.h>
26#import <sys/types.h>
27#ifdef __OPENSTEP__
28#define _POSIX_SOURCE
29#endif
30#import <dirent.h>
31#import <pwd.h>
32#import "stuff/bool.h"
33#import "stuff/errors.h"
34#import "stuff/allocate.h"
35#import "stuff/SymLoc.h"
36
37const char *
38symLocForDylib(const char *installName, const char *releaseName,
39enum bool *found_project,
40enum bool disablewarnings,
41enum bool no_error_if_missing)
42{
43	return(LocForDylib(installName, releaseName, "Symbols", found_project,
44			   disablewarnings, no_error_if_missing));
45}
46
47const char *
48dstLocForDylib(const char *installName, const char *releaseName,
49enum bool *found_project,
50enum bool disablewarnings,
51enum bool no_error_if_missing)
52{
53	return(LocForDylib(installName, releaseName, "Roots", found_project,
54			   disablewarnings, no_error_if_missing));
55}
56
57// caller is responsible for freeing the returned string (using free(3))
58const char *
59LocForDylib(const char *installName, const char *releaseName,
60const char *dirname,
61enum bool *found_project,
62enum bool disablewarnings,
63enum bool no_error_if_missing)
64{
65    struct passwd	*passwd		= NULL;
66    struct dirent	*dp		= NULL;
67    FILE		*file 		= NULL;
68    DIR			*dirp		= NULL;
69    DIR			*dirp2		= NULL;
70    char		*line		= NULL;
71    char		*c		= NULL;
72    char		*v		= NULL;
73    char		*viewMap	= NULL;
74    int			 releaseLen	= strlen(releaseName);
75    char		 buf[MAXPATHLEN+MAXNAMLEN+64];
76    char		 readbuf[MAXPATHLEN+64];
77    char		 viewPath[MAXPATHLEN];
78    char		 dylibList[MAXPATHLEN];
79    char		 installNameList[MAXPATHLEN];
80
81    *found_project = FALSE;
82
83    // check parameters
84    if (!installName || !*installName || !releaseName || !*releaseName) {
85        fatal("internal error symLocForDylib(): Null or empty parameter");
86        return NULL;
87    }
88
89    viewMap = getenv("RC_VIEW_MAP_LOCATION");
90    if(!viewMap) {
91        // find ~rc's home directory
92        if (!(passwd = getpwnam("rc"))) {
93            system_error("symLocForDylib(): getpwnam(\"rc\") returns NULL");
94            return NULL;
95        }
96        strcpy(buf, passwd->pw_dir);
97        // open release-to-view file
98        strcat(buf, "/Data/release_to_view.map");
99    } else {
100        strcpy(buf, viewMap);
101    }
102    if (!(file = fopen(buf, "r"))) {
103        system_error("symLocForDylib(): Can't fopen %s", buf);
104        return NULL;
105    }
106
107    // parse release-to-view file
108    *viewPath = '\0';
109    while ((line = fgets(buf, sizeof(buf), file))) {
110        if (!strncmp(line, releaseName, releaseLen) && isspace(line[releaseLen])) {
111            c = &line[releaseLen] + 1;
112            while (isspace(*c)) c++;
113            for (v = &viewPath[0]; !isspace(*c); c++, v++) *v = *c;
114            *v = '\0';
115            break;
116        }
117    }
118    if(fclose(file) != 0)
119	system_error("fclose() failed");
120    if (!*viewPath) {
121        error("symLocForDylib(): Can't locate view path for release %s",
122	      releaseName);
123        return NULL;
124    }
125
126    // open DylibProjects directory
127    strcpy(dylibList, viewPath);
128    c = &dylibList[strlen(dylibList)];
129    strcpy(c, "/.BuildData/DylibProjects");
130    if (!(dirp = opendir(dylibList))) {
131        system_error("symLocForDylib(): Can't opendir %s", buf);
132        return NULL;
133    }
134
135    // open the InstallNames directory
136    strcpy(installNameList, viewPath);
137    c = &installNameList[strlen(installNameList)];
138    strcpy(c, "/.BuildData/InstallNames");
139    if (!(dirp2 = opendir(installNameList))) {
140        system_error("symLocForDylib(): Can't opendir %s", buf);
141        return NULL;
142    }
143    c = NULL;
144
145    // read DylibProjects entries
146    *buf = '\0';
147    v = &dylibList[strlen(dylibList)];
148    *v = '/';
149    v++;
150    while ((dp = readdir(dirp))) {
151
152        // skip "." and ".."
153        if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
154
155        // open file
156        strcpy(v, dp->d_name);
157        if (!(file = fopen(dylibList, "r"))) {
158            system_error("symLocForDylib(): Can't fopen %s", dylibList);
159	    if(closedir(dirp) != 0)
160		system_error("closedir() failed");
161            return NULL;
162        }
163
164        // parse file
165        while ((line = fgets(readbuf, sizeof(readbuf), file))) {
166            if (!*line || *line == '(' || *line == ')') continue;
167            while (*line == ' ') line++;
168            if (*line != '"') {
169                warning("symLocForDylib(): %s contains malformed line",
170			dp->d_name);
171                continue;
172            }
173            line++;
174            for (c = &buf[0]; *line && *line != '"'; *c++ = *line++);
175            if (*line != '"') {
176                warning("symLocForDylib(): %s contains malformed line",
177		        dp->d_name);
178                continue;
179            }
180            *c = '\0';
181            if (!strcmp(buf, installName)) {
182                c = allocate(strlen(viewPath) + strlen(releaseName) +
183			     strlen(dirname) + strlen(dp->d_name) + 32);
184                sprintf(c, "%s/Updates/Built%s/%s/%s", viewPath, releaseName,
185			dirname, dp->d_name);
186                break;
187            } else {
188                c = NULL;
189            }
190        }
191        if(fclose(file) != 0)
192	    system_error("fclose() failed");
193        if (c) break;
194    }
195    if(closedir(dirp) != 0)
196	system_error("closedir() failed");
197
198    if(!c) {
199         // read InstallNames entries
200        *buf = '\0';
201        v = &installNameList[strlen(installNameList)];
202        *v = '/';
203        v++;
204
205        while ((dp = readdir(dirp2))) {
206
207            // skip "." and ".."
208            if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
209
210            // open file
211            strcpy(v, dp->d_name);
212            if (!(file = fopen(installNameList, "r"))) {
213                system_error("symLocForDylib(): Can't fopen %s", installNameList);
214                if(closedir(dirp) != 0)
215                    system_error("closedir() failed");
216                return NULL;
217            }
218
219            // parse file
220            while ((line = fgets(readbuf, sizeof(readbuf), file))) {
221                if (!*line || *line == '(' || *line == ')') continue;
222                while (*line == ' ') line++;
223                if (*line != '"') {
224                    warning("symLocForDylib(): %s contains malformed line",
225                        dp->d_name);
226                    continue;
227                }
228                line++;
229                for (c = &buf[0]; *line && *line != '"'; *c++ = *line++);
230                if (*line != '"') {
231                    warning("symLocForDylib(): %s contains malformed line",
232                        dp->d_name);
233                    continue;
234                }
235                *c = '\0';
236                if (!strcmp(buf, installName)) {
237                    c = allocate(strlen(viewPath) + strlen(releaseName) +
238                             strlen(dirname) + strlen(dp->d_name) + 32);
239                    sprintf(c, "%s/Updates/Built%s/%s/%s", viewPath, releaseName,
240                        dirname, dp->d_name);
241                    break;
242                } else {
243                    c = NULL;
244                }
245            }
246            if(fclose(file) != 0)
247                system_error("fclose() failed");
248            if (c) break;
249        }
250   }
251
252    // process return value
253    if (!c) {
254	if(no_error_if_missing == FALSE)
255	    error("Can't find project that builds %s", installName);
256        return NULL;
257    } else {
258	*found_project = TRUE;
259        return c;
260    }
261}
262#endif /* !defined(RLD) */
263