xref: /plan9/sys/src/ape/lib/bsd/rcmd.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 /* posix */
2 #include <sys/types.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <signal.h>
9 
10 /* socket extensions */
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <sys/un.h>
14 #include <netdb.h>
15 
16 #include "priv.h"
17 
18 static char *pbotch = "rcmd: protocol botch\n";
19 static char *lbotch = "rcmd: botch starting error stream\n";
20 
21 static void
22 ding(int x)
23 {
24 }
25 
26 int
27 rcmd(char **dst, int port, char *luser, char *ruser, char *cmd, int *fd2p)
28 {
29 	char c;
30 	int i, fd, lfd, fd2, port2;
31 	struct hostent *h;
32 	Rock *r;
33 	struct sockaddr_in in;
34 	char buf[128];
35 	void	(*x)(int);
36 
37 	h = gethostbyname(*dst);
38 	if(h == 0)
39 		return -1;
40 	*dst = h->h_name;
41 
42 	/* connect using a reserved tcp port */
43 	fd = socket(PF_INET, SOCK_STREAM, 0);
44 	if(fd < 0)
45 		return -1;
46 	r = _sock_findrock(fd, 0);
47 	if(r == 0){
48 		errno = ENOTSOCK;
49 		return -1;
50 	}
51 	r->reserved = 1;
52 	in.sin_family = AF_INET;
53 	in.sin_port = htons(port);
54 	memmove(&in.sin_addr, h->h_addr_list[0], sizeof(in.sin_addr));
55 	if(connect(fd, &in, sizeof(in)) < 0){
56 		close(fd);
57 		return -1;
58 	}
59 
60 	/* error stream */
61 	if(fd2p){
62 		/* create an error stream and wait for a call in */
63 		for(i = 0; i < 10; i++){
64 			lfd = rresvport(&port2);
65 			if(lfd < 0)
66 				continue;
67 			if(listen(lfd, 1) == 0)
68 				break;
69 			close(lfd);
70 		}
71 		if(i >= 10){
72 			fprintf(stderr, pbotch);
73 			return -1;
74 		}
75 
76 		sprintf(buf, "%d", port2);
77 		if(write(fd, buf, strlen(buf)+1) < 0){
78 			close(fd);
79 			close(lfd);
80 			fprintf(stderr, lbotch);
81 			return -1;
82 		}
83 	} else {
84 		if(write(fd, "", 1) < 0){
85 			fprintf(stderr, pbotch);
86 			return -1;
87 		}
88 	}
89 
90 	/* pass id's and command */
91 	if(write(fd, luser, strlen(luser)+1) < 0
92 	|| write(fd, ruser, strlen(ruser)+1) < 0
93 	|| write(fd, cmd, strlen(cmd)+1) < 0){
94 		if(fd2p)
95 			close(fd2);
96 		fprintf(stderr, pbotch);
97 		return -1;
98 	}
99 
100 	if(fd2p){
101 		x = signal(SIGALRM, ding);
102 		alarm(15);
103 		fd2 = accept(lfd, &in, &i);
104 		alarm(0);
105 		close(lfd);
106 		signal(SIGALRM, x);
107 
108 		if(fd2 < 0){
109 			close(fd);
110 			close(lfd);
111 			fprintf(stderr, lbotch);
112 			return -1;
113 		}
114 		*fd2p = fd2;
115 	}
116 
117 	/* get reply */
118 	if(read(fd, &c, 1) != 1){
119 		if(fd2p)
120 			close(fd2);
121 		fprintf(stderr, pbotch);
122 		return -1;
123 	}
124 	if(c == 0)
125 		return fd;
126 	i = 0;
127 	while(c){
128 		buf[i++] = c;
129 		if(read(fd, &c, 1) != 1)
130 			break;
131 		if(i >= sizeof(buf)-1)
132 			break;
133 	}
134 	buf[i] = 0;
135 	fprintf(stderr, "rcmd: %s\n", buf);
136 	close(fd);
137 	return -1;
138 }
139