citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

fe_unix.cc (3932B)


      1 //
      2 // Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
      3 //
      4 // Permission to use, copy, modify, and distribute this software for any
      5 // purpose with or without fee is hereby granted, provided that the above
      6 // copyright notice and this permission notice appear in all copies.
      7 //
      8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 //
     16 #include "fe_unix.h"
     17 
     18 #include <sys/stat.h>		// stat
     19 #include <sys/time.h>		// utimes
     20 #include <sys/utsname.h>	// uname
     21 #include <sys/wait.h>		// waitpid
     22 
     23 #include <err.h>
     24 #include <fstream>		// ifstream, ofstream
     25 #include <unistd.h>		// execvp, fork, getpid, unlink
     26 
     27 
     28 char
     29 InstFrontendUnix::dir_sep()
     30 {
     31 	return '/';
     32 }
     33 
     34 char
     35 InstFrontendUnix::path_sep()
     36 {
     37 	return ':';
     38 }
     39 
     40 std::string
     41 InstFrontendUnix::lib_name()
     42 {
     43 	return "lib/libcitrun.a";
     44 }
     45 
     46 void
     47 InstFrontendUnix::log_os_str()
     48 {
     49 	struct utsname	 utsname;
     50 
     51 	if (uname(&utsname) == -1)
     52 		m_log << " (Unknown OS)";
     53 	else
     54 		m_log << " (" << utsname.sysname << "-" << utsname.release
     55 			<< " " << utsname.machine << ")";
     56 
     57 	// Sometimes we're not called as citrun_inst so force that here.
     58 	setprogname("citrun_inst");
     59 }
     60 
     61 void
     62 InstFrontendUnix::set_path(std::string const &new_path)
     63 {
     64 	if (setenv("PATH", new_path.c_str(), 1))
     65 		err(1, "setenv");
     66 }
     67 
     68 //
     69 // Copies one file to another preserving timestamps.
     70 //
     71 void
     72 InstFrontendUnix::copy_file(std::string const &dst_fn, std::string const &src_fn)
     73 {
     74 	struct stat sb;
     75 	struct timeval st_tim[2];
     76 
     77 	// Save original access and modification times
     78 	if (stat(src_fn.c_str(), &sb) < 0)
     79 		err(1, "stat");
     80 #ifdef __APPLE__
     81 	TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atimespec);
     82 	TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtimespec);
     83 #else
     84 	TIMESPEC_TO_TIMEVAL(&st_tim[0], &sb.st_atim);
     85 	TIMESPEC_TO_TIMEVAL(&st_tim[1], &sb.st_mtim);
     86 #endif
     87 
     88 	std::ifstream src(src_fn, std::ios::binary);
     89 	std::ofstream dst(dst_fn, std::ios::binary);
     90 
     91 	dst << src.rdbuf();
     92 
     93 	src.close();
     94 	dst.close();
     95 
     96 	//
     97 	// Restore the original access and modification time, it's not critical
     98 	// if it fails.
     99 	//
    100 	if (utimes(dst_fn.c_str(), st_tim) < 0)
    101 		warn("utimes");
    102 }
    103 
    104 bool
    105 InstFrontendUnix::is_link(bool object_arg, bool compile_arg)
    106 {
    107 	if (!object_arg && !compile_arg && m_source_files.size() > 0)
    108 		// Assume single line a.out compilation
    109 		// $ gcc main.c
    110 		return true;
    111 	else if (object_arg && !compile_arg)
    112 		// gcc -o main main.o fib.o while.o
    113 		// gcc -o main main.c fib.c
    114 		return true;
    115 
    116 	return false;
    117 }
    118 
    119 //
    120 // Execute the compiler by calling execvp(3) on the m_args vector.
    121 //
    122 void
    123 InstFrontendUnix::exec_compiler()
    124 {
    125 	if (m_is_citruninst) {
    126 		m_log << "Running as citrun_inst, not calling exec()" << std::endl;
    127 		exit(0);
    128 	}
    129 
    130 	// Null termination explicitly mentioned in execvp(3).
    131 	m_args.push_back(NULL);
    132 	if (execvp(m_args[0], &m_args[0]))
    133 		err(1, "execvp");
    134 }
    135 
    136 //
    137 // fork(2) then execute the compiler and wait for it to finish. Returns exit
    138 // code of native compiler.
    139 //
    140 int
    141 InstFrontendUnix::fork_compiler()
    142 {
    143 	pid_t child_pid;
    144 	int status;
    145 	int exit = -1;
    146 
    147 	if ((child_pid = fork()) < 0)
    148 		err(1, "fork");
    149 
    150 	// If in child execute compiler.
    151 	if (child_pid == 0)
    152 		exec_compiler();
    153 
    154 	m_log << "Forked compiler '" << m_args[0] << "' "
    155 	       << "pid is '" << child_pid << "'" << std::endl;
    156 
    157 	// Wait for the child to finish so we can get its exit code.
    158 	if (waitpid(child_pid, &status, 0) < 0)
    159 		err(1, "waitpid");
    160 
    161 	// Decode the exit code from status.
    162 	if (WIFEXITED(status))
    163 		exit = WEXITSTATUS(status);
    164 
    165 	// Return the exit code of the native compiler.
    166 	return exit;
    167 }