cs_platforms.cpp 10.3 KB
Newer Older
1
// This file is part of BOINC.
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2008 University of California
4
//
5
6
7
8
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
9
//
10
// BOINC is distributed in the hope that it will be useful,
11
12
13
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
15
16
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17
18
19
20
21
22
23
24

// Determine which platforms are supported and provide a way
//   of exposing that information to the rest of the client.

#include "cpp.h"

#ifdef _WIN32
#include "boinc_win.h"
25
26
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
27
#else
28
#include "config.h"
Eric J. Korpela's avatar
   
Eric J. Korpela committed
29
30
#include <cstdio>
#include <cstdlib>
31
#include <signal.h>
32
#if HAVE_UNISTD_H
33
34
#include <unistd.h>
#endif
35
#if HAVE_SYS_TYPES_H
36
37
#include <sys/types.h>
#endif
38
#if HAVE_SYS_WAIT_H
39
40
#include <sys/wait.h>
#endif
41
42
#endif

43
44
45
46
#if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
#include <sys/sysctl.h>
#endif

47
#include "error_numbers.h"
48
#include "filesys.h"
49
#include "str_util.h"
50
#include "str_replace.h"
51
52
#include "util.h"

53
54
55
56
57
#include "client_types.h"
#include "client_state.h"
#include "log_flags.h"
#include "project.h"

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// return the primary platform id.
//
const char* CLIENT_STATE::get_primary_platform() {
    return platforms[0].name.c_str();
}


// add a platform to the vector.
//
void CLIENT_STATE::add_platform(const char* platform) {
    PLATFORM pp;
    pp.name = platform;
    platforms.push_back(pp);
}


// determine the list of supported platforms.
//
void CLIENT_STATE::detect_platforms() {

#if defined(_WIN32) && !defined(__CYGWIN32__)
#if defined(_WIN64) && defined(_M_X64)
    add_platform("windows_x86_64");
    add_platform("windows_intelx86");
#else
83
84
85
86
87
88
89
90
91
92
93
94
95
    // see if 32-bit client is running on 64-bit machine
    //
    BOOL bIsWow64 = FALSE;
    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process"
    );
    if (fnIsWow64Process) {
        if (fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {
            if (bIsWow64) {
                add_platform("windows_x86_64");
            }
        }
    }
96
97
98
99
    add_platform("windows_intelx86");
#endif

#elif defined(__APPLE__)
Eric J. Korpela's avatar
   
Eric J. Korpela committed
100

101
#if defined(__i386__) || defined(__x86_64__)
102
103
104
105
106
    int response = 0;
    int retval = 0;
    size_t len = sizeof(response);

    retval = sysctlbyname("hw.optional.x86_64", &response, &len, NULL, 0);
107
    if (!retval) {
108
109
110
        add_platform("x86_64-apple-darwin");
    }

111
    // Supported on both Mac Intel architectures
112
    add_platform("i686-apple-darwin");
113
#else
114
115
116
    // We no longer request PowerPC applications on Intel Macs
    // because all projects supporting Macs should have Intel
    // applications by now, and PowerPC emulation ("Rosetta")
117
    // is not always supported in newer versions of OS X.
118
    add_platform("powerpc-apple-darwin");
119
#endif
Eric J. Korpela's avatar
   
Eric J. Korpela committed
120

121
122
123
124
125
126
127
128
129
130
131
#elif defined(__linux__) && ( defined(__i386__) || defined(__x86_64__) )
    // Let's try to support both 32 and 64 bit applications in one client
    // regardless of whether it is a 32 or 64 bit client
    const char *uname[]={"/bin/uname","/usr/bin/uname",0};
    int eno=0, support64=0, support32=0;
    FILE *f;
    char cmdline[256];
    cmdline[0]=0;

    // find the 'uname' executable
    do {
132
        if (boinc_file_exists(uname[eno])) break;
133
    } while (uname[++eno] != 0);
134

135
136
137
138
139
140
    // run it and check the kernel machine architecture.
    if ( uname[eno] != 0 ) {
        strlcpy(cmdline,uname[eno],256);
        strlcat(cmdline," -m",256);
        if ((f=popen(cmdline,"r"))) {
            while (!std::feof(f)) {
141
                if (!fgets(cmdline,256,f)) break;
Rom Walton's avatar
Rom Walton committed
142
143
144
145
                if (strstr(cmdline,"x86_64")) support64=1;
            }
            pclose(f);
        }
146

147
        if (!support64) {
148
149
150
151
152
153
154
            // we're running on a 32 bit kernel, so we will assume
            // we are i686-pc-linux-gnu only.
            support32=1;
        } else {
            // we're running on a 64 bit kernel.
            // Now comes the hard part.  How to tell whether we can run
            // 32-bit binaries.
155
#if defined(__i386__) && !defined(__x86_64__)
156
            // If we're a 32 bit binary, then we obviously can.
157
            support32=1;
158
#else
159
            // If we're a 64 bit binary, the check is a bit harder.
160
161
162
163
164
165
            // We'll use the file command to check installation of
            // 32 bit libraries or executables.
            const char *file[]={"/usr/bin/file","/bin/file",0};
            const char *libdir[]={"/lib","/lib32","/lib/32","/usr/lib","/usr/lib32","/usr/lib/32"};
            const int nlibdirs=sizeof(libdir)/sizeof(char *);

166
167
168
            // find 'file'
            eno=0;
            do {
169
                if (boinc_file_exists(file[eno])) break;
170
            } while (file[++eno] != 0);
171

172
            // now try to find a 32-bit C library.
173
174
175
176
177
            if (file[eno] != 0) {
                int i;
                for (i=0; i < nlibdirs; i++) {
                    struct dirent *entry;
                    DIR *a = opendir(libdir[i]);
178
                    // if dir doesn't exist, do the next one
179
180
181
182
183
184
185
186
187
188
189
                    if (a == 0) continue;
                    // dir exists. read each entry until you find a 32bit lib
                    while ((support32 == 0) && ((entry=readdir(a)) != 0)) {
                        strlcpy(cmdline, file[eno], 256);
                        strlcat(cmdline, " -L ", 256);
                        strlcat(cmdline, libdir[i], 256);
                        strlcat(cmdline, "/", 256);
                        strlcat(cmdline, entry->d_name, 256);
                        f = popen(cmdline, "r");
                        if (f) {
                            while (!std::feof(f)) {
190
                                if (!fgets(cmdline,256,f)) break;
191
192
                                // If the library is 32-bit ELF, then we're
                                // golden.
193
194
195
196
                                if (strstr(cmdline, "ELF") && strstr(cmdline, "32-bit")) support32=1;
                            }
                            pclose(f);
                        }
197
198
199
                    }
                    closedir(a);
                    if (support32) break;
200
                }
201
            }
202
#endif
203
204
        }
    }
205
206

    if (support64) {
207
        add_platform("x86_64-pc-linux-gnu");
208
209
    }
    if (support32) {
210
        add_platform("i686-pc-linux-gnu");
211
212
213
214
    }

    if (!(support64 || support32)) {
        // Something went wrong. Assume HOSTTYPE and HOSTTYPEALT
215
        // are correct
216
217
218
219
220
221
        add_platform(HOSTTYPE);
#ifdef HOSTTYPEALT
        add_platform(HOSTTYPEALT);
#endif
    }

222
#elif defined(sun)
Eric J. Korpela's avatar
   
Eric J. Korpela committed
223
224
    // Check if we can run 64-bit binaries...
    // this assumes there isn't a 64-bit only solaris.  (Every 64-bit solaris can run 32 bit binaries)
225
226

#if defined(__sparc) || defined(sparc)
Eric J. Korpela's avatar
   
Eric J. Korpela committed
227
228
229
230
231
232
233
234
235
236
237
238
    char *exe64=const_cast<char *>("/usr/bin/sparcv9/ls");
    char *platform64=const_cast<char *>("sparc64-sun-solaris");
    char *platform32=const_cast<char *>("sparc-sun-solaris");
#elif defined(__i386) || defined(i386) || defined(__amd64) || defined(__x86_64__)
    char *exe64=const_cast<char *>("/usr/bin/amd64/ls");
    char *platform64=const_cast<char *>("x86_64-pc-solaris");
    char *platform32=const_cast<char *>("i686-pc-solaris");
#else
#define UNKNOWN_SOLARIS_PROCESSOR
#endif

#ifndef UNKNOWN_SOLARIS_PROCESSOR
239
    FILE *f=fopen(exe64,"r");
240
241
242
    char *argv[3];
    pid_t pid;
    int rv=0;
Eric J. Korpela's avatar
   
Eric J. Korpela committed
243
    argv[0]=exe64;
244
245
246
    argv[1]=argv[0];
    argv[2]=NULL;
    if (f) {
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
        fclose(f);
        if (0==(pid=fork())) {
            // we are in child process
            freopen("/dev/null","a",stderr);
            freopen("/dev/null","a",stdout);
            rv=execv(argv[0],argv);
            exit(rv);
        } else {
            // we are in the parent process.
            time_t start=time(0);
            int done;
            // wait 5 seconds or until the process exits.
            do {
                done=waitpid(pid,&rv,WNOHANG);
                sleep(1);
            } while (!done && ((time(0)-start)<5));
263
            // if we timed out, kill the process
264
            if ((time(0)-start)>=5) {
265
                kill(pid,SIGKILL);
266
267
268
269
                done=-1;
            }
            // if we exited with success add the 64 bit platform
            if ((done == pid) && (rv == 0)) {
Eric J. Korpela's avatar
   
Eric J. Korpela committed
270
               add_platform(platform64);
271
272
            }
        }
273
    }
Eric J. Korpela's avatar
   
Eric J. Korpela committed
274
    add_platform(platform32);
275
    // the following platform is obsolete, but we'll add it anyway.
276
#if defined(__sparc) || defined(sparc)
277
    add_platform("sparc-sun-solaris2.7");
Eric J. Korpela's avatar
   
Eric J. Korpela committed
278
279
280
#endif
#else  // !defined(UNKNOWN_SOLARIS_PROCESSOR)

281
282
283
284
285
    add_platform(HOSTTYPE);
#ifdef HOSTTYPEALT
    add_platform(HOSTTYPEALT);
#endif

Eric J. Korpela's avatar
   
Eric J. Korpela committed
286
287
#endif  // !defined(UNKNOWN_SOLARIS_PROCESSOR)

288
#else
289

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
    // Any other platform, fall back to the previous method
    add_platform(HOSTTYPE);
#ifdef HOSTTYPEALT
    add_platform(HOSTTYPEALT);
#endif

#endif

    if (config.no_alt_platform) {
        PLATFORM p = platforms[0];
        platforms.clear();
        platforms.push_back(p);
    }

    // add platforms listed in cc_config.xml AFTER the above.
    //
    for (unsigned int i=0; i<config.alt_platforms.size(); i++) {
        add_platform(config.alt_platforms[i].c_str());
    }
}


// write XML list of supported platforms
//
void CLIENT_STATE::write_platforms(PROJECT* p, MIOFILE& mf) {
315
316
317
    if (p->anonymous_platform) {
        mf.printf("    <platform_name>anonymous</platform_name>\n");
    } else {
318
        mf.printf(
319
            "    <platform_name>%s</platform_name>\n", get_primary_platform()
320
        );
321
322
323
324
325
326
327
328
329
        for (unsigned int i=1; i<platforms.size(); i++) {
            PLATFORM& platform = platforms[i];
            mf.printf(
                "    <alt_platform>\n"
                "        <name>%s</name>\n"
                "    </alt_platform>\n",
                platform.name.c_str()
            );
        }
330
331
332
333
334
335
336
337
338
339
340
341
    }
}

bool CLIENT_STATE::is_supported_platform(const char* p) {
    for (unsigned int i=0; i<platforms.size(); i++) {
        PLATFORM& platform = platforms[i];
        if (!strcmp(p, platform.name.c_str())) {
            return true;
        }
    }
    return false;
}