1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // 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 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #if   defined(_WIN32) && !defined(__STDWX_H__)
19 #include "boinc_win.h"
20 #elif defined(_WIN32) && defined(__STDWX_H__)
21 #include "stdwx.h"
22 #else
23 #include "config.h"
24 #include <cstring>
25 #include <string>
26 #endif
27 
28 #include "error_numbers.h"
29 #include "filesys.h"
30 #include "miofile.h"
31 #include "parse.h"
32 #include "str_replace.h"
33 #include "str_util.h"
34 #include "url.h"
35 #include "util.h"
36 
37 #include "app_ipc.h"
38 
39 using std::string;
40 
APP_INIT_DATA()41 APP_INIT_DATA::APP_INIT_DATA() {
42     clear();
43 }
44 
~APP_INIT_DATA()45 APP_INIT_DATA::~APP_INIT_DATA() {
46     if (project_preferences) {
47         free(project_preferences);
48         project_preferences=0;      // paranoia
49     }
50 }
51 
APP_INIT_DATA(const APP_INIT_DATA & a)52 APP_INIT_DATA::APP_INIT_DATA(const APP_INIT_DATA& a) {
53     copy(a);
54 }
55 
operator =(const APP_INIT_DATA & a)56 APP_INIT_DATA &APP_INIT_DATA::operator=(const APP_INIT_DATA& a) {
57     if (this != &a) {
58       copy(a);
59     }
60     return *this;
61 }
62 
copy(const APP_INIT_DATA & a)63 void APP_INIT_DATA::copy(const APP_INIT_DATA& a) {
64     safe_strcpy(app_name, a.app_name);
65     safe_strcpy(symstore, a.symstore);
66     safe_strcpy(acct_mgr_url, a.acct_mgr_url);
67     safe_strcpy(user_name, a.user_name);
68     safe_strcpy(team_name, a.team_name);
69     safe_strcpy(project_dir, a.project_dir);
70     safe_strcpy(boinc_dir, a.boinc_dir);
71     safe_strcpy(wu_name, a.wu_name);
72     safe_strcpy(result_name, a.result_name);
73     safe_strcpy(authenticator, a.authenticator);
74     memcpy(&shmem_seg_name, &a.shmem_seg_name, sizeof(SHMEM_SEG_NAME));
75     safe_strcpy(gpu_type, a.gpu_type);
76 
77     // use assignment for the rest, especially the classes
78     // (so that the overloaded operators are called!)
79     major_version               = a.major_version;
80     minor_version               = a.minor_version;
81     release                     = a.release;
82     app_version                 = a.app_version;
83     userid                      = a.userid;
84     teamid                      = a.teamid;
85     hostid                      = a.hostid;
86     slot                        = a.slot;
87     client_pid                  = a.client_pid;
88     user_total_credit           = a.user_total_credit;
89     user_expavg_credit          = a.user_expavg_credit;
90     host_total_credit           = a.host_total_credit;
91     host_expavg_credit          = a.host_expavg_credit;
92     resource_share_fraction     = a.resource_share_fraction;
93     host_info                   = a.host_info;
94     proxy_info                  = a.proxy_info;
95     global_prefs                = a.global_prefs;
96     starting_elapsed_time       = a.starting_elapsed_time;
97     using_sandbox               = a.using_sandbox;
98     vm_extensions_disabled      = a.vm_extensions_disabled;
99     rsc_fpops_est               = a.rsc_fpops_est;
100     rsc_fpops_bound             = a.rsc_fpops_bound;
101     rsc_memory_bound            = a.rsc_memory_bound;
102     rsc_disk_bound              = a.rsc_disk_bound;
103     computation_deadline        = a.computation_deadline;
104     fraction_done_start         = a.fraction_done_start;
105     fraction_done_end           = a.fraction_done_end;
106     gpu_device_num              = a.gpu_device_num;
107     gpu_opencl_dev_index        = a.gpu_opencl_dev_index;
108     gpu_usage                   = a.gpu_usage;
109     ncpus                       = a.ncpus;
110     checkpoint_period           = a.checkpoint_period;
111     wu_cpu_time                 = a.wu_cpu_time;
112     if (a.project_preferences) {
113         project_preferences = strdup(a.project_preferences);
114     } else {
115         project_preferences = NULL;
116     }
117     vbox_window                 = a.vbox_window;
118     app_files                   = a.app_files;
119 }
120 
write_init_data_file(FILE * f,APP_INIT_DATA & ai)121 int write_init_data_file(FILE* f, APP_INIT_DATA& ai) {
122     char buf[2048];
123     fprintf(f,
124         "<app_init_data>\n"
125         "<major_version>%d</major_version>\n"
126         "<minor_version>%d</minor_version>\n"
127         "<release>%d</release>\n"
128         "<app_version>%d</app_version>\n"
129         "<userid>%d</userid>\n"
130         "<teamid>%d</teamid>\n"
131         "<hostid>%d</hostid>\n",
132         ai.major_version,
133         ai.minor_version,
134         ai.release,
135         ai.app_version,
136         ai.userid,
137         ai.teamid,
138         ai.hostid
139     );
140     if (strlen(ai.app_name)) {
141         fprintf(f, "<app_name>%s</app_name>\n", ai.app_name);
142     }
143     if (strlen(ai.symstore)) {
144         fprintf(f, "<symstore>%s</symstore>\n", ai.symstore);
145     }
146     if (strlen(ai.acct_mgr_url)) {
147         fprintf(f, "<acct_mgr_url>%s</acct_mgr_url>\n", ai.acct_mgr_url);
148     }
149     if (ai.project_preferences && strlen(ai.project_preferences)) {
150         fprintf(f, "<project_preferences>\n%s</project_preferences>\n", ai.project_preferences);
151     }
152     if (strlen(ai.team_name)) {
153         xml_escape(ai.team_name, buf, sizeof(buf));
154         fprintf(f, "<team_name>%s</team_name>\n", buf);
155     }
156     if (strlen(ai.user_name)) {
157         xml_escape(ai.user_name, buf, sizeof(buf));
158         fprintf(f, "<user_name>%s</user_name>\n", buf);
159     }
160     if (strlen(ai.project_dir)) {
161         fprintf(f, "<project_dir>%s</project_dir>\n", ai.project_dir);
162     }
163     if (strlen(ai.boinc_dir)) {
164         fprintf(f, "<boinc_dir>%s</boinc_dir>\n", ai.boinc_dir);
165     }
166     if (strlen(ai.authenticator)) {
167         fprintf(f, "<authenticator>%s</authenticator>\n", ai.authenticator);
168     }
169     if (strlen(ai.wu_name)) {
170         fprintf(f, "<wu_name>%s</wu_name>\n", ai.wu_name);
171     }
172     if (strlen(ai.result_name)) {
173         fprintf(f, "<result_name>%s</result_name>\n", ai.result_name);
174     }
175 #ifdef _WIN32
176     if (strlen(ai.shmem_seg_name)) {
177         fprintf(f, "<comm_obj_name>%s</comm_obj_name>\n", ai.shmem_seg_name);
178     }
179 #else
180     fprintf(f, "<shm_key>%d</shm_key>\n", ai.shmem_seg_name);
181 #endif
182     fprintf(f,
183         "<slot>%d</slot>\n"
184         "<client_pid>%d</client_pid>\n"
185         "<wu_cpu_time>%f</wu_cpu_time>\n"
186         "<starting_elapsed_time>%f</starting_elapsed_time>\n"
187         "<using_sandbox>%d</using_sandbox>\n"
188         "<vm_extensions_disabled>%d</vm_extensions_disabled>\n"
189         "<user_total_credit>%f</user_total_credit>\n"
190         "<user_expavg_credit>%f</user_expavg_credit>\n"
191         "<host_total_credit>%f</host_total_credit>\n"
192         "<host_expavg_credit>%f</host_expavg_credit>\n"
193         "<resource_share_fraction>%f</resource_share_fraction>\n"
194         "<checkpoint_period>%f</checkpoint_period>\n"
195         "<fraction_done_start>%f</fraction_done_start>\n"
196         "<fraction_done_end>%f</fraction_done_end>\n"
197         "<gpu_type>%s</gpu_type>\n"
198         "<gpu_device_num>%d</gpu_device_num>\n"
199         "<gpu_opencl_dev_index>%d</gpu_opencl_dev_index>\n"
200         "<gpu_usage>%f</gpu_usage>\n"
201         "<ncpus>%f</ncpus>\n"
202         "<rsc_fpops_est>%f</rsc_fpops_est>\n"
203         "<rsc_fpops_bound>%f</rsc_fpops_bound>\n"
204         "<rsc_memory_bound>%f</rsc_memory_bound>\n"
205         "<rsc_disk_bound>%f</rsc_disk_bound>\n"
206         "<computation_deadline>%f</computation_deadline>\n"
207         "<vbox_window>%d</vbox_window>\n",
208         ai.slot,
209         ai.client_pid,
210         ai.wu_cpu_time,
211         ai.starting_elapsed_time,
212         ai.using_sandbox?1:0,
213         ai.vm_extensions_disabled?1:0,
214         ai.user_total_credit,
215         ai.user_expavg_credit,
216         ai.host_total_credit,
217         ai.host_expavg_credit,
218         ai.resource_share_fraction,
219         ai.checkpoint_period,
220         ai.fraction_done_start,
221         ai.fraction_done_end,
222         ai.gpu_type,
223         ai.gpu_device_num,
224         ai.gpu_opencl_dev_index,
225         ai.gpu_usage,
226         ai.ncpus,
227         ai.rsc_fpops_est,
228         ai.rsc_fpops_bound,
229         ai.rsc_memory_bound,
230         ai.rsc_disk_bound,
231         ai.computation_deadline,
232         ai.vbox_window
233     );
234     MIOFILE mf;
235     mf.init_file(f);
236     ai.host_info.write(mf, true, true);
237     ai.proxy_info.write(mf);
238     ai.global_prefs.write(mf);
239     for (unsigned int i=0; i<ai.app_files.size(); i++) {
240         fprintf(f, "<app_file>%s</app_file>\n", ai.app_files[i].c_str());
241     }
242     fprintf(f, "</app_init_data>\n");
243     return 0;
244 }
245 
clear()246 void APP_INIT_DATA::clear() {
247     major_version = 0;
248     minor_version = 0;
249     release = 0;
250     app_version = 0;
251     safe_strcpy(app_name, "");
252     safe_strcpy(symstore, "");
253     safe_strcpy(acct_mgr_url, "");
254     project_preferences = NULL;
255     userid = 0;
256     teamid = 0;
257     hostid = 0;
258     safe_strcpy(user_name, "");
259     safe_strcpy(team_name, "");
260     safe_strcpy(project_dir, "");
261     safe_strcpy(boinc_dir, "");
262     safe_strcpy(wu_name, "");
263     safe_strcpy(result_name, "");
264     safe_strcpy(authenticator, "");
265     slot = 0;
266     client_pid = 0;
267     user_total_credit = 0;
268     user_expavg_credit = 0;
269     host_total_credit = 0;
270     host_expavg_credit = 0;
271     resource_share_fraction = 0;
272     host_info.clear_host_info();
273     proxy_info.clear();
274     global_prefs.defaults();
275     starting_elapsed_time = 0;
276     using_sandbox = false;
277     vm_extensions_disabled = false;
278     rsc_fpops_est = 0;
279     rsc_fpops_bound = 0;
280     rsc_memory_bound = 0;
281     rsc_disk_bound = 0;
282     computation_deadline = 0;
283     fraction_done_start = 0;
284     fraction_done_end = 0;
285     checkpoint_period = 0;
286     // gpu_type is an empty string for client versions before 6.13.3 without this
287     // field or (on newer clients) if BOINC did not assign an OpenCL GPU to task.
288     safe_strcpy(gpu_type, "");
289     // gpu_device_num < 0 for client versions before 6.13.3 without this field
290     // or (on newer clients) if BOINC did not assign an OpenCL GPU to task.
291     gpu_device_num = -1;
292     // gpu_opencl_dev_index < 0 for client versions before 7.0.12 without this
293     // field or (on newer clients) if BOINC did not assign any GPU to task.
294     gpu_opencl_dev_index = -1;
295     gpu_usage = 0;
296     ncpus = 0;
297     memset(&shmem_seg_name, 0, sizeof(shmem_seg_name));
298     wu_cpu_time = 0;
299     vbox_window = false;
300 }
301 
parse_init_data_file(FILE * f,APP_INIT_DATA & ai)302 int parse_init_data_file(FILE* f, APP_INIT_DATA& ai) {
303     int retval;
304     bool flag;
305 
306     MIOFILE mf;
307     mf.init_file(f);
308     XML_PARSER xp(&mf);
309 
310     if (!xp.parse_start("app_init_data")) {
311         fprintf(stderr, "%s: no start tag in app init data\n",
312             time_to_string(dtime())
313         );
314         return ERR_XML_PARSE;
315     }
316 
317     if (ai.project_preferences) {
318         free(ai.project_preferences);
319         ai.project_preferences = 0;
320     }
321     ai.clear();
322     ai.fraction_done_start = 0;
323     ai.fraction_done_end = 1;
324 
325     while (!xp.get_tag()) {
326         if (!xp.is_tag) {
327             fprintf(stderr,
328                 "%s: unexpected text in init_data.xml: %s\n",
329                 time_to_string(dtime()), xp.parsed_tag
330             );
331             continue;
332         }
333         if (xp.match_tag("/app_init_data")) return 0;
334         if (xp.match_tag("project_preferences")) {
335             retval = dup_element(f, "project_preferences", &ai.project_preferences);
336             if (retval) return retval;
337             continue;
338         }
339         if (xp.match_tag("global_preferences")) {
340             GLOBAL_PREFS_MASK mask;
341             retval = ai.global_prefs.parse(xp, "", flag, mask);
342             if (retval) return retval;
343             continue;
344         }
345         if (xp.match_tag("host_info")) {
346             ai.host_info.parse(xp);
347             continue;
348         }
349         if (xp.match_tag("proxy_info")) {
350             ai.proxy_info.parse(xp);
351             continue;
352         }
353         if (xp.parse_int("major_version", ai.major_version)) continue;
354         if (xp.parse_int("minor_version", ai.minor_version)) continue;
355         if (xp.parse_int("release", ai.release)) continue;
356         if (xp.parse_int("app_version", ai.app_version)) continue;
357         if (xp.parse_str("app_name", ai.app_name, sizeof(ai.app_name))) continue;
358         if (xp.parse_str("symstore", ai.symstore, sizeof(ai.symstore))) continue;
359         if (xp.parse_str("acct_mgr_url", ai.acct_mgr_url, sizeof(ai.acct_mgr_url))) continue;
360         if (xp.parse_int("userid", ai.userid)) continue;
361         if (xp.parse_int("teamid", ai.teamid)) continue;
362         if (xp.parse_int("hostid", ai.hostid)) continue;
363         if (xp.parse_str("user_name", ai.user_name, sizeof(ai.user_name))) {
364             xml_unescape(ai.user_name);
365             continue;
366         }
367         if (xp.parse_str("team_name", ai.team_name, sizeof(ai.team_name))) {
368             xml_unescape(ai.team_name);
369             continue;
370         }
371         if (xp.parse_str("project_dir", ai.project_dir, sizeof(ai.project_dir))) continue;
372         if (xp.parse_str("boinc_dir", ai.boinc_dir, sizeof(ai.boinc_dir))) continue;
373         if (xp.parse_str("authenticator", ai.authenticator, sizeof(ai.authenticator))) continue;
374         if (xp.parse_str("wu_name", ai.wu_name, sizeof(ai.wu_name))) continue;
375         if (xp.parse_str("result_name", ai.result_name, sizeof(ai.result_name))) continue;
376 #ifdef _WIN32
377         if (xp.parse_str("comm_obj_name", ai.shmem_seg_name, sizeof(ai.shmem_seg_name))) continue;
378 #else
379         if (xp.parse_int("shm_key", ai.shmem_seg_name)) continue;
380 #endif
381         if (xp.parse_int("slot", ai.slot)) continue;
382         if (xp.parse_int("client_pid", ai.client_pid)) continue;
383         if (xp.parse_double("user_total_credit", ai.user_total_credit)) continue;
384         if (xp.parse_double("user_expavg_credit", ai.user_expavg_credit)) continue;
385         if (xp.parse_double("host_total_credit", ai.host_total_credit)) continue;
386         if (xp.parse_double("host_expavg_credit", ai.host_expavg_credit)) continue;
387         if (xp.parse_double("resource_share_fraction", ai.resource_share_fraction)) continue;
388         if (xp.parse_double("rsc_fpops_est", ai.rsc_fpops_est)) continue;
389         if (xp.parse_double("rsc_fpops_bound", ai.rsc_fpops_bound)) continue;
390         if (xp.parse_double("rsc_memory_bound", ai.rsc_memory_bound)) continue;
391         if (xp.parse_double("rsc_disk_bound", ai.rsc_disk_bound)) continue;
392         if (xp.parse_double("computation_deadline", ai.computation_deadline)) continue;
393         if (xp.parse_double("wu_cpu_time", ai.wu_cpu_time)) continue;
394         if (xp.parse_double("starting_elapsed_time", ai.starting_elapsed_time)) continue;
395         if (xp.parse_bool("using_sandbox", ai.using_sandbox)) continue;
396         if (xp.parse_bool("vm_extensions_disabled", ai.vm_extensions_disabled)) continue;
397         if (xp.parse_double("checkpoint_period", ai.checkpoint_period)) continue;
398         if (xp.parse_str("gpu_type", ai.gpu_type, sizeof(ai.gpu_type))) continue;
399         if (xp.parse_int("gpu_device_num", ai.gpu_device_num)) continue;
400         if (xp.parse_int("gpu_opencl_dev_index", ai.gpu_opencl_dev_index)) continue;
401         if (xp.parse_double("gpu_usage", ai.gpu_usage)) continue;
402         if (xp.parse_double("ncpus", ai.ncpus)) continue;
403         if (xp.parse_double("fraction_done_start", ai.fraction_done_start)) continue;
404         if (xp.parse_double("fraction_done_end", ai.fraction_done_end)) continue;
405         if (xp.parse_bool("vbox_window", ai.vbox_window)) continue;
406         xp.skip_unexpected(false, "parse_init_data_file");
407     }
408     fprintf(stderr, "%s: parse_init_data_file: no end tag\n",
409         time_to_string(dtime())
410     );
411     return ERR_XML_PARSE;
412 }
413 
APP_CLIENT_SHM()414 APP_CLIENT_SHM::APP_CLIENT_SHM() : shm(NULL) {
415 }
416 
get_msg(char * msg)417 bool MSG_CHANNEL::get_msg(char *msg) {
418     if (!buf[0]) return false;
419     strlcpy(msg, buf+1, MSG_CHANNEL_SIZE-1);
420     buf[0] = 0;
421     return true;
422 }
423 
send_msg(const char * msg)424 bool MSG_CHANNEL::send_msg(const char *msg) {
425     if (has_msg()) return false;
426     strlcpy(buf+1, msg, MSG_CHANNEL_SIZE-1);
427     buf[0] = 1;
428     return true;
429 }
430 
send_msg_overwrite(const char * msg)431 void MSG_CHANNEL::send_msg_overwrite(const char* msg) {
432     strlcpy(buf+1, msg, MSG_CHANNEL_SIZE-1);
433     buf[0] = 1;
434 }
435 
reset_msgs()436 void APP_CLIENT_SHM::reset_msgs() {
437     memset(shm, 0, sizeof(SHARED_MEM));
438 }
439 
440 // Resolve virtual name (in slot dir) to physical path (in project dir).
441 // Cases:
442 // - Windows and pre-6.12 Unix:
443 //   virtual name refers to a "soft link" (XML file acting as symbolic link)
444 // - 6.12+ Unix:
445 //   virtual name is a symbolic link
446 // - Standalone: physical path is same as virtual name
447 //
boinc_resolve_filename(const char * virtual_name,char * physical_name,int len)448 int boinc_resolve_filename(
449     const char *virtual_name, char *physical_name, int len
450 ) {
451     FILE *fp;
452     char buf[512], *p;
453 
454     if (!virtual_name) return ERR_NULL;
455     strlcpy(physical_name, virtual_name, len);
456 
457 #ifndef _WIN32
458     if (is_symlink(virtual_name)) {
459         return 0;
460     }
461 #endif
462 
463     // Open the link file and read the first line
464     //
465     fp = boinc_fopen(virtual_name, "r");
466     if (!fp) return 0;
467 
468     // must initialize buf since fgets() on an empty file won't do anything
469     //
470     buf[0] = 0;
471     p = fgets(buf, sizeof(buf), fp);
472     fclose(fp);
473 
474     // If it's the <soft_link> XML tag, return its value,
475     // otherwise, return the original file name
476     //
477     // coverity[check_return]
478     if (p) parse_str(buf, "<soft_link>", physical_name, len);
479     return 0;
480 }
481 
482 
483 // same, std::string version
484 //
boinc_resolve_filename_s(const char * virtual_name,string & physical_name)485 int boinc_resolve_filename_s(const char *virtual_name, string& physical_name) {
486     char buf[512], *p;
487     if (!virtual_name) return ERR_NULL;
488     physical_name = virtual_name;
489 #ifndef _WIN32
490     if (is_symlink(virtual_name)) {
491         return 0;
492     }
493 #endif
494     FILE *fp = boinc_fopen(virtual_name, "r");
495     if (!fp) return 0;
496     buf[0] = 0;
497     p = fgets(buf, 512, fp);
498     fclose(fp);
499     // coverity[check_return]
500     if (p) parse_str(buf, "<soft_link>", physical_name);
501     return 0;
502 }
503 
504 // if the given file is a soft link of the form ../../project_dir/x,
505 // return x, else return empty string
506 //
resolve_soft_link(const char * project_dir,const char * file)507 string resolve_soft_link(const char* project_dir, const char* file) {
508     char buf[1024], physical_name[1024];
509     FILE* fp = boinc_fopen(file, "r");
510     if (!fp) {
511         return string("");
512     }
513     buf[0] = 0;
514     char* p = fgets(buf, sizeof(buf), fp);
515     fclose(fp);
516     if (!p) {
517         return string("");
518     }
519     if (!parse_str(buf, "<soft_link>", physical_name, sizeof(physical_name))) {
520         return string("");
521     }
522     snprintf(buf, sizeof(buf), "../../%s/", project_dir);
523     if (strstr(physical_name, buf) != physical_name) {
524         return string("");
525     }
526     return string(physical_name + strlen(buf));
527 }
528 
url_to_project_dir(char * url,char * dir,int dirsize)529 void url_to_project_dir(char* url, char* dir, int dirsize) {
530     char buf[256];
531     escape_project_url(url, buf);
532     snprintf(dir, dirsize, "%s/%s", PROJECT_DIR, buf);
533 }
534 
535