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
310 fd = open("/proc/self/stat", O_RDONLY, 0);
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
|
Event secure_coding: |
[VERY RISKY]. Using "sscanf" can cause a buffer overflow when done incorrectly. sscanf() assumes an arbitrarily large string, so callers must use correct precision specifiers or never use sscanf(). Use correct precision specifiers or do your own parsing. |
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