1 /****************************************************************************
2 * Copyright (C) 2006-2008 by Jason Ansel *
3 * jansel@csail.mit.edu *
4 * *
5 * This file is part of the JALIB module of DMTCP (DMTCP:dmtcp/jalib). *
6 * *
7 * DMTCP:dmtcp/jalib 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:dmtcp/src 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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <dirent.h>
27 #include <algorithm>
28 #include <errno.h>
29 #include <sys/utsname.h>
30 #include <sys/syscall.h>
31 #include "jfilesystem.h"
32 #include "jconvert.h"
33 #include "syscallwrappers.h"
34 #include "util.h"
35
36 namespace
37 {
38 jalib::string _GetProgramExe()
39 {
40 jalib::string exe = "/proc/self/exe";
41 jalib::string exeRes = jalib::Filesystem::ResolveSymlink ( exe );
42 JASSERT ( exe != exeRes ) ( exe ).Text ( "problem with /proc/self/exe" );
43 return exeRes;
44 }
45
46 // Set buf, and return length read (including all null characters)
47 int _GetProgramCmdline(char *buf, int size)
48 {
49 int fd = open("/proc/self/cmdline", O_RDONLY);
50 int rc;
51 int count = 0;
52 JASSERT(fd >= 0);
53 // rc == 0 means EOF, or else it means buf is full (size chars read)
54 rc = dmtcp::Util::readAll(fd, buf, size);
55 return rc;
56 }
57
58 }
59
60 jalib::string jalib::Filesystem::GetCWD()
61 {
62 jalib::string cwd;
63 char buf[PATH_MAX];
64 JASSERT(getcwd(buf, PATH_MAX) == buf)
65 .Text("Pathname too long");
66 cwd = buf;
67 return cwd;
68 }
69
70 jalib::string jalib::Filesystem::FileBaseName ( const jalib::string& str )
71 {
72 int lastSlash = 0;
73 for ( size_t i = 0; i<str.length(); ++i )
74 if ( str[i] == '/' )
75 lastSlash = i;
76 return str.substr ( lastSlash+1 );
77 }
78
79 jalib::string jalib::Filesystem::DirBaseName ( const jalib::string& str )
80 {
81 int lastSlash = 0;
82 for ( size_t i = 0; i<str.length(); ++i )
83 if ( str[i] == '/' )
84 lastSlash = i;
85 return str.substr ( 0,lastSlash );
86 }
87
88 jalib::string jalib::Filesystem::GetProgramDir()
89 {
90 static jalib::string value = DirBaseName ( GetProgramPath() );
91 return value;
92 }
93
94 jalib::string jalib::Filesystem::GetProgramName()
95 {
96 static jalib::string value = "";
97 if (value == "") {
98 int len;
99 char cmdline[1024];
100 value = FileBaseName ( GetProgramPath() ); // uses /proc/self/exe
101 // We may rewrite "a.out" to "/lib/ld-linux.so.2 a.out". If so, find cmd.
102 if (!value.empty()
103 && ( value == ResolveSymlink("/lib/ld-linux.so.2")
104 || value == ResolveSymlink("/lib64/ld-linux-x86-64.so.2") )
105 && (len = _GetProgramCmdline(cmdline, sizeof(cmdline))) > 0
106 && len > strlen(cmdline) + 1 // more than one word in cmdline
107 && *(cmdline + strlen(cmdline) + 1) != '-') // second word not a flag
108 value = FileBaseName(cmdline + strlen(cmdline) + 1); // find second word
109 }
110 return value;
111 }
112
113 jalib::string jalib::Filesystem::GetProgramPath()
114 {
115 static jalib::string value = _GetProgramExe();
116 return value;
117 }
118
119
120 jalib::string jalib::Filesystem::ResolveSymlink ( const jalib::string& path )
121 {
122 char buf [1024]; // This could be passed on via call to readlink()
123 // If path is not a symbolic link, just return it.
124 if (lstat(path.c_str(), (struct stat *)buf) == 0
125 && ! S_ISLNK(((struct stat *)buf)->st_mode))
126 return path;
127 memset ( buf,0,sizeof ( buf ) );
128 int len = readlink ( path.c_str(), buf, sizeof ( buf )-1 );
129 if ( len <= 0 )
130 return "";
131 return buf;
132 }
133
134 bool jalib::Filesystem::FileExists ( const jalib::string& str )
135 {
136 struct stat st;
137
138 if( !stat(str.c_str(),&st) ){
139 return true;
140 }else {
141 return false;
142 }
143 /* Old variant. If file is write-only we fail but this is wrong
144 FILE* fp = fopen ( str.c_str(),"r" );
145 if ( fp != NULL ) fclose ( fp );
146 return fp != NULL;
147 */
148 }
149
150 #define FHU_TRY_DIR(expr) {\
151 jalib::string pth = expr; \
152 if(FileExists(pth)) \
153 return pth;}
154
155
156 jalib::string jalib::Filesystem::FindHelperUtility ( const jalib::string& file, bool dieOnError /*= true*/ )
157 {
158 const char* d = NULL;
159 if ( ( d=getenv ( "JALIB_UTILITY_DIR" ) ) != NULL )
160 {
161 jalib::string udir = d;
162 FHU_TRY_DIR ( udir + "/" + file );
163 FHU_TRY_DIR ( udir + "/mtcp/" + file );
164 FHU_TRY_DIR ( udir + "/../mtcp/" + file );
165 FHU_TRY_DIR ( udir + "/../../mtcp/" + file );
166 FHU_TRY_DIR ( udir + "/../../../mtcp/" + file );
167 FHU_TRY_DIR ( udir + "/../" + file );
168 FHU_TRY_DIR ( udir + "/../../" + file );
169 FHU_TRY_DIR ( udir + "/../../../" + file );
170 FHU_TRY_DIR ( udir + "/../lib/dmtcp/" + file );
171 }
172 FHU_TRY_DIR ( GetProgramDir() + "/" + file );
173 FHU_TRY_DIR ( GetProgramDir() + "/mtcp/" + file );
174 FHU_TRY_DIR ( GetProgramDir() + "/../mtcp/" + file );
175 FHU_TRY_DIR ( GetProgramDir() + "/../../mtcp/" + file );
176 FHU_TRY_DIR ( GetProgramDir() + "/../../../mtcp/" + file );
177 FHU_TRY_DIR ( GetProgramDir() + "/../" + file );
178 FHU_TRY_DIR ( GetProgramDir() + "/../../" + file );
179 FHU_TRY_DIR ( GetProgramDir() + "/../../../" + file );
180 FHU_TRY_DIR ( GetProgramDir() + "/../lib/dmtcp/" + file );
181 FHU_TRY_DIR ( "./" + file );
182 FHU_TRY_DIR ( "../" + file );
183 FHU_TRY_DIR ( "../../" + file );
184 FHU_TRY_DIR ( "../../../" + file );
185 FHU_TRY_DIR ( "/bin/" + file );
186 FHU_TRY_DIR ( "/usr/bin/" + file );
187 FHU_TRY_DIR ( "/lib/" + file );
188 FHU_TRY_DIR ( "/lib64/" + file );
189 FHU_TRY_DIR ( "/usr/lib/" + file );
190 FHU_TRY_DIR ( "/usr/lib64/" + file );
191 JASSERT ( !dieOnError ) ( file ) ( GetProgramDir() ) ( d )
192 .Text ( "failed to find needed file" );
193 return file;
194 }
195
196
197 jalib::StringVector jalib::Filesystem::GetProgramArgs()
198 {
199 StringVector rv;
200
201 jalib::string path = "/proc/self/cmdline";
202 FILE* args = fopen ( path.c_str(),"r" );
203
204 JASSERT ( args != NULL ) ( path ).Text ( "failed to open command line" );
205
206 char * lineptr = ( char* ) malloc ( 512 ); //getdelim will auto-grow this buffer
207 size_t len = 511;
208
209 while ( getdelim ( &lineptr, &len, '\0', args ) >= 0 )
210 {
211 rv.push_back ( lineptr );
212 }
213
214 free ( lineptr );
215
216 return rv;
217 }
218
219 #define MALLOC_SAFE_LISTOPENFDS
220 #ifdef MALLOC_SAFE_LISTOPENFDS
221 jalib::IntVector jalib::Filesystem::ListOpenFds()
222 {
223 int fd = _real_open ("/proc/self/fd", O_RDONLY | O_NDELAY |
224 O_LARGEFILE | O_DIRECTORY, 0);
225 JASSERT(fd>=0);
226
227 const size_t allocation = (4 * BUFSIZ < sizeof (struct dirent64)
228 ? sizeof (struct dirent64) : 4 * BUFSIZ);
229 char *buf = (char*) JALLOC_HELPER_MALLOC(allocation);
230
231 IntVector fdVec;
232
233 while (true) {
234 int nread = _real_syscall(SYS_getdents, fd, buf, allocation);
235 if (nread == 0) {
236 break;
237 }
238 JASSERT(nread > 0);
239 for (int pos = 0; pos < nread;) {
240 struct linux_dirent *d = (struct linux_dirent *) (&buf[pos]);
241 if (d->d_ino > 0) {
242 char *ch;
243 int fdnum = strtol ( d->d_name, &ch, 10 );
244 if ( *ch == 0 && fdnum >= 0 ) {
245 fdVec.push_back ( fdnum );
246 }
247 }
248 pos += d->d_reclen;
249 }
250 }
251
252 _real_close(fd);
253
254 std::sort(fdVec.begin(), fdVec.end());
255 JALLOC_HELPER_FREE(buf);
256 return fdVec;
257 }
258 #else
259 jalib::IntVector jalib::Filesystem::ListOpenFds()
260 {
261 jalib::string dir = "/proc/self/fd";
262 IntVector rv;
263 struct dirent **namelist;
264 char* p;
265 int nents = scandir ( dir.c_str(), &namelist, NULL, versionsort );
266 JASSERT ( nents >= 0 ) ( dir ) ( JASSERT_ERRNO ).Text ( "failed to open directory" );
267
268 for ( int i = 0; i < nents; i ++ )
269 {
270 struct dirent * de = namelist[i];
271 int fdnum = strtol ( de -> d_name, &p, 10 );
272 if ( *p == 0 && fdnum >= 0 )
273 {
274 rv.push_back ( fdnum );
275 }
276 free ( de );
277 }
278 free ( namelist );
279
280 return rv;
281 }
282 #endif
283
284 jalib::string jalib::Filesystem::GetCurrentHostname()
285 {
286 struct utsname tmp;
287 memset ( &tmp,0,sizeof ( tmp ) );
288 JASSERT(uname ( &tmp ) != -1) (JASSERT_ERRNO);
289 jalib::string name = "unknown";
290 if ( strlen(tmp.nodename) != 0 )
291 name = tmp.nodename;
292 // #ifdef _GNU_SOURCE
293 // if(tmp.domainname != 0)
294 // name += jalib::string(".") + tmp.domainname;
295 // #endif
296 return name;
297 }
298
299 jalib::string jalib::Filesystem::GetControllingTerm()
300 {
301 char sbuf[1024];
302 jalib::ostringstream ttyName;
303 char *tmp;
304 char *S;
305 char state;
306 int ppid, pgrp, session, tty, tpgid;
307
308 int fd, num_read;
309
|
Event negative_return_fn: |
Function "open("/proc/self/stat", 0, 0)" returns a negative number. |
|
Event var_assign: |
Assigning: signed variable "fd" = "open". |
| Also see events: |
[negative_returns] |
310 fd = open("/proc/self/stat", O_RDONLY, 0);
|
At conditional (1): "fd >= 0": Taking false branch.
|
311 JASSERT( fd >= 0 ) (strerror(errno))
312 .Text ("Unable to open /proc/self/stat\n");
313
314 num_read = read(fd, sbuf, sizeof sbuf - 1);
315 close(fd);
316 if(num_read<=0) return NULL;
317 sbuf[num_read] = '\0';
318
319 S = strchr(sbuf, '(') + 1;
320 tmp = strrchr(S, ')');
321 S = tmp + 2; // skip ") "
322
323 sscanf(S,
324 "%c "
325 "%d %d %d %d %d ",
326 &state,
327 &ppid, &pgrp, &session, &tty, &tpgid
328 );
329
330 int maj = ((unsigned)(tty)>>8u) & 0xfffu;
331 int min = ((unsigned)(tty)&0xffu) | (((unsigned)(tty)&0xfff00000u)>>12u);
332
333 /* /dev/pts/ * has major numbers in the range 136 - 143 */
334 if ( maj >= 136 && maj <= 143)
335 ttyName << "/dev/pts/" << min+(maj-136)*256;
336 else
337 ttyName << "";
338
339 return ttyName.str();
340 }
341