1 /* cvm/client_xfer_command.c - CVM client command transmission library
2 * Copyright (C) 2010 Bruce Guenter <bruce@untroubled.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <sys/types.h>
19 #include <netdb.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25
26 #include <bglibs/sysdeps.h>
27
28 #include "v1client.h"
29
30 static pid_t pid;
31
32 /* Command module execution **************************************************/
pipefork(const char * cmd,int pipes[2])33 static int pipefork(const char* cmd, int pipes[2])
34 {
35 int pipe1[2];
36 int pipe2[2];
37
38 if (pipe(pipe1) == -1 || pipe(pipe2) == -2) return 0;
39 pid = fork();
40 switch (pid) {
41 case -1:
42 return 0;
43 case 0:
44 close(0);
45 close(pipe1[1]);
46 dup2(pipe1[0], 0);
47 close(pipe1[0]);
48 close(1);
49 close(pipe2[0]);
50 dup2(pipe2[1], 1);
51 close(pipe2[1]);
52 execlp(cmd, cmd, NULL);
53 exit(1);
54 default:
55 close(pipe1[0]);
56 pipes[0] = pipe1[1];
57 close(pipe2[1]);
58 pipes[1] = pipe2[0];
59 return 1;
60 }
61 }
62
killit(void)63 static void killit(void)
64 {
65 if (pid != -1)
66 kill(pid, SIGTERM);
67 }
68
waitforit(void)69 static int waitforit(void)
70 {
71 int status;
72 pid_t tmp;
73 while ((tmp = wait(&status)) != -1) {
74 if (tmp == pid)
75 return WIFEXITED(status) ? WEXITSTATUS(status) : -CVME_IO;
76 }
77 return -CVME_IO;
78 }
79
write_buffer(int fd,const unsigned char * buffer,unsigned buflen)80 static int write_buffer(int fd, const unsigned char* buffer, unsigned buflen)
81 {
82 size_t wr;
83
84 while (buflen > 0) {
85 wr = write(fd, buffer, buflen);
86 if (wr == 0 || wr == (unsigned)-1) return 0;
87 buflen -= wr;
88 buffer += wr;
89 }
90 return 1;
91 }
92
read_buffer(int fd,unsigned char * buffer)93 static unsigned read_buffer(int fd, unsigned char* buffer)
94 {
95 size_t rd;
96 unsigned buflen;
97
98 for (buflen = 0; buflen < CVM_BUFSIZE; buffer += rd, buflen += rd) {
99 rd = read(fd, buffer, CVM_BUFSIZE-buflen);
100 if (rd == (unsigned)-1) return 0;
101 if (rd == 0) break;
102 }
103 return buflen;
104 }
105
cvm_xfer_command_packets(const char * module,const struct cvm_packet * request,struct cvm_packet * response)106 unsigned cvm_xfer_command_packets(const char* module,
107 const struct cvm_packet* request,
108 struct cvm_packet* response)
109 {
110 int pipes[2];
111 int result;
112
113 if (!pipefork(module, pipes)) return CVME_IO;
114
115 if (!write_buffer(pipes[0], request->data, request->length) ||
116 close(pipes[0]) == -1 ||
117 (response->length = read_buffer(pipes[1], response->data)) == 0 ||
118 close(pipes[1]) == -1) {
119 killit();
120 if ((result = waitforit()) < 0)
121 return -result;
122 return CVME_IO;
123 }
124
125 if ((result = waitforit()) < 0)
126 return -result;
127 response->data[0] = result;
128 return 0;
129 }
130