xref: /plan9/sys/src/ape/lib/bsd/rcmd.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
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
ding(int)22 ding(int)
23 {
24 }
25 
26 int
rcmd(char ** dst,int port,char * luser,char * ruser,char * cmd,int * fd2p)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 	lfd = -1;
62 	if(fd2p){
63 		/* create an error stream and wait for a call in */
64 		for(i = 0; i < 10; i++){
65 			lfd = rresvport(&port2);
66 			if(lfd < 0)
67 				continue;
68 			if(listen(lfd, 1) == 0)
69 				break;
70 			close(lfd);
71 		}
72 		if(i >= 10){
73 			fprintf(stderr, pbotch);
74 			return -1;
75 		}
76 
77 		snprintf(buf, sizeof buf, "%d", port2);
78 		if(write(fd, buf, strlen(buf)+1) < 0){
79 			close(fd);
80 			close(lfd);
81 			fprintf(stderr, lbotch);
82 			return -1;
83 		}
84 	} else {
85 		if(write(fd, "", 1) < 0){
86 			fprintf(stderr, pbotch);
87 			return -1;
88 		}
89 	}
90 
91 	/* pass id's and command */
92 	if(write(fd, luser, strlen(luser)+1) < 0
93 	|| write(fd, ruser, strlen(ruser)+1) < 0
94 	|| write(fd, cmd, strlen(cmd)+1) < 0){
95 		fprintf(stderr, pbotch);
96 		return -1;
97 	}
98 
99 	fd2 = -1;
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 			*fd2p = -1;
122 		}
123 		fprintf(stderr, pbotch);
124 		return -1;
125 	}
126 	if(c == 0)
127 		return fd;
128 	i = 0;
129 	while(c){
130 		buf[i++] = c;
131 		if(read(fd, &c, 1) != 1)
132 			break;
133 		if(i >= sizeof(buf)-1)
134 			break;
135 	}
136 	buf[i] = 0;
137 	fprintf(stderr, "rcmd: %s\n", buf);
138 	close(fd);
139 	return -1;
140 }
141