timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
tim::popen Namespace Reference

Classes

struct  group_info
 
struct  TIMEMORY_PIPE
 

Typedefs

using string_t = std::string
 
using strvec_t = std::vector< string_t >
 

Functions

group_infoget_group_info ()
 
void drop_privileges (int permanent)
 
void restore_privileges ()
 
int open_devnull (int fd)
 
void sanitize_files ()
 
pid_t fork ()
 
TIMEMORY_PIPEpopen (const char *path, char **argv, char **envp)
 
int pclose (TIMEMORY_PIPE *p)
 
strvec_t read_fork (TIMEMORY_PIPE *proc, int max_counter)
 
std::ostream & flush_output (std::ostream &os, TIMEMORY_PIPE *proc, int max_counter)
 
 TIMEMORY_UTILITY_LINKAGE (TIMEMORY_PIPE *) popen(const char *path
 
 TIMEMORY_UTILITY_LINKAGE (int) pclose(TIMEMORY_PIPE *p)
 
 TIMEMORY_UTILITY_LINKAGE (pid_t) fork()
 
 TIMEMORY_UTILITY_LINKAGE (void) sanitize_files()
 
 TIMEMORY_UTILITY_LINKAGE (strvec_t) read_fork(TIMEMORY_PIPE *proc
 

Variables

char ** argv = nullptr
 
char char ** envp = nullptr)
 
int max_counter = 50)
 

Class Documentation

◆ tim::popen::group_info

struct tim::popen::group_info

Definition at line 55 of file popen.cpp.

+ Collaboration diagram for tim::popen::group_info:
Class Members
gid_t group_id
gid_t groups[16]
int ngroups
uid_t user_id

◆ tim::popen::TIMEMORY_PIPE

struct tim::popen::TIMEMORY_PIPE

Definition at line 60 of file popen.hpp.

+ Collaboration diagram for tim::popen::TIMEMORY_PIPE:
Class Members
pid_t child_pid
int child_status
FILE * read_fd
FILE * write_fd

Typedef Documentation

◆ string_t

using tim::popen::string_t = typedef std::string

Definition at line 57 of file popen.hpp.

◆ strvec_t

using tim::popen::strvec_t = typedef std::vector<string_t>

Definition at line 58 of file popen.hpp.

Function Documentation

◆ drop_privileges()

void tim::popen::drop_privileges ( int  permanent)

Definition at line 75 of file popen.cpp.

76{
77 gid_t newgid = getgid();
78 gid_t oldgid = getegid();
79 uid_t newuid = getuid();
80 uid_t olduid = geteuid();
81
82 if(permanent == 0)
83 {
84 // Save information about the privileges that are being dropped so that they
85 // can be restored later.
86 //
87 get_group_info().group_id = oldgid;
88 get_group_info().user_id = olduid;
89 get_group_info().ngroups = getgroups(NGROUPS_MAX, get_group_info().groups);
90 }
91
92 // If root privileges are to be dropped, be sure to pare down the ancillary
93 // groups for the process before doing anything else because the setgroups( )
94 // system call requires root privileges. Drop ancillary groups regardless of
95 // whether privileges are being dropped temporarily or permanently.
96 //
97 if(olduid == 0)
98 setgroups(1, &newgid);
99
100 if(newgid != oldgid)
101 {
102# if !defined(TIMEMORY_LINUX)
103 auto ret = setegid(newgid);
104 if(ret != 0)
105 abort();
106 if(permanent != 0 && setgid(newgid) == -1)
107 abort();
108# else
109 if(setregid(((permanent != 0) ? newgid : oldgid), newgid) == -1)
110 abort();
111# endif
112 }
113
114 if(newuid != olduid)
115 {
116# if !defined(TIMEMORY_LINUX)
117 auto ret = seteuid(newuid);
118 if(ret != 0)
119 abort();
120 if(permanent != 0 && setuid(newuid) == -1)
121 abort();
122# else
123 if(setreuid(((permanent != 0) ? newuid : olduid), newuid) == -1)
124 abort();
125# endif
126 }
127
128 // verify that the changes were successful
129 if(permanent != 0)
130 {
131 if(newgid != oldgid && (setegid(oldgid) != -1 || getegid() != newgid))
132 abort();
133 if(newuid != olduid && (seteuid(olduid) != -1 || geteuid() != newuid))
134 abort();
135 }
136 else
137 {
138 if(newgid != oldgid && getegid() != newgid)
139 abort();
140 if(newuid != olduid && geteuid() != newuid)
141 abort();
142 }
143}
group_info & get_group_info()
Definition: popen.cpp:66
#define NGROUPS_MAX
Definition: popen.cpp:40

References get_group_info(), tim::popen::group_info::group_id, tim::popen::group_info::ngroups, NGROUPS_MAX, and tim::popen::group_info::user_id.

Referenced by fork().

◆ flush_output()

std::ostream & tim::popen::flush_output ( std::ostream &  os,
TIMEMORY_PIPE proc,
int  max_counter 
)

Definition at line 426 of file popen.cpp.

427{
428 int counter = 0;
429 while(proc)
430 {
431 char buffer[4096];
432 auto* ret = fgets(buffer, 4096, proc->read_fd);
433 if(ret == nullptr || strlen(buffer) == 0)
434 {
435 if(max_counter == 0)
436 {
437 pid_t cpid = waitpid(proc->child_pid, &proc->child_status, WNOHANG);
438 if(cpid == 0)
439 continue;
440 else
441 break;
442 }
443 if(counter++ > max_counter)
444 break;
445 continue;
446 }
447 os << string_t{ buffer } << std::flush;
448 }
449
450 return os;
451}
std::string string_t
Definition: library.cpp:57
int max_counter
Definition: popen.hpp:90
const std::string std::ostream * os

References tim::popen::TIMEMORY_PIPE::child_pid, tim::popen::TIMEMORY_PIPE::child_status, max_counter, tim::os, and tim::popen::TIMEMORY_PIPE::read_fd.

Referenced by tim::if().

◆ fork()

pid_t tim::popen::fork ( )

Definition at line 208 of file popen.cpp.

209{
210 pid_t childpid;
211
212 if((childpid = ::fork()) == -1)
213 return -1;
214
215 // If this is the parent process, there's nothing more to do
216 if(childpid != 0)
217 return childpid;
218
219 // This is the child process
220 popen::sanitize_files(); // Close all open files.
221 popen::drop_privileges(1); // Permanently drop privileges.
222
223 return 0;
224}
void drop_privileges(int permanent)
Definition: popen.cpp:75
void sanitize_files()
Definition: popen.cpp:181
pid_t fork()
Definition: popen.cpp:208

References drop_privileges(), fork(), and sanitize_files().

Referenced by fork(), and popen().

◆ get_group_info()

group_info & tim::popen::get_group_info ( )
inline

Definition at line 66 of file popen.cpp.

67{
68 static group_info _instance;
69 return _instance;
70}

Referenced by drop_privileges(), and restore_privileges().

◆ open_devnull()

int tim::popen::open_devnull ( int  fd)

Definition at line 165 of file popen.cpp.

166{
167 FILE* f = nullptr;
168 switch(fd)
169 {
170 case 0: f = freopen("/dev/null", "rb", stdin); break;
171 case 1: f = freopen("/dev/null", "wb", stdout); break;
172 case 2: f = freopen("/dev/null", "wb", stderr); break;
173 default: break;
174 }
175 return (f != nullptr && fileno(f) == fd) ? 1 : 0;
176}

Referenced by sanitize_files().

◆ pclose()

int tim::popen::pclose ( TIMEMORY_PIPE p)

Definition at line 327 of file popen.cpp.

328{
329 int status = p->child_status;
330 pid_t pid = -1;
331
332 // clean up memory
333 auto _clean = [&]() {
334 if(p->read_fd)
335 fclose(p->read_fd);
336 if(p->write_fd)
337 fclose(p->write_fd);
338 delete p;
339 };
340
341 if(status != std::numeric_limits<int>::max())
342 {
343 _clean();
344 if(WIFEXITED(status))
345 {
346 // printf("process %i exited, status=%d\n", p->child_pid,
347 // WEXITSTATUS(status));
348 return EXIT_SUCCESS;
349 }
350 else if(WIFSIGNALED(status))
351 {
352 printf("process %i killed by signal %d\n", p->child_pid, WTERMSIG(status));
353 return EXIT_FAILURE;
354 }
355 else if(WIFSTOPPED(status))
356 {
357 printf("process %i stopped by signal %d\n", p->child_pid, WSTOPSIG(status));
358 // return EXIT_FAILURE;
359 }
360 else if(WIFCONTINUED(status))
361 {
362 printf("process %i continued\n", p->child_pid);
363 // return EXIT_FAILURE;
364 }
365 }
366 else
367 {
368 if(p->child_pid != -1)
369 {
370 do
371 {
372 pid = waitpid(p->child_pid, &status, 0);
373 } while(pid == -1 && errno == EINTR);
374 }
375 }
376 _clean();
377 if(pid != -1 && WIFEXITED(status))
378 return WEXITSTATUS(status);
379 return (pid == -1 ? -1 : 0);
380}
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
Definition: statistics.hpp:320

References tim::popen::TIMEMORY_PIPE::child_pid, tim::popen::TIMEMORY_PIPE::child_status, std::max(), tim::popen::TIMEMORY_PIPE::read_fd, and tim::popen::TIMEMORY_PIPE::write_fd.

◆ popen()

TIMEMORY_PIPE * tim::popen::popen ( const char *  path,
char **  argv,
char **  envp 
)

Definition at line 229 of file popen.cpp.

230{
231 int stdin_pipe[2] = { 0, 0 };
232 int stdout_pipe[2] = { 0, 0 };
233 TIMEMORY_PIPE* p = nullptr;
234
235 static char** _argv = []() {
236 static auto* _tmp = new char*[1];
237 _tmp[0] = nullptr;
238 return _tmp;
239 }();
240
241 if(envp == nullptr)
242 envp = environ;
243 if(argv == nullptr)
244 argv = _argv;
245
246 p = new TIMEMORY_PIPE;
247
248 if(!p)
249 return nullptr;
250
251 p->read_fd = nullptr;
252 p->write_fd = nullptr;
253 p->child_pid = -1;
254
255 if(pipe(stdin_pipe) == -1)
256 {
257 delete p;
258 return nullptr;
259 }
260
261 if(pipe(stdout_pipe) == -1)
262 {
263 close(stdin_pipe[1]);
264 close(stdin_pipe[0]);
265 delete p;
266 return nullptr;
267 }
268
269 if(!(p->read_fd = fdopen(stdout_pipe[0], "r")))
270 {
271 close(stdout_pipe[1]);
272 close(stdout_pipe[0]);
273 close(stdin_pipe[1]);
274 close(stdin_pipe[0]);
275 delete p;
276 return nullptr;
277 }
278
279 if(!(p->write_fd = fdopen(stdin_pipe[1], "w")))
280 {
281 fclose(p->read_fd);
282 close(stdout_pipe[1]);
283 close(stdin_pipe[1]);
284 close(stdin_pipe[0]);
285 delete p;
286 return nullptr;
287 }
288
289 if((p->child_pid = popen::fork()) == -1)
290 {
291 fclose(p->write_fd);
292 fclose(p->read_fd);
293 close(stdout_pipe[1]);
294 close(stdin_pipe[0]);
295 delete p;
296 return nullptr;
297 }
298
299 if(p->child_pid == 0)
300 {
301 // this is the child process
302 close(stdout_pipe[0]);
303 close(stdin_pipe[1]);
304 if(stdin_pipe[0] != 0)
305 {
306 dup2(stdin_pipe[0], 0);
307 close(stdin_pipe[0]);
308 }
309 if(stdout_pipe[1] != 1)
310 {
311 dup2(stdout_pipe[1], 1);
312 close(stdout_pipe[1]);
313 }
314 execve(path, argv, envp);
315 exit(127);
316 }
317
318 close(stdout_pipe[1]);
319 close(stdin_pipe[0]);
320
321 return p;
322}
char char ** envp
Definition: popen.hpp:69
char ** argv
Definition: config.cpp:55
char ** environ

References argv, tim::popen::TIMEMORY_PIPE::child_pid, tim::plotting::close(), environ, envp, fork(), tim::popen::TIMEMORY_PIPE::read_fd, and tim::popen::TIMEMORY_PIPE::write_fd.

Referenced by tim::if().

◆ read_fork()

strvec_t tim::popen::read_fork ( TIMEMORY_PIPE proc,
int  max_counter 
)

Definition at line 385 of file popen.cpp.

386{
387 int counter = 0;
388 strvec_t linked_libraries;
389
390 while(proc)
391 {
392 char buffer[4096];
393 auto* ret = fgets(buffer, 4096, proc->read_fd);
394 if(ret == nullptr || strlen(buffer) == 0)
395 {
396 if(max_counter == 0)
397 {
398 pid_t cpid = waitpid(proc->child_pid, &proc->child_status, WNOHANG);
399 if(cpid == 0)
400 continue;
401 else
402 break;
403 }
404 if(counter++ > max_counter)
405 break;
406 continue;
407 }
408 auto line = string_t(buffer);
409 auto loc = string_t::npos;
410 while((loc = line.find_first_of("\n\t")) != string_t::npos)
411 line.erase(loc, 1);
412 auto delim = delimit(line, " \n\t=>");
413 for(const auto& itr : delim)
414 {
415 if(itr.find('/') == 0)
416 linked_libraries.push_back(itr);
417 }
418 }
419
420 return linked_libraries;
421}
std::vector< string_t > strvec_t
Definition: popen.hpp:58
ContainerT delimit(const std::string &line, const std::string &delimiters="\"',;: ", PredicateT &&predicate=[](const std::string &s) -> std::string { return s;})
Definition: delimit.hpp:68

References tim::popen::TIMEMORY_PIPE::child_pid, tim::popen::TIMEMORY_PIPE::child_status, tim::delimit(), max_counter, and tim::popen::TIMEMORY_PIPE::read_fd.

◆ restore_privileges()

void tim::popen::restore_privileges ( )

Definition at line 148 of file popen.cpp.

149{
150 if(geteuid() != get_group_info().user_id)
151 if(seteuid(get_group_info().user_id) == -1 ||
152 geteuid() != get_group_info().user_id)
153 abort();
154 if(getegid() != get_group_info().group_id)
155 if(setegid(get_group_info().group_id) == -1 ||
156 getegid() != get_group_info().group_id)
157 abort();
158 if(get_group_info().user_id == 0U)
159 setgroups(get_group_info().ngroups, get_group_info().groups);
160}

References get_group_info().

◆ sanitize_files()

void tim::popen::sanitize_files ( )

Definition at line 181 of file popen.cpp.

182{
183 // int fds;
184 struct stat st;
185
186 // Make sure all open descriptors other than the standard ones are closed
187 // if((fds = getdtablesize()) == -1)
188 // fds = OPEN_MAX;
189
190 // closing these files results in the inability to read the pipe from the parent
191 // for(int fd = 3; fd < fds; ++fd)
192 // close(fd);
193
194 // Verify that the standard descriptors are open. If they're not, attempt to
195 // open them using /dev/null. If any are unsuccessful, abort.
196 for(int fd = 0; fd < 3; ++fd)
197 {
198 if(fstat(fd, &st) == -1 && (errno != EBADF || open_devnull(fd) == 0))
199 {
200 abort();
201 }
202 }
203}
int open_devnull(int fd)
Definition: popen.cpp:165

References open_devnull().

Referenced by fork().

◆ TIMEMORY_UTILITY_LINKAGE() [1/5]

tim::popen::TIMEMORY_UTILITY_LINKAGE ( int  )

◆ TIMEMORY_UTILITY_LINKAGE() [2/5]

tim::popen::TIMEMORY_UTILITY_LINKAGE ( pid_t  )

◆ TIMEMORY_UTILITY_LINKAGE() [3/5]

tim::popen::TIMEMORY_UTILITY_LINKAGE ( strvec_t  )

◆ TIMEMORY_UTILITY_LINKAGE() [4/5]

tim::popen::TIMEMORY_UTILITY_LINKAGE ( TIMEMORY_PIPE ) const

◆ TIMEMORY_UTILITY_LINKAGE() [5/5]

tim::popen::TIMEMORY_UTILITY_LINKAGE ( void  )

Variable Documentation

◆ argv

char** tim::popen::argv = nullptr

Definition at line 69 of file popen.hpp.

Referenced by popen().

◆ envp

char char** tim::popen::envp = nullptr)

Definition at line 69 of file popen.hpp.

Referenced by popen().

◆ max_counter

int tim::popen::max_counter = 50)

Definition at line 90 of file popen.hpp.

Referenced by flush_output(), and read_fork().