]> git.ipfire.org Git - thirdparty/mdadm.git/blob - msg.c
Add some comments to explain some of the bits of superswitch.
[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 }