root/util_exec.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- setVirtualPidEnvVar
- isdir0700
- safeMkdir
- safeSystem
- expandPathname
- elfType
- ld_linux_so_path
- isStaticallyLinked
- isScreen
- setScreenDir
- getScreenDir
- isSetuid
- patchArgvIfSetuid
- freePatchedArgv
- prepareDlsymWrapper
- getDlsymOffset
- getDlsymOffset_m32
- runMtcpRestore
- adjustRlimitStack
- getPath
- getDmtcpArgs
1 /****************************************************************************
2 * Copyright (C) 2006-2013 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of DMTCP. *
6 * *
7 * DMTCP is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/time.h>
25 #include <sys/resource.h>
26 #include "util.h"
27 #include "syscallwrappers.h"
28 #include "uniquepid.h"
29 #include "protectedfds.h"
30 #include "shareddata.h"
31 #include "../jalib/jassert.h"
32 #include "../jalib/jfilesystem.h"
33 #include "../jalib/jconvert.h"
34
35 using namespace dmtcp;
36
37 static int32_t getDlsymOffset();
38 static int32_t getDlsymOffset_m32();
39
40 void Util::setVirtualPidEnvVar(pid_t pid, pid_t virtPpid, pid_t realPpid)
41 {
42 // We want to use setenv() only once. For all later changes, we manipulate
43 // the buffer in place. This was done to avoid a bug when using Perl. Perl
44 // implements its own setenv by keeping a private copy libc:environ and never
45 // refers to libc:private, thus libc:setenv is outdated and calling setenv()
46 // can cause segfault.
47 char buf1[80];
48 char buf2[80];
49 memset(buf2, '#', sizeof(buf2));
50 buf2[sizeof(buf2) - 1] = '\0';
51
52 sprintf(buf1, "%d:%d:%d:", pid, virtPpid, realPpid);
53
54 if (getenv(ENV_VAR_VIRTUAL_PID) == NULL) {
55 memcpy(buf2, buf1, strlen(buf1));
56 setenv(ENV_VAR_VIRTUAL_PID, buf2, 1);
57 } else {
58 char *envStr = (char*) getenv(ENV_VAR_VIRTUAL_PID);
59 memcpy(envStr, buf1, strlen(buf1));
60 }
61 }
62
63 // 'screen' requires directory with permissions 0700
64 static int isdir0700(const char *pathname)
65 {
66 struct stat st;
67 stat(pathname, &st);
68 return (S_ISDIR(st.st_mode) == 1
69 && (st.st_mode & 0777) == 0700
70 && st.st_uid == getuid()
71 && access(pathname, R_OK | W_OK | X_OK) == 0
72 );
73 }
74
75 int Util::safeMkdir(const char *pathname, mode_t mode)
76 {
77 // If it exists and we can give it the right permissions, do it.
78 chmod(pathname, 0700);
79 if (isdir0700(pathname))
80 return 0;
81 // else start over
82 unlink(pathname);
83 rmdir(pathname); // Maybe it was an empty directory
84 mkdir(pathname, 0700);
85 return isdir0700(pathname);
86 }
87
88 int Util::safeSystem(const char *command)
89 {
90 char *str = getenv("LD_PRELOAD");
91 string dmtcphjk;
92 if (str != NULL)
93 dmtcphjk = str;
94 unsetenv("LD_PRELOAD");
95 int rc = _real_system(command);
96 if (str != NULL)
97 setenv("LD_PRELOAD", dmtcphjk.c_str(), 1);
98 return rc;
99 }
100
101 int Util::expandPathname(const char *inpath, char * const outpath,
102 size_t size)
103 {
104 bool success = false;
105 if (*inpath == '/' || strstr(inpath, "/") != NULL) {
106 strncpy(outpath, inpath, size);
107 success = true;
108 } else if (strStartsWith(inpath, "~/")) {
109 snprintf(outpath, size, "%s%s", getenv("HOME"), &inpath[1]);
110 success = true;
111 } else if (strStartsWith(inpath, "~")) {
112 snprintf(outpath, size, "/home/%s", &inpath[1]);
113 success = true;
114 } else if (strStartsWith(inpath, ".")) {
115 snprintf(outpath, size, "%s/%s", jalib::Filesystem::GetCWD().c_str(),
116 inpath);
117 success = true;
118 } else {
119 char *pathVar = getenv("PATH");
120 outpath[0] = '\0';
121 if (pathVar == NULL) {
122 pathVar = (char*) ":/bin:/usr/bin";
123 }
124 while (*pathVar != '\0') {
125 char *nextPtr;
126 nextPtr = strchrnul(pathVar, ':');
127 if (nextPtr == pathVar) {
128 /* Two adjacent colons, or a colon at the beginning or the end
129 of `PATH' means to search the current directory. */
130 strcpy(outpath, jalib::Filesystem::GetCWD().c_str());
131 } else {
132 strncpy(outpath, pathVar, nextPtr - pathVar);
133 outpath[nextPtr-pathVar] = '\0';
134 }
135
136 JASSERT(size > strlen(outpath) + strlen(inpath) + 1)
137 (size) (outpath) (strlen(outpath)) (inpath) (strlen(inpath))
138 .Text("Pathname too long; Use larger buffer.");
139
140 strcat(outpath, "/");
141 strcat(outpath, inpath);
142
143 if (*nextPtr == '\0')
144 pathVar = nextPtr;
145 else // else *nextPtr == ':'
146 pathVar = nextPtr + 1; // prepare for next iteration
147 if (access(outpath, X_OK) == 0) {
148 success = true;
149 break;
150 }
151 }
152 }
153 return (success ? 0 : -1);
154 }
155
156 int Util::elfType(const char *pathname, bool *isElf, bool *is32bitElf)
157 {
158 const char *magic_elf = "\177ELF"; // Magic number for ELF
159 const char *magic_elf32 = "\177ELF\001"; // Magic number for ELF 32-bit
160 // Magic number for ELF 64-bit is "\177ELF\002"
161 const int len = strlen(magic_elf32);
162 char argv_buf[len + 1];
163 char full_path[PATH_MAX];
164 expandPathname(pathname, full_path, sizeof(full_path));
165 int fd = _real_open(full_path, O_RDONLY, 0);
166 if (fd == -1) {
167 return -1;
168 }
169 ssize_t ret = readAll(fd, argv_buf, len);
170 close (fd);
171 if (ret != len) {
172 return -1;
173 }
174 *isElf = (memcmp(magic_elf, argv_buf, strlen(magic_elf)) == 0);
175 *is32bitElf = (memcmp(magic_elf32, argv_buf, strlen(magic_elf32)) == 0);
176 return 0;
177 }
178
179 static string ld_linux_so_path(int version, bool is32bitElf = false)
180 {
181 char buf[80];
182 #if (defined(__x86_64__) || defined(__aarch64__)) && !defined(CONFIG_M32)
183 if (is32bitElf) {
184 sprintf(buf, "/lib/ld-linux.so.%d", version);
185 } else {
186 sprintf(buf, ELF_INTERPRETER);
187 }
188 #else
189 sprintf(buf, ELF_INTERPRETER);
190 #endif
191
192 string cmd = buf;
193 return cmd;
194 }
195
196 bool Util::isStaticallyLinked(const char *filename)
197 {
198 bool isElf, is32bitElf;
199 char pathname[PATH_MAX];
200 expandPathname(filename, pathname, sizeof(pathname));
201 elfType(pathname, &isElf, &is32bitElf);
202
203 int version = 2;
204 string cmd;
205 do {
206 cmd = ld_linux_so_path(version, is32bitElf);
207 version++;
208 } while (!jalib::Filesystem::FileExists(cmd) && version < 10);
209
210 cmd = cmd + " --verify " + pathname + " > /dev/null";
211
212 // FIXME: When tested on dmtcp/test/pty.c, 'ld.so -verify' returns
213 // nonzero status. Why is this? It's dynamically linked.
214 if (isElf && safeSystem(cmd.c_str())) {
215 return true;
216 }
217 return false;
218 }
219
220 bool Util::isScreen(const char *filename)
221 {
222 return jalib::Filesystem::BaseName(filename) == "screen" &&
223 isSetuid(filename);
224 }
225
226 //NOTE: This routine is called only if 'screen' is setuid.
227 // In Ubuntu 9.10, an unprivileged 'screen' (no setuid) will ckpt and restart
228 // fine if SCREENDIR is set to the file $USER/tmp4 when $USER/tmp4 doesn't exist
229 // Arguably this is a bug in screen-4.0. Should we take advantage of it?
230 void Util::setScreenDir() {
231 if (getenv("SCREENDIR") == NULL) {
232 // This will flash by, but the user will see it again on exiting screen.
233 JASSERT_STDERR <<"*** WARNING: Environment variable SCREENDIR is not set!\n"
234 << "*** Set this to a safe location, and if restarting on\n"
235 << "*** a new host, copy your SCREENDIR directory there.\n"
236 << "*** DMTCP will use"
237 " $DMTCP_TMPDIR/dmtcp-USER@HOST/uscreens for now,\n"
238 << "*** but this directory may not survive a re-boot!\n"
239 << "*** As of DMTCP-1.2.3, emacs23 not yet supported\n"
240 << "*** inside screen. Please use emacs22 for now. This\n"
241 << "*** will be fixed in a future version of DMTCP.\n\n";
242 setenv("SCREENDIR", Util::getScreenDir().c_str(), 1);
243 } else {
244 if (access(getenv("SCREENDIR"), R_OK|W_OK|X_OK) != 0)
245 JASSERT_STDERR << "*** WARNING: Environment variable SCREENDIR is set\n"
246 << "*** to directory with improper permissions.\n"
247 << "*** Please use a SCREENDIR with permission 700."
248 << " [ SCREENDIR = " << getenv("SCREENDIR") << " ]\n"
249 << "*** Continuing anyway, and hoping for the best.\n";
250 }
251
252 }
253
254 string Util::getScreenDir()
255 {
256 string tmpdir = string(dmtcp_get_tmpdir()) + "/" + "uscreens";
257 safeMkdir(tmpdir.c_str(), 0700);
258 return tmpdir;
259 }
260
261 bool Util::isSetuid(const char *filename)
262 {
263 char pathname[PATH_MAX];
264 if (expandPathname(filename, pathname, sizeof(pathname)) == 0) {
265 struct stat buf;
266 if (stat(pathname, &buf) == 0 && (buf.st_mode & S_ISUID ||
267 buf.st_mode & S_ISGID)) {
268 return true;
269 }
270 }
271 return false;
272 }
273
274 void Util::patchArgvIfSetuid(const char* filename, char *const origArgv[],
275 char ***newArgv)
276 {
277 if (isSetuid(filename) == false) return;
278
279 char realFilename[PATH_MAX];
280 memset(realFilename, 0, sizeof(realFilename));
281 expandPathname(filename, realFilename, sizeof (realFilename));
282 //char expandedFilename[PATH_MAX];
283 // expandPathname(filename, expandedFilename, sizeof (expandedFilename));
284 // JASSERT(readlink(expandedFilename, realFilename, PATH_MAX - 1) != -1)
285 // (filename) (expandedFilename) (realFilename) (JASSERT_ERRNO);
286
287 size_t newArgc = 0;
288 while (origArgv[newArgc] != NULL) newArgc++;
289 newArgc += 2;
290 size_t newArgvSize = newArgc * sizeof(char*);
291
292 // IS THIS A MEMORY LEAK? WHEN DO WE FREE buf? - Gene
293 void *buf = JALLOC_HELPER_MALLOC(newArgvSize + 2 + PATH_MAX);
294 memset(buf, 0, newArgvSize + 2 + PATH_MAX);
295
296 *newArgv = (char**) buf;
297 char *newFilename = (char*)buf + newArgvSize + 1;
298
299 #define COPY_BINARY
300 #ifdef COPY_BINARY
301 // cp /usr/bin/screen /tmp/dmtcp-USER@HOST/screen
302 char cpCmdBuf[PATH_MAX * 2 + 8];
303
304 snprintf(newFilename, PATH_MAX, "%s/%s",
305 dmtcp_get_tmpdir(),
306 jalib::Filesystem::BaseName(realFilename).c_str());
307
308 snprintf(cpCmdBuf, sizeof(cpCmdBuf),
309 "/bin/cp %s %s", realFilename, newFilename);
310
311 // Remove any stale copy, just in case it's not right.
312 JASSERT(unlink(newFilename) == 0 || errno == ENOENT) (newFilename);
313
314 JASSERT(safeSystem(cpCmdBuf) == 0)(cpCmdBuf)
315 .Text("call to system(cpCmdBuf) failed");
316
317 JASSERT(access(newFilename, X_OK) == 0) (newFilename) (JASSERT_ERRNO);
318
319 (*newArgv)[0] = newFilename;
320 int i;
321 for (i = 1; origArgv[i] != NULL; i++)
322 (*newArgv)[i] = (char*)origArgv[i];
323 (*newArgv)[i] = origArgv[i]; // copy final NULL pointer.
324
325 return;
326 #else
327 // FIXME : This might fail to compile. Will fix later. -- Kapil
328 // Translate: screen to: /lib/ld-linux.so /usr/bin/screen
329 // This version is more general, but has a bug on restart:
330 // memory layout is altered on restart, and so brk() doesn't match.
331 // Switch argvPtr from ptr to input to ptr to output now.
332 *argvPtr = (char **)(cmdBuf + strlen(cmdBuf) + 1); // ... + 1 for '\0'
333 // Use /lib64 if 64-bit O/S and not 32-bit app:
334
335 char *ldStrPtr = NULL;
336 #if (defined(__x86_64__) || defined(__aarch64__)) && !defined(CONFIG_M32)
337 bool isElf, is32bitElf;
338 elfType(cmdBuf, &isElf, &is32bitElf);
339 if (is32bitElf)
340 ldStrPtr = (char *)"/lib/ld-linux.so.2";
341 else
342 ldStrPtr = (char *)ELF_INTERPRETER;
343 # else
344 ldStrPtr = (char *)ELF_INTERPRETER;
345 # endif
346
347 JASSERT(newArgv0Len > strlen(origPath) + 1)
348 (newArgv0Len) (origPath) (strlen(origPath)) .Text("Buffer not large enough");
349
350 strncpy(newArgv0, origPath, newArgv0Len);
351
352 size_t origArgvLen = 0;
353 while (origArgv[origArgvLen] != NULL)
354 origArgvLen++;
355
356 JASSERT(newArgvLen >= origArgvLen + 1) (origArgvLen) (newArgvLen)
357 .Text("newArgv not large enough to hold the expanded argv");
358
359 // ISN'T THIS A BUG? newArgv WAS DECLARED 'char ***'.
360 newArgv[0] = ldStrPtr;
361 newArgv[1] = newArgv0;
362 for (int i = 1; origArgv[i] != NULL; i++)
363 newArgv[i+1] = origArgv[i];
364 newArgv[i+1] = origArgv[i]; // Copy final NULL pointer.
365 #endif
366 return;
367 }
368
369 void Util::freePatchedArgv(char **newArgv)
370 {
371 JALLOC_HELPER_FREE(*newArgv);
372 }
373
374 // FIXME: ENV_VAR_DLSYM_OFFSET should be reset in _real_dlsym and it should be
375 // recalculated/reset right before returning from prepareForExec to support
376 // process migration (the offset might have changed after the process had
377 // migrated to a new machine with different ld.so.
378 void Util::prepareDlsymWrapper()
379 {
380 /* For the sake of dlsym wrapper. We compute the address of _real_dlsym by
381 * adding dlsym_offset to the address of dlopen after the exec into the user
382 * application. */
383 uint32_t offset = SharedData::getDlsymOffset();
384 uint32_t offset_m32 = SharedData::getDlsymOffset_m32();
385
386 if (offset == 0) {
387 offset = getDlsymOffset();
388 offset_m32 = getDlsymOffset_m32();
389 SharedData::updateDlsymOffset(offset, offset_m32);
390 }
391
392 char str[21] = {0};
393 sprintf(str, "%d", offset);
394 setenv(ENV_VAR_DLSYM_OFFSET, str, 1);
395 sprintf(str, "%d", offset_m32);
396 setenv(ENV_VAR_DLSYM_OFFSET_M32, str, 1);
397 }
398
399 static int32_t getDlsymOffset()
400 {
401 void* base_addr = NULL;
402 void* dlsym_addr = NULL;
403 int32_t offset;
404 void* handle = NULL;
405 handle = dlopen(LIBDL_FILENAME, RTLD_NOW);
406 JASSERT(handle != NULL) (dlerror());
407
408 /* Earlier, we used to compute the offset of "dlsym" from "dlerror" by
409 * computing the address of the two symbols using '&' operator. However, in
410 * some distros (for ex. SLES 9), '&dlsym' might give the address of the
411 * symbol defined in binary's PLT. Thus, to compute the correct offset, we
412 * use dlopen/dlsym.
413 */
414 base_addr = dlsym(handle, LIBDL_BASE_FUNC_STR);
415 dlsym_addr = dlsym(handle, "dlsym");
416 dlclose(handle);
417 offset = (char *)dlsym_addr - (char *)base_addr;
418 return offset;
419 }
420
421 static int32_t getDlsymOffset_m32()
422 {
423 uint64_t base_addr = 0;
424 uint64_t dlsym_addr = 0;
425 int32_t offset;
426 FILE *fp;
427 char buf[PATH_MAX];
428 string cmd1, cmd2, libdl, libdmtcp32;
429
430 libdmtcp32 = Util::getPath("libdmtcp.so", true);
431 if (libdmtcp32 == "libdmtcp.so") return 0;
432
433 cmd1 = "ldd " + libdmtcp32 + " | grep " + LIBDL_FILENAME
434 + " | tr '\t' ' ' | tr -s ' '| cut -d' ' -f4";
435 fp = popen(cmd1.c_str(), "r");
436 JASSERT(fp != NULL);
437 JASSERT(fscanf(fp, "%s", (char*) &buf) == 1);
438 fclose(fp);
439 JASSERT(buf[0] == '/');
440
441 libdl = buf;
442
443 cmd2 = "nm -D -g " + libdl + " | grep '" + LIBDL_BASE_FUNC_STR + "'";
444 fp = popen(cmd2.c_str(), "r");
445 JASSERT(fp != NULL);
446 // fread returns the total number of bytes read only when 'size' is 1.
447 JASSERT(fread(buf, 1, sizeof(buf), fp) > 0);
448 base_addr = strtoull(buf, NULL, 16);
449 JASSERT(base_addr != 0);
450 fclose(fp);
451
452 cmd2 = "nm -D -g " + libdl + " | grep 'dlsym'";
453 fp = popen(cmd2.c_str(), "r");
454 JASSERT(fp != NULL);
455 JASSERT(fread(buf, 1, sizeof(buf), fp) > 0);
456 dlsym_addr = strtoull(buf, NULL, 16);
457 JASSERT(base_addr != 0);
458 fclose(fp);
459
460 offset = (int32_t) ((char *)dlsym_addr - (char *)base_addr);
461 return offset;
462 }
463
464 void Util::runMtcpRestore(int is32bitElf, const char* path, int fd,
465 size_t argvSize, size_t envSize)
466 {
467 static string mtcprestart = Util::getPath ("mtcp_restart");
468
469 if (is32bitElf) {
470 mtcprestart = Util::getPath("mtcp_restart-32", is32bitElf);
471 }
472
473 // Tell mtcp_restart process to write its debugging information to
474 // PROTECTED_STDERR_FD. This way we prevent it from spitting out garbage onto
475 // FD_STDERR if it is being used by the user process in a special way.
476 char protected_stderr_fd_str[16];
477 sprintf(protected_stderr_fd_str, "%d", PROTECTED_STDERR_FD);
478
479 char buf[64];
480 sprintf(buf, "%d", fd);
481
482 char* newArgs[] = {
483 (char*) mtcprestart.c_str(),
484 (char*) "--stderr-fd",
485 protected_stderr_fd_str,
486 (char*) "--fd",
487 buf,
488 NULL
489 };
490 JTRACE ("launching mtcp_restart --fd")(fd)(path);
491
492 // Create the placeholder for "MTCP_OLDPERS" environment.
493 // setenv("MTCP_OLDPERS_DUMMY", "XXXXXXXXXXXXXXXX", 1);
494 // FIXME: Put an explanation of the logic below. -- Kapil
495 #define ENV_PTR(x) ((char*) (getenv(x) - strlen(x) - 1))
496 char* dummyEnviron = NULL;
497 const int pathIndex = 0; // index in newEnv[]
498 const int dummyEnvironIndex = 1; // index in newEnv[]
499 // Eventually, newEnv = {ENV_PTR("MTCP_OLDPERS"), ENV_PTR("PATH"), NULL}
500 // newEnv[2] = NULL; newEnv[3] and newEnv[4] are available so that
501 // they can easily be used to modify envp inside mtcp_restart.c:main().
502 // for debugging in GDB. These appear _after_ final NULL of newEnv[].
503 char* newEnv[7] = {NULL, NULL, NULL,
504 const_cast<char *> ("MTCP_RESTART_PAUSE=1"),
505 const_cast<char *> ("DMTCP_RESTART_PAUSE=1"),
506 const_cast<char *> ("MTCP_RESTART_PAUSE2=1"),
507 const_cast<char *> ("DMTCP_RESTART_PAUSE2=1")};
508 // Will put ENV_PTR("MTCP_OLDPERS") here.
509 newEnv[dummyEnvironIndex] = (char*) dummyEnviron;
510 newEnv[pathIndex] = (getenv("PATH") ? ENV_PTR("PATH") : NULL);
511
512 size_t newArgsSize = 0;
513 for (int i = 0; newArgs[i] != 0; i++) {
514 newArgsSize += strlen(newArgs[i]) + 1;
515 }
516 size_t newEnvSize = 0;
517 for (int i = 0; newEnv[i] != 0; i++) {
518 newEnvSize += strlen(newEnv[i]) + 1;
519 }
520 size_t originalArgvEnvSize = argvSize + envSize;
521 size_t newArgvEnvSize = newArgsSize + newEnvSize + strlen(newArgs[0]);
522 size_t argvSizeDiff = originalArgvEnvSize - newArgvEnvSize;
523 if (argvSizeDiff > 0) {
524 dummyEnviron = (char*) malloc(argvSizeDiff);
525 memset(dummyEnviron, '0', argvSizeDiff - 1 );
526 strncpy(dummyEnviron,
527 ENV_VAR_DMTCP_DUMMY "=",
528 strlen(ENV_VAR_DMTCP_DUMMY "="));
529 dummyEnviron[argvSizeDiff - 1] = '\0';
530 newEnv[dummyEnvironIndex] = dummyEnviron;
531 }
532
533 JTRACE("Args/Env Sizes")
534 (newArgsSize) (newEnvSize) (argvSize) (envSize) (argvSizeDiff);
535
536 execve (newArgs[0], newArgs, newEnv);
537 JASSERT (false) (newArgs[0]) (newArgs[1]) (JASSERT_ERRNO)
538 .Text ("exec() failed");
539 }
540
541 void Util::adjustRlimitStack()
542 {
543 #ifdef __i386__
544 // This is needed in 32-bit Ubuntu 9.10, to fix bug with test/dmtcp5.c
545 // NOTE: Setting personality() is cleanest way to force legacy_va_layout,
546 // but there's currently a bug on restart in the sequence:
547 // checkpoint -> restart -> checkpoint -> restart
548 # if 0
549 { unsigned long oldPersonality = personality(0xffffffffL);
550 if (! (oldPersonality & ADDR_COMPAT_LAYOUT)) {
551 // Force ADDR_COMPAT_LAYOUT for libs in high mem, to avoid vdso conflict
552 personality(oldPersonality & ADDR_COMPAT_LAYOUT);
553 JTRACE("setting ADDR_COMPAT_LAYOUT");
554 setenv("DMTCP_ADDR_COMPAT_LAYOUT", "temporarily is set", 1);
555 }
556 }
557 # else
558 { struct rlimit rlim;
559 getrlimit(RLIMIT_STACK, &rlim);
560 if (rlim.rlim_cur != RLIM_INFINITY) {
561 char buf[100];
562 sprintf(buf, "%lu", rlim.rlim_cur); // "%llu" for BSD/Mac OS
563 JTRACE("setting rlim_cur for RLIMIT_STACK") (rlim.rlim_cur);
564 setenv("DMTCP_RLIMIT_STACK", buf, 1);
565 // Force kernel's internal compat_va_layout to 0; Force libs to high mem.
566 rlim.rlim_cur = rlim.rlim_max;
567 // FIXME: if rlim.rlim_cur != RLIM_INFINITY, then we should warn the user.
568 setrlimit(RLIMIT_STACK, &rlim);
569 // After exec, process will restore DMTCP_RLIMIT_STACK in DmtcpWorker()
570 }
571 }
572 # endif
573 #endif
574 }
575
576 // TODO(kapil): rewrite getPath to remove dependency on jalib.
577 string Util::getPath(string cmd, bool is32bit)
578 {
579 // search relative to base dir of dmtcp installation.
580 const char *p1[] = {
581 "/bin/",
582 "/lib64/dmtcp/",
583 "/lib/dmtcp/",
584 };
585
586 string suffixFor32Bits;
587 #if defined(__x86_64__) || defined(__aarch64__)
588 if (is32bit) { // if this is a multi-architecture build
589 string basename = jalib::Filesystem::BaseName(cmd);
590 if (cmd == "mtcp_restart-32") {
591 suffixFor32Bits = "32/bin/";
592 } else {
593 suffixFor32Bits = "32/lib/dmtcp/";
594 }
595 }
596 #endif
597
598 // Search relative to dir of this command (bin/dmtcp_launch), (using p1).
599 string udir = SharedData::getInstallDir();
600 for (size_t i = 0; i < sizeof(p1) / sizeof(char*); i++) {
601 string pth = udir + p1[i] + suffixFor32Bits + cmd;
602 if (jalib::Filesystem::FileExists(pth)) {
603 return pth;
604 }
605 }
606
607 return cmd;
608 }
609
610 void Util::getDmtcpArgs(vector<string> &dmtcp_args)
611 {
612 const char * sigckpt = getenv (ENV_VAR_SIGCKPT);
613 const char * compression = getenv (ENV_VAR_COMPRESSION);
614 const char * allocPlugin = getenv (ENV_VAR_ALLOC_PLUGIN);
615 const char * dlPlugin = getenv (ENV_VAR_DL_PLUGIN);
616 #ifdef HBICT_DELTACOMP
617 const char * deltacompression = getenv (ENV_VAR_DELTACOMPRESSION);
618 #endif
619 const char * ckptOpenFiles = getenv (ENV_VAR_CKPT_OPEN_FILES);
620 const char * ckptDir = getenv (ENV_VAR_CHECKPOINT_DIR);
621 const char * tmpDir = getenv (ENV_VAR_TMPDIR);
622 const char * plugins = getenv (ENV_VAR_PLUGIN);
623
624 //modify the command
625 dmtcp_args.clear();
626 dmtcp_args.push_back("--coord-host");
627 dmtcp_args.push_back(SharedData::coordHost());
628 dmtcp_args.push_back("--coord-port");
629 dmtcp_args.push_back(jalib::XToString(SharedData::coordPort()));
630
631 if (jassert_quiet == 1) {
632 dmtcp_args.push_back("-q");
633 } else if (jassert_quiet == 2) {
634 dmtcp_args.push_back("-q -q");
635 }
636
637 if (sigckpt != NULL) {
638 dmtcp_args.push_back("--ckpt-signal");
639 dmtcp_args.push_back(sigckpt);
640 }
641
642 if (ckptDir != NULL) {
643 dmtcp_args.push_back("--ckptdir");
644 dmtcp_args.push_back(ckptDir);
645 }
646
647 if (tmpDir != NULL) {
648 dmtcp_args.push_back("--tmpdir");
649 dmtcp_args.push_back(tmpDir);
650 }
651
652 if (ckptOpenFiles != NULL) {
653 dmtcp_args.push_back("--checkpoint-open-files");
654 }
655
656 if (plugins != NULL) {
657 dmtcp_args.push_back("--with-plugin");
658 dmtcp_args.push_back(plugins);
659 }
660
661 if (compression != NULL) {
662 if (strcmp (compression, "1") == 0)
663 dmtcp_args.push_back("--no-gzip");
664 else
665 dmtcp_args.push_back("--gzip");
666 }
667
668 if (allocPlugin != NULL && strcmp(allocPlugin, "0") == 0) {
669 dmtcp_args.push_back("--disable-alloc-plugin");
670 }
671
672 if (dlPlugin != NULL && strcmp(dlPlugin, "0") == 0) {
673 dmtcp_args.push_back("--disable-dl-plugin");
674 }
675
676 if (dmtcp_ptrace_enabled != NULL && dmtcp_ptrace_enabled()) {
677 dmtcp_args.push_back("--ptrace");
678 }
679
680 if (dmtcp_modify_env_enabled != NULL && dmtcp_modify_env_enabled()) {
681 dmtcp_args.push_back("--modify_env");
682 }
683
684 if (dmtcp_infiniband_enabled != NULL && dmtcp_infiniband_enabled()) {
685 dmtcp_args.push_back("--infiniband");
686 }
687
688 if (dmtcp_batch_queue_enabled != NULL && dmtcp_batch_queue_enabled()) {
689 dmtcp_args.push_back("--batch-queue");
690 }
691
692 #ifdef HBICT_DELTACOMP
693 if (deltacompression != NULL) {
694 if (strcmp(deltacompression, "0") == 0)
695 dmtcp_args.push_back("--no-hbict");
696 else
697 dmtcp_args.push_back("--hbict");
698 }
699 #endif
700 }