handle Manage_subdevs() for 'external' arrays
[thirdparty/mdadm.git] / msg.c
1 /*
2  * Copyright (C) 2008 Intel Corporation
3  *
4  *      mdmon socket / message handling
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include "mdadm.h"
32
33 enum tx_rx_state {
34         TX_RX_START,
35         TX_RX_SEQ,
36         TX_RX_NUM_BYTES,
37         TX_RX_BUF,
38         TX_RX_END,
39         TX_RX_SUCCESS,
40         TX_RX_ERR,
41 };
42
43 const int start_magic = 0x5a5aa5a5;
44 const int end_magic = 0xa5a55a5a;
45
46 #define txrx(fd, buf, size, flags) (recv_send ? \
47         recv(fd, buf, size, flags) : \
48         send(fd, buf, size, flags))
49
50 /* non-blocking send/receive with n second timeout */
51 static enum tx_rx_state
52 tx_rx_message(int fd, struct md_message *msg, int recv_send, int tmo)
53 {
54         int d = recv_send ? 0 : start_magic;
55         int flags = recv_send ? 0 : MSG_NOSIGNAL;
56         enum tx_rx_state state = TX_RX_START;
57         void *buf = &d;
58         size_t size = sizeof(d);
59         off_t n = 0;
60         int rc;
61         int again;
62
63         do {
64                 again = 0;
65                 rc = txrx(fd, buf + n, size - n, flags);
66                 if (rc <= 0) { /* error */
67                         if (rc == -1 && errno == EAGAIN)
68                                 again = 1;
69                         else
70                                 state = TX_RX_ERR;
71                 } else if (rc + n == size) /* done */
72                         switch (state) {
73                         case TX_RX_START:
74                                 if (recv_send && d != start_magic)
75                                         state = TX_RX_ERR;
76                                 else {
77                                         state = TX_RX_SEQ;
78                                         buf = &msg->seq;
79                                         size = sizeof(msg->seq);
80                                         n = 0;
81                                 }
82                                 break;
83                         case TX_RX_SEQ:
84                                 state = TX_RX_NUM_BYTES;
85                                 buf = &msg->num_bytes;
86                                 size = sizeof(msg->num_bytes);
87                                 n = 0;
88                                 break;
89                         case TX_RX_NUM_BYTES:
90                                 if (msg->num_bytes >
91                                     sizeof(union md_message_commands))
92                                         state = TX_RX_ERR;
93                                 else if (recv_send && msg->num_bytes) {
94                                         msg->buf = malloc(msg->num_bytes);
95                                         if (!msg->buf)
96                                                 state = TX_RX_ERR;
97                                         else {
98                                                 state = TX_RX_BUF;
99                                                 buf = msg->buf;
100                                                 size = msg->num_bytes;
101                                                 n = 0;
102                                         }
103                                 } else if (!recv_send && msg->num_bytes) {
104                                         state = TX_RX_BUF;
105                                         buf = msg->buf;
106                                         size = msg->num_bytes;
107                                         n = 0;
108                                 } else {
109                                         d = recv_send ? 0 : end_magic;
110                                         state = TX_RX_END;
111                                         buf = &d;
112                                         size = sizeof(d);
113                                         n = 0;
114                                 }
115                                 break;
116                         case TX_RX_BUF:
117                                 d = recv_send ? 0 : end_magic;
118                                 state = TX_RX_END;
119                                 buf = &d;
120                                 size = sizeof(d);
121                                 n = 0;
122                                 break;
123                         case TX_RX_END:
124                                 if (recv_send && d != end_magic)
125                                         state = TX_RX_ERR;
126                                 else
127                                         state = TX_RX_SUCCESS;
128                                 break;
129                         case TX_RX_ERR:
130                         case TX_RX_SUCCESS:
131                                 break;
132                         }
133                 else /* continue */
134                         n += rc;
135
136                 if (again) {
137                         fd_set set;
138                         struct timeval timeout = { tmo, 0 };
139                         struct timeval *ptmo = tmo ? &timeout : NULL;
140
141                         FD_ZERO(&set);
142                         FD_SET(fd, &set);
143
144                         if (recv_send)
145                                 rc = select(fd + 1, &set, NULL, NULL, ptmo);
146                         else
147                                 rc = select(fd + 1, NULL, &set, NULL, ptmo);
148
149                         if (rc <= 0)
150                                 state = TX_RX_ERR;
151                 }
152         } while (state < TX_RX_SUCCESS);
153
154         return state;
155 }
156
157
158 int receive_message(int fd, struct md_message *msg, int tmo)
159 {
160         if (tx_rx_message(fd, msg, 1, tmo) == TX_RX_SUCCESS)
161                 return 0;
162         else
163                 return -1;
164 }
165
166 int send_message(int fd, struct md_message *msg, int tmo)
167 {
168         if (tx_rx_message(fd, msg, 0, tmo) == TX_RX_SUCCESS)
169                 return 0;
170         else
171                 return -1;
172 }
173
174 int ack(int fd, int seq, int tmo)
175 {
176         struct md_message msg = { .seq = seq, .num_bytes = 0 };
177
178         return send_message(fd, &msg, tmo);
179 }
180
181 int nack(int fd, int err, int tmo)
182 {
183         struct md_message msg = { .seq = err, .num_bytes = 0 };
184
185         return send_message(fd, &msg, tmo);
186 }
187
188 int send_remove_device(int fd, dev_t rdev, int seq, int tmo)
189 {
190         struct md_remove_device_cmd cmd = { .action = md_action_remove_device,
191                                             .rdev = rdev
192                                           };
193         struct md_message msg = { .seq = seq,
194                                   .num_bytes = sizeof(cmd),
195                                   .buf = &cmd
196                                 };
197
198         return send_message(fd, &msg, tmo);
199 }
200
201 int connect_monitor(char *devname)
202 {
203         char path[100];
204         int sfd;
205         long fl;
206         struct sockaddr_un addr;
207
208         sprintf(path, "/var/run/mdadm/%s.sock", devname);
209         sfd = socket(PF_LOCAL, SOCK_STREAM, 0);
210         if (sfd < 0)
211                 return -1;
212
213         addr.sun_family = PF_LOCAL;
214         strcpy(addr.sun_path, path);
215         if (connect(sfd, &addr, sizeof(addr)) < 0) {
216                 close(sfd);
217                 return -1;
218         }
219
220         fl = fcntl(sfd, F_GETFL, 0);
221         fl |= O_NONBLOCK;
222         fcntl(sfd, F_SETFL, fl);
223
224         return sfd;
225 }
226
227 int ping_monitor(char *devname)
228 {
229         int sfd = connect_monitor(devname);
230         struct md_message msg;
231         int err = 0;
232
233         if (sfd < 0)
234                 return sfd;
235
236         /* try to ping existing socket */
237         if (ack(sfd, 0, 0) != 0)
238                 err = -1;
239
240         /* check the reply */
241         if (!err && receive_message(sfd, &msg, 0) != 0)
242                 err = -1;
243
244         if (msg.seq != 0)
245                 err = -1;
246
247         close(sfd);
248         return err;
249 }