root/util_init.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- getCoordHostAndPort
- setCoordPort
- writeCoordPortToFile
- calcTmpDir
- initializeLogFile
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 <pwd.h>
24 #include <sys/fcntl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include "constants.h"
28 #include "util.h"
29 #include "protectedfds.h"
30 #include "uniquepid.h"
31 #include "coordinatorapi.h" // for COORD_JOIN, COORD_NEW, COORD_ANY
32 #include "../jalib/jassert.h"
33 #include "../jalib/jfilesystem.h"
34 #include "../jalib/jsocket.h"
35 #include "../jalib/jconvert.h"
36
37 using namespace dmtcp;
38
39 void Util::getCoordHostAndPort(CoordinatorMode mode,
40 const char **host, int *port)
41 {
42 JASSERT(mode & COORD_JOIN || mode & COORD_NEW || mode & COORD_ANY);
43
44 if (SharedData::initialized()) {
45 *host = SharedData::coordHost().c_str();
46 *port = SharedData::coordPort();
47 return;
48 }
49
50 static bool _firstTime = true;
51 static const char *_cachedHost;
52 static int _cachedPort;
53
54 if (_firstTime) {
55 // Set host to cmd line (if --cord-host) or env var or DEFAULT_HOST
56 if (*host == NULL) {
57 if (getenv(ENV_VAR_NAME_HOST)) {
58 *host = getenv(ENV_VAR_NAME_HOST);
59 } else if (getenv("DMTCP_HOST")) { // deprecated
60 *host = getenv("DMTCP_HOST");
61 } else {
62 *host = DEFAULT_HOST;
63 }
64 }
65
66 // Set port to cmd line (if --coord-port) or env var
67 // or 0 (if --new-coordinator from cmd line) or DEFAULT_PORT
68 if (*port == UNINITIALIZED_PORT) {
69 if (getenv(ENV_VAR_NAME_PORT)) {
70 *port = jalib::StringToInt(getenv(ENV_VAR_NAME_PORT));
71 } else if (getenv("DMTCP_PORT")) { // deprecated
72 *port = jalib::StringToInt(getenv("DMTCP_PORT"));
73 } else if (mode & COORD_NEW) {
74 *port = 0;
75 } else {
76 *port = DEFAULT_PORT;
77 }
78 }
79
80 _cachedHost = *host;
81 _cachedPort = *port;
82 _firstTime = false;
83
84 } else {
85 // We might have gotten a user-requested port of 0 (random port) before,
86 // and now the user is passing in the actual coordinator port.
87 if (*port > 0 && _cachedPort == 0) {
88 _cachedPort = *port;
89 }
90 *host = _cachedHost;
91 *port = _cachedPort;
92 }
93 }
94 void Util::setCoordPort(int port)
95 {
96 const char *host = NULL;
97 // mode will be ignored, since this is not the first time we call this.
98 Util::getCoordHostAndPort(COORD_ANY, &host, &port);
99 }
100
101 void Util::writeCoordPortToFile(int port, const char *portFile)
102 {
103 if (portFile != NULL && strlen(portFile) > 0) {
104 int fd = open(portFile, O_CREAT|O_WRONLY|O_TRUNC, 0600);
105 JWARNING(fd != -1) (JASSERT_ERRNO) (portFile)
106 .Text("Failed to open port file.");
107 char port_buf[30];
108 memset(port_buf, '\0', sizeof(port_buf));
109 sprintf(port_buf, "%d", port);
110 writeAll(fd, port_buf, strlen(port_buf));
111 fsync(fd);
112 close(fd);
113 }
114 }
115
116 /*
117 * calcTmpDir() computes the TmpDir to be used by DMTCP. It does so by using
118 * DMTCP_TMPDIR env, current username, and hostname. Once computed, we open the
119 * directory on file descriptor PROTECTED_TMPDIR_FD.
120 *
121 * This mechanism was introduced to avoid calls to gethostname(), getpwuid()
122 * etc. while DmtcpWorker was still initializing (in constructor) or the
123 * process was restarting. gethostname(), getpwuid() will create a socket
124 * connect to some DNS server to find out hostname and username. The socket is
125 * closed only at next exec() and thus it leaves a dangling socket in the
126 * worker process. To resolve this issue, we make sure to call calcTmpDir() only
127 * from dmtcp_launch and dmtcp_restart process and once the user process
128 * has been exec()ed, we use SharedData::getTmpDir() only.
129 */
130 string Util::calcTmpDir(const char *tmpdirenv)
131 {
132 char hostname[256];
133 memset(hostname, 0, sizeof(hostname));
134
135 JASSERT ( gethostname(hostname, sizeof(hostname)) == 0 ||
136 errno == ENAMETOOLONG ).Text ( "gethostname() failed" );
137
138 char *userName = const_cast<char *>("");
139 if ( getpwuid ( getuid() ) != NULL ) {
140 userName = getpwuid ( getuid() ) -> pw_name;
141 } else if ( getenv("USER") != NULL ) {
142 userName = getenv("USER");
143 }
144
145 if (tmpdirenv) {
146 // tmpdirenv was set by --tmpdir
147 } else if (getenv("DMTCP_TMPDIR")) {
148 tmpdirenv = getenv("DMTCP_TMPDIR");
149 } else if (getenv("TMPDIR")) {
150 tmpdirenv = getenv("TMPDIR");
151 } else {
152 tmpdirenv = "/tmp";
153 }
154
155 JASSERT(mkdir(tmpdirenv, S_IRWXU) == 0 || errno == EEXIST)
156 (JASSERT_ERRNO) (tmpdirenv)
157 .Text("Error creating base directory (--tmpdir/DMTCP_TMPDIR/TMPDIR)");
158
159 ostringstream o;
160 o << tmpdirenv << "/dmtcp-" << userName << "@" << hostname;
161 string tmpDir = o.str();
162
163 JASSERT(mkdir(tmpDir.c_str(), S_IRWXU) == 0 || errno == EEXIST)
164 (JASSERT_ERRNO) (tmpDir)
165 .Text("Error creating tmp directory");
166
167
168 JASSERT(0 == access(tmpDir.c_str(), X_OK|W_OK)) (tmpDir)
169 .Text("ERROR: Missing execute- or write-access to tmp dir");
170
171 return tmpDir;
172 }
173
174 void Util::initializeLogFile(string tmpDir, string procname, string prevLogPath)
175 {
176 UniquePid::ThisProcess(true);
177 #ifdef DEBUG
178 // Initialize JASSERT library here
179 ostringstream o;
180 o << tmpDir;
181 o << "/jassertlog.";
182 o << UniquePid::ThisProcess();
183 o << "_";
184 if (procname.empty()) {
185 o << jalib::Filesystem::GetProgramName();
186 } else {
187 o << procname;
188 }
189
190 JASSERT_SET_LOG(o.str(), tmpDir, UniquePid::ThisProcess().toString());
191
192 ostringstream a;
193 a << "\n========================================";
194 a << "\nProcess Information";
195 a << "\n========================================";
196 a << "\nThis Process: " << UniquePid::ThisProcess()
197 << "\nParent Process: " << UniquePid::ParentProcess();
198
199 if (!prevLogPath.empty()) {
200 a << "\nPrev JAssertLog path: " << prevLogPath;
201 }
202
203 a << "\nArgv: ";
204 vector<string> args = jalib::Filesystem::GetProgramArgs();
205 size_t i;
206 for (i = 0; i < args.size(); i++) {
207 a << " " << args[i];
208 }
209
210 a << "\nEnvironment: ";
211 for (i = 0; environ[i] != NULL; i++) {
212 a << " " << environ[i] << ";";
213 }
214 a << "\n========================================\n";
215
216 JLOG(a.str().c_str());
217 #else
218 JASSERT_SET_LOG("", tmpDir, UniquePid::ThisProcess().toString());
219 #endif
220 if (getenv(ENV_VAR_QUIET)) {
221 jassert_quiet = *getenv(ENV_VAR_QUIET) - '0';
222 } else {
223 jassert_quiet = 0;
224 }
225 #ifdef QUIET
226 jassert_quiet = 2;
227 #endif
228 unsetenv(ENV_VAR_STDERR_PATH);
229 }