show version
[tridge/junkcode.git] / sock_exec.c
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13
14 #define BOOL int
15
16 /****************************************************************************
17 Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
18 else
19 if SYSV use O_NDELAY
20 if BSD use FNDELAY
21 ****************************************************************************/
22 int set_blocking(int fd, BOOL set)
23 {
24   int val;
25 #ifdef O_NONBLOCK
26 #define FLAG_TO_SET O_NONBLOCK
27 #else
28 #ifdef SYSV
29 #define FLAG_TO_SET O_NDELAY
30 #else /* BSD */
31 #define FLAG_TO_SET FNDELAY
32 #endif
33 #endif
34
35   if((val = fcntl(fd, F_GETFL, 0)) == -1)
36         return -1;
37   if(set) /* Turn blocking on - ie. clear nonblock flag */
38         val &= ~FLAG_TO_SET;
39   else
40     val |= FLAG_TO_SET;
41   return fcntl( fd, F_SETFL, val);
42 #undef FLAG_TO_SET
43 }
44
45 /*******************************************************************
46 this is like socketpair but uses tcp. It is used by the Samba
47 regression test code
48 The function guarantees that nobody else can attach to the socket,
49 or if they do that this function fails and the socket gets closed
50 returns 0 on success, -1 on failure
51 the resulting file descriptors are symmetrical
52  ******************************************************************/
53 static int socketpair_tcp(int fd[2])
54 {
55         int listener;
56         struct sockaddr sock;
57         struct sockaddr_in sock2;
58         socklen_t socklen = sizeof(sock);
59         int connect_done = 0;
60         
61         fd[0] = fd[1] = listener = -1;
62
63         memset(&sock, 0, sizeof(sock));
64         
65         if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
66
67         memset(&sock2, 0, sizeof(sock2));
68 #ifdef HAVE_SOCK_SIN_LEN
69         sock2.sin_len = sizeof(sock2);
70 #endif
71         sock2.sin_family = PF_INET;
72
73         bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
74
75         if (listen(listener, 1) != 0) goto failed;
76
77         if (getsockname(listener, &sock, &socklen) != 0) goto failed;
78
79         if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
80
81         set_blocking(fd[1], 0);
82
83         if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
84                 if (errno != EINPROGRESS) goto failed;
85         } else {
86                 connect_done = 1;
87         }
88
89         if ((fd[0] = accept(listener, &sock, &socklen)) == -1) goto failed;
90
91         close(listener);
92         if (connect_done == 0) {
93                 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
94                     && errno != EISCONN) goto failed;
95         }
96
97         set_blocking(fd[1], 1);
98
99         /* all OK! */
100         return 0;
101
102  failed:
103         if (fd[0] != -1) close(fd[0]);
104         if (fd[1] != -1) close(fd[1]);
105         if (listener != -1) close(listener);
106         return -1;
107 }
108
109
110 /*******************************************************************
111 run a program on a local tcp socket, this is used to launch smbd
112 when regression testing
113 the return value is a socket which is attached to a subprocess
114 running "prog". stdin and stdout are attached. stderr is left
115 attached to the original stderr
116  ******************************************************************/
117 int sock_exec(const char *prog)
118 {
119         int fd[2];
120         if (socketpair_tcp(fd) != 0) return -1;
121         if (fork() == 0) {
122                 close(fd[0]);
123                 close(0);
124                 close(1);
125                 dup(fd[1]);
126                 dup(fd[1]);
127                 exit(system(prog));
128         }
129         close(fd[1]);
130         return fd[0];
131 }
132
133
134 int main(int argc, char *argv[])
135 {
136         int fd;
137         char buf[100];
138         int n;
139
140         fd = sock_exec(argv[1]);
141
142         while ((n = read(fd, buf, sizeof(buf))) > 0) {
143                 write(1, buf, n);
144         }
145         return 0;
146 }