summaryrefslogtreecommitdiff
path: root/src/helper/slbt_dump_machine.c
blob: 0704386c7119b22e45daccb096c9e9e37cd9a2c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*******************************************************************/
/*  slibtool: a skinny libtool implementation, written in C        */
/*  Copyright (C) 2016  Z. Gilboa                                  */
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
/*******************************************************************/

#include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/wait.h>

#include <slibtool/slibtool.h>
#include "slibtool_spawn_impl.h"

static void slbt_dump_machine_child(
	char *	program,
	int	fd[2])
{
	char *	compiler;
	char *	argv[3];

	if ((compiler = strchr(program,'/')))
		compiler++;
	else
		compiler = program;

	argv[0] = compiler;
	argv[1] = "-dumpmachine";
	argv[2] = 0;

	close(fd[0]);
	close(0);
	close(1);

	if ((fd[0] = open("/dev/null",O_RDONLY)))
		exit(EXIT_FAILURE);

	if (dup(fd[1]) == 1)
		execvp(program,argv);

	exit(EXIT_FAILURE);
}

int slbt_dump_machine(
	const char *	compiler,
	char *		machine,
	size_t		bufsize)
{
	pid_t	pid;
	pid_t	rpid;
	int	code;
	int	fd[2];
	FILE *	fmachine;
	char *	newline;
	char *	mark;
	char	check[2];
	char	program[PATH_MAX];

	if (!machine || !bufsize)
		return -1;

	if ((size_t)snprintf(program,sizeof(program),"%s",
			compiler) >= sizeof(program))
		return -1;

	if (pipe(fd))
		return -1;

	if ((pid = fork()) < 0) {
		close(fd[0]);
		close(fd[1]);
		return -1;
	}

	if (pid == 0)
		slbt_dump_machine_child(
			program,
			fd);

	rpid = waitpid(
		pid,
		&code,
		0);

	if ((rpid != pid) || code) {
		close(fd[0]);
		close(fd[1]);
		return -1;
	}

	if ((fmachine = fdopen(fd[0],"r"))) {
		close(fd[1]);
		newline = 0;

		if (fgets(machine,bufsize,fmachine) == machine)
			if (!fgets(check,sizeof(check),fmachine))
				if (feof(fmachine))
					if ((newline = strrchr(machine,'\n')))
						*newline = 0;

		fclose(fmachine);
	} else {
		newline = 0;
		close(fd[0]);
		close(fd[1]);
	}

	/* support the portbld <--> unknown synonym */
	if (newline)
		if ((mark = strstr(machine,"-portbld-")))
			memcpy(mark,"-unknown",8);

	return newline ? 0 : -1;
}