#if defined(DARWIN)
#include <dns_sd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysctl.h>
#include <unistd.h>
#include "config.h"
#include "distcc.h"
#include "exitcode.h"
#include "exec.h"
#include "trace.h"
#include "zeroconf_util.h"
char *dcc_zc_full_name(const char *aName, const char *aRegType,
const char *aDomain)
{
char *fullName = malloc(1025);
fullName[0] = '\0';
strcat(fullName, aName);
strcat(fullName, ".");
strcat(fullName, aRegType);
strcat(fullName, aDomain);
return fullName;
}
int dcc_simple_spawn(const char *path, char *const argv[])
{
int pid = fork();
if ( pid < 0 ) {
rs_log_error("Unable to execute %s: (%d) %s", path, errno,
strerror(errno));
return -1;
} else if ( pid == 0 ) {
if ( execve(path, argv, NULL) ) {
rs_log_error("Unexpected error while trying to execute %s: (%d) %s",
path, errno, strerror(errno));
exit(EXIT_DISTCC_FAILED);
}
} else {
int status;
long s_us;
long u_us;
rs_trace("Executed %s with pid %d", path, pid);
return dcc_collect_child(pid, &status, &u_us, &s_us);
}
return 0;
}
static char *dcc_output_from_simple_execution(const char *path,
char *const argv[])
{
int exitVal = -1;
char *output = NULL;
int outputPipe[2];
int stderrBackup = -1;
int stdoutBackup = -1;
stderrBackup = dup(2);
if ( stderrBackup < 0 ) {
rs_log_error("Unable to backup stderr: (%d) %s", errno,
strerror(errno));
}
stdoutBackup = dup(1);
if ( stdoutBackup < 0 ) {
rs_log_error("Unable to backup stdout: (%d) %s", errno,
strerror(errno));
}
exitVal = pipe(outputPipe);
if ( exitVal < 0 ) {
rs_log_error("Unable to create output pipe: (%d) %s", errno,
strerror(errno));
}
if ( stderrBackup < 0 || stdoutBackup < 0 || exitVal < 0 ) {
if ( exitVal == 0 ) {
close(outputPipe[0]);
close(outputPipe[1]);
}
if ( stderrBackup > 0 ) {
close(stderrBackup);
}
if ( stdoutBackup > 0 ) {
close(stdoutBackup);
}
} else {
int stderrDup = -1;
int stdoutDup = -1;
stdoutDup = dup2(outputPipe[1], 1);
if ( stdoutDup < 0 ) {
rs_log_error("Unable to use pipe for stdout: (%d) %s", errno,
strerror(errno));
}
stderrDup = dup2(outputPipe[1], 2);
if ( stderrDup < 0 ) {
rs_log_error("Unable to use pipe for stderr: (%d) %s", errno,
strerror(errno));
}
close(outputPipe[1]);
if ( stderrDup < 0 || stdoutDup < 0 ) {
if ( stdoutDup > 0 ) {
stdoutDup = dup2(stdoutBackup, 1);
if ( stdoutDup < 0 ) {
rs_fatal("Unable to restore stdout: (%d) %s", errno,
strerror(errno));
}
}
if ( stderrDup > 0 ) {
stderrDup = dup2(stderrBackup, 2);
if ( stderrDup < 0 ) {
rs_fatal("Unable to restore stderr: (%d) %s", errno,
strerror(errno));
}
}
} else {
fcntl(outputPipe[0], F_SETFD, 1);
exitVal = dcc_simple_spawn(path, argv);
if ( stdoutDup > 0 ) {
stdoutDup = dup2(stdoutBackup, 1);
if ( stdoutDup < 0 ) {
rs_fatal("Unable to restore stdout: (%d) %s", errno,
strerror(errno));
}
}
if ( stderrDup > 0 ) {
stderrDup = dup2(stderrBackup, 2);
if ( stderrDup < 0 ) {
rs_fatal("Unable to restore stderr: (%d) %s", errno,
strerror(errno));
}
}
if ( exitVal == 0 ) {
char bytes[1024];
ssize_t readBytes = 0;
size_t totalBytes = 1;
output = malloc(totalBytes);
if ( output == NULL ) {
rs_log_error("Unable to allocate memory for spawn output");
} else {
output[0] = '\0';
do {
readBytes = read(outputPipe[0], bytes, 1024);
if ( readBytes > 0 ) {
char *newOutput;
bytes[readBytes] = '\0';
totalBytes += (size_t) readBytes;
newOutput = realloc(output, totalBytes);
if ( newOutput == NULL ) {
rs_log_error("Unable to reallocate spawn output memory");
free(output);
output = NULL;
} else {
output = newOutput;
strcat(output, bytes);
}
}
} while ( output != NULL && readBytes > 0 );
}
}
}
close(outputPipe[0]);
close(stderrBackup);
close(stdoutBackup);
if ( stderrDup < 0 || stdoutDup < 0 ) {
exit(EXIT_DISTCC_FAILED);
}
}
return output;
}
char *dcc_generate_txt_record(void)
{
char *osRelease;
int releaseMib[2];
size_t releaseLen;
char *osType;
int typeMib[2];
size_t typeLen;
char *gccPath = (char *) "/usr/bin/gcc-3.3";
char *gccArgs[] = { gccPath, (char *) "-v", NULL };
char *gccVersion;
char *txtRecord = NULL;
char *comAppleEnd = (char *) "\";";
char *comAppleGCC = (char *) "GCCVersion=\"";
char *comAppleOS = (char *) "SystemVersion=\"";
char *protoVers = (char *) "protovers=371;";
char *txtVers = (char *) "txtvers=1;";
gccVersion = dcc_output_from_simple_execution(gccPath, gccArgs);
if ( gccVersion == NULL ) {
rs_log_error("Unable to get gcc version");
} else {
char *next;
while ( ( next = strchr(gccVersion, '\n') ) ) {
*next = ' ';
}
}
typeMib[0] = CTL_KERN;
typeMib[1] = KERN_OSTYPE;
releaseMib[0] = CTL_KERN;
releaseMib[1] = KERN_OSRELEASE;
if ( sysctl(typeMib, 2, NULL, &typeLen, NULL, 0) ) {
rs_log_error("Unable to get length for kern.ostype: (%d) %s", errno,
strerror(errno));
}
if ( sysctl(releaseMib, 2, NULL, &releaseLen, NULL, 0) ) {
rs_log_error("Unable to get length for kern.osrelease: (%d) %s", errno,
strerror(errno));
}
osType = (char *) malloc(typeLen);
osRelease = (char *) malloc(releaseLen);
if ( sysctl(typeMib, 2, osType, &typeLen, NULL, 0) ) {
rs_log_error("Unable to get kern.ostype: (%d) %s", errno,
strerror(errno));
}
if ( sysctl(releaseMib, 2, osRelease, &releaseLen, NULL, 0) ) {
rs_log_error("Unable to get kern.osrelease: (%d) %s", errno,
strerror(errno));
}
if ( gccVersion != NULL && osType != NULL && osRelease != NULL ) {
txtRecord = malloc(1 + strlen(txtVers) + 1 + 1 + strlen(protoVers) + 1 +
1 + strlen(comAppleOS) + typeLen + 1 + releaseLen +
strlen(comAppleEnd) + 1 + 1 + strlen(comAppleGCC) +
strlen(gccVersion) + strlen(comAppleEnd) + 1);
if ( txtRecord == NULL ) {
rs_log_error("Unable to allocate memory for txtRecord");
} else {
size_t endOfRecord;
txtRecord[1] = '\0';
txtRecord[0] = (char) ( strlen(txtVers) + 1 );
strcat(txtRecord, txtVers);
strcat(txtRecord, "\n");
endOfRecord = strlen(txtRecord);
txtRecord[endOfRecord+1] = '\0';
txtRecord[endOfRecord] = (char) ( strlen(protoVers) + 1 );
strcat(txtRecord, protoVers);
strcat(txtRecord, "\n");
endOfRecord = strlen(txtRecord);
txtRecord[endOfRecord+1] = '\0';
txtRecord[endOfRecord] = (char) ( strlen(comAppleOS) +
strlen(osType) +
strlen(" ") +
strlen(osRelease) +
strlen(comAppleEnd) + 1 );
strcat(txtRecord, comAppleOS);
strcat(txtRecord, osType);
strcat(txtRecord, " ");
strcat(txtRecord, osRelease);
strcat(txtRecord, comAppleEnd);
strcat(txtRecord, "\n");
endOfRecord = strlen(txtRecord);
txtRecord[endOfRecord+1] = '\0';
txtRecord[endOfRecord] = (char) ( strlen(comAppleGCC) +
strlen(gccVersion) +
strlen(comAppleEnd) + 1 + 1 );
strcat(txtRecord, comAppleGCC);
strcat(txtRecord, gccVersion);
strcat(txtRecord, comAppleEnd);
strcat(txtRecord, "\n");
}
}
if ( gccVersion != NULL ) {
free(gccVersion);
}
if ( osType != NULL ) {
free(osType);
}
if ( osRelease != NULL ) {
free(osRelease);
}
return txtRecord;
}
#endif // DARWIN