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