Skip to content

Commit 8b4efc0

Browse files
fhoernisbabic
authored andcommitted
swupdate_async_start: fix early termination blocking in client
It could happen on the client side, that the termination status of the installation was missed, leading to the client waiting forever. This modification connects the progress socket before sending the image payload, to be sure not to miss the termination status (SUCCESS or FAILURE). We also need to consume the events during the image transfer, so that the pipe does not get full and block the daemon. Signed-off-by: Frederic Hoerni <fhoerni@witekio.com>
1 parent a82e037 commit 8b4efc0

File tree

1 file changed

+86
-12
lines changed

1 file changed

+86
-12
lines changed

ipc/network_ipc-if.c

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,54 @@ static void unstack_installation_status(getstatus callback)
102102
} while (ipcmsg.data.status.current != IDLE);
103103
}
104104

105+
/* Consume progress events
106+
*
107+
* Returns:
108+
* -1 error
109+
* FAILURE the installation failed
110+
* SUCCESS the installation suceeded
111+
* 0 no event or other events consumed
112+
*
113+
* On error, progressfd is closed and set to -1.
114+
*/
115+
static int consume_progress_events(int *progressfd)
116+
{
117+
struct progress_msg progressmsg;
118+
int ret = -1;
119+
120+
/* Wait until the end of the installation (FAILURE or SUCCESS) */
121+
while (1) {
122+
int err = progress_ipc_receive_nb(progressfd, &progressmsg);
123+
if (err < 0) {
124+
/* Note that progressfd may have been closed by progress_ipc_receive
125+
* and set to -1 */
126+
fprintf(stderr, "progress_ipc_receive_nb failed (%d)\n", ret);
127+
ret = -1;
128+
break;
129+
} else if (err == 0) {
130+
/* no pending message */
131+
ret = 0;
132+
break;
133+
}
134+
135+
if (progressmsg.status == FAILURE || progressmsg.status == SUCCESS) {
136+
/* We have the final result of the installation */
137+
ret = progressmsg.status;
138+
break;
139+
} else {
140+
/* Other status (START, RUN, PROGRESS) */
141+
/* continue consuming messages */
142+
continue;
143+
}
144+
}
145+
146+
if (ret == -1 && *progressfd >= 0) {
147+
close(*progressfd);
148+
*progressfd = -1;
149+
}
150+
151+
return ret;
152+
}
105153

106154
static void *swupdate_async_thread(void *data)
107155
{
@@ -113,6 +161,8 @@ static void *swupdate_async_thread(void *data)
113161
struct async_lib *rq = (struct async_lib *)data;
114162
int swupdate_result = FAILURE;
115163
int progressfd = -1;
164+
int ret;
165+
int early_status = -1;
116166

117167
sigemptyset(&sigpipe_mask);
118168
sigaddset(&sigpipe_mask, SIGPIPE);
@@ -122,6 +172,16 @@ static void *swupdate_async_thread(void *data)
122172
swupdate_result = FAILURE;
123173
goto out;
124174
}
175+
/* Start listening to progress events, before sending
176+
* the image so that we don't miss the result event.
177+
*/
178+
progressfd = progress_ipc_connect(0 /* no reconnect */);
179+
if (progressfd < 0) {
180+
fprintf(stderr, "progress_ipc_connect failed\n");
181+
ipc_end(rq->connfd);
182+
goto out;
183+
}
184+
125185
/* Start writing the image until end */
126186

127187
do {
@@ -136,26 +196,40 @@ static void *swupdate_async_thread(void *data)
136196
goto out;
137197
}
138198
}
199+
/* Consume progress events so that the pipe does not get full
200+
* and block the daemon */
201+
ret = consume_progress_events(&progressfd);
202+
if (ret == -1) {
203+
/* If we cannot get events, then we won't be able to get the result.
204+
* Quit and fail */
205+
fprintf(stderr, "Cannot consume progress events. Fail.\n");
206+
early_status = FAILURE;
207+
break;
208+
} else if (ret == FAILURE || ret == SUCCESS) {
209+
/* early termination */
210+
fprintf(stderr, "early termination while sending the image: %s\n",
211+
ret==SUCCESS?"SUCCESS":"FAILURE");
212+
early_status = ret;
213+
/* interrupt the transfer */
214+
break;
215+
}
139216
} while(size > 0);
140217

141-
/* Start listening to progress events, before ipc_end
142-
* so that we don't miss the result event.
143-
*/
144-
progressfd = progress_ipc_connect(0 /* no reconnect */);
145-
146218
ipc_end(rq->connfd);
147219

148-
if (progressfd < 0) {
149-
fprintf(stderr, "progress_ipc_connect failed\n");
150-
goto out;
151-
}
152-
153220
/*
154221
* Everything sent, wait for completion of the installation
155222
*/
156223

157-
/* Wait until the end of the installation and get the final result */
158-
swupdate_result = inst_wait_for_complete(&progressfd); /* progressfd closed by the call */
224+
if (early_status >= 0) {
225+
swupdate_result = early_status;
226+
close(progressfd);
227+
progressfd = -1;
228+
229+
} else {
230+
/* Wait until the end of the installation and get the final result */
231+
swupdate_result = inst_wait_for_complete(&progressfd); /* progressfd closed by the call */
232+
}
159233

160234
/*
161235
* Get and print all status lines, for compatibility with legacy programs

0 commit comments

Comments
 (0)