1 /*****************************************************************************\
2  **  pmi1.c - PMI1 client(task) command handling
3  *****************************************************************************
4  *  Copyright (C) 2011-2012 National University of Defense Technology.
5  *  Written by Hongjia Cao <hjcao@nudt.edu.cn>.
6  *  All rights reserved.
7  *
8  *  This file is part of Slurm, a resource management program.
9  *  For details, see <https://slurm.schedmd.com/>.
10  *  Please also read the included file: DISCLAIMER.
11  *
12  *  Slurm is free software; you can redistribute it and/or modify it under
13  *  the terms of the GNU General Public License as published by the Free
14  *  Software Foundation; either version 2 of the License, or (at your option)
15  *  any later version.
16  *
17  *  In addition, as a special exception, the copyright holders give permission
18  *  to link the code of portions of this program with the OpenSSL library under
19  *  certain conditions as described in each individual source file, and
20  *  distribute linked combinations including the two. You must obey the GNU
21  *  General Public License in all respects for all of the code used other than
22  *  OpenSSL. If you modify file(s) with this exception, you may extend this
23  *  exception to your version of the file(s), but you are not obligated to do
24  *  so. If you do not wish to do so, delete this exception statement from your
25  *  version.  If you delete this exception statement from all source files in
26  *  the program, then also delete it here.
27  *
28  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
29  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
31  *  details.
32  *
33  *  You should have received a copy of the GNU General Public License along
34  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
35  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
36 \*****************************************************************************/
37 
38 #include "config.h"
39 
40 #if defined(__FreeBSD__) || defined(__DragonFly__)
41 #include <sys/socket.h> /* AF_INET */
42 #endif
43 
44 #include <fcntl.h>
45 #include <signal.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/types.h>
49 
50 #include "slurm/slurm_errno.h"
51 
52 #include "src/common/slurm_xlator.h"
53 #include "src/common/xmalloc.h"
54 #include "src/common/log.h"
55 
56 #include "pmi.h"
57 #include "client.h"
58 #include "spawn.h"
59 #include "setup.h"
60 #include "kvs.h"
61 #include "agent.h"
62 #include "nameserv.h"
63 
64 /* client command handlers */
65 static int _handle_get_maxes(int fd, int lrank, client_req_t *req);
66 static int _handle_get_universe_size(int fd, int lrank, client_req_t *req);
67 static int _handle_get_appnum(int fd, int lrank, client_req_t *req);
68 static int _handle_barrier_in(int fd, int lrank, client_req_t *req);
69 static int _handle_finalize(int fd, int lrank, client_req_t *req);
70 static int _handle_abort(int fd, int lrank, client_req_t *req);
71 static int _handle_get_my_kvsname(int fd, int lrank, client_req_t *req);
72 static int _handle_create_kvs(int fd, int lrank, client_req_t *req);
73 static int _handle_destroy_kvs(int fd, int lrank, client_req_t *req);
74 static int _handle_put(int fd, int lrank, client_req_t *req);
75 static int _handle_get(int fd, int lrank, client_req_t *req);
76 static int _handle_getbyidx(int fd, int lrank ,client_req_t *req);
77 static int _handle_publish_name(int fd, int lrank, client_req_t *req);
78 static int _handle_unpublish_name(int fd, int lrank, client_req_t *req);
79 static int _handle_lookup_name(int fd, int lrank, client_req_t *req);
80 static int _handle_mcmd(int fd, int lrank, client_req_t *req);
81 
82 static struct {
83 	char *cmd;
84 	int (*handler)(int fd, int lrank, client_req_t *req);
85 } pmi1_cmd_handlers[] = {
86 	{ GETMAXES_CMD,          _handle_get_maxes },
87 	{ GETUNIVSIZE_CMD,       _handle_get_universe_size },
88 	{ GETAPPNUM_CMD,         _handle_get_appnum },
89 	{ BARRIERIN_CMD,         _handle_barrier_in },
90 	{ FINALIZE_CMD,          _handle_finalize },
91 	{ ABORT_CMD,             _handle_abort },
92 	{ GETMYKVSNAME_CMD,      _handle_get_my_kvsname },
93 	{ CREATEKVS_CMD,         _handle_create_kvs },
94 	{ DESTROYKVS_CMD,        _handle_destroy_kvs },
95 	{ PUT_CMD,               _handle_put },
96 	{ GET_CMD,               _handle_get },
97 	{ GETBYIDX_CMD,          _handle_getbyidx },
98 	{ PUBLISHNAME_CMD,       _handle_publish_name },
99 	{ UNPUBLISHNAME_CMD,     _handle_unpublish_name },
100 	{ LOOKUPNAME_CMD,        _handle_lookup_name },
101 	{ MCMD_CMD,              _handle_mcmd },
102 	{ NULL, NULL},
103 };
104 
105 static spawn_req_t *pmi1_spawn = NULL;
106 
107 static int
_handle_get_maxes(int fd,int lrank,client_req_t * req)108 _handle_get_maxes(int fd, int lrank, client_req_t *req)
109 {
110 	int rc = 0;
111 	client_resp_t *resp;
112 
113 	debug3("mpi/pmi2: in _handle_get_maxes");
114 
115 	resp = client_resp_new();
116 	client_resp_append(resp, CMD_KEY"="MAXES_CMD" " RC_KEY"=%d "
117 			   KVSNAMEMAX_KEY"=%d " KEYLENMAX_KEY"=%d "
118 			   VALLENMAX_KEY"=%d\n",
119 			   rc, MAXKVSNAME, MAXKEYLEN, MAXVALLEN);
120 	(void) client_resp_send(resp, fd);
121 	client_resp_free(resp);
122 
123 	debug3("mpi/pmi2: out _handle_get_maxes");
124 	return SLURM_SUCCESS;
125 }
126 
127 static int
_handle_get_universe_size(int fd,int lrank,client_req_t * req)128 _handle_get_universe_size(int fd, int lrank, client_req_t *req)
129 {
130 	int rc = 0;
131 	client_resp_t *resp;
132 
133 	debug3("mpi/pmi2: in _handle_get_universe_size");
134 
135 	resp = client_resp_new();
136 	client_resp_append(resp, CMD_KEY"="UNIVSIZE_CMD" " RC_KEY"=%d "
137 			   SIZE_KEY"=%d\n",
138 			   rc, job_info.ntasks);
139 	(void) client_resp_send(resp, fd);
140 	client_resp_free(resp);
141 
142 	debug3("mpi/pmi2: out _handle_get_universe_size");
143 	return SLURM_SUCCESS;
144 }
145 
146 static int
_handle_get_appnum(int fd,int lrank,client_req_t * req)147 _handle_get_appnum(int fd, int lrank, client_req_t *req)
148 {
149 	int rc = 0;
150 	client_resp_t *resp;
151 
152 	debug3("mpi/pmi2: in _handle_get_appnum");
153 
154 	resp = client_resp_new();
155 	/*
156 	 * TODO: spawn_multiple: order number of command
157 	 *       spawn: 0
158 	 *       otherwise: -1, since no way to get the order
159 	 *         number from multi-prog conf
160 	 */
161 	client_resp_append(resp, CMD_KEY"="APPNUM_CMD" " RC_KEY"=%d "
162 			   APPNUM_KEY"=-1\n", rc);
163 	(void) client_resp_send(resp, fd);
164 	client_resp_free(resp);
165 
166 	debug3("mpi/pmi2: out _handle_get_appnum");
167 	return SLURM_SUCCESS;
168 }
169 
170 static int
_handle_barrier_in(int fd,int lrank,client_req_t * req)171 _handle_barrier_in(int fd, int lrank, client_req_t *req)
172 {
173 	int rc = 0;
174 
175 	debug3("mpi/pmi2: in _handle_barrier_in, from task %d",
176 	       job_info.gtids[lrank]);
177 	if (tasks_to_wait == 0 && children_to_wait == 0) {
178 		tasks_to_wait = job_info.ltasks;
179 		children_to_wait = tree_info.num_children;
180 	}
181 	tasks_to_wait --;
182 
183 	/* mutex protection is not required */
184 	if (tasks_to_wait == 0 && children_to_wait == 0) {
185 		rc = temp_kvs_send();
186 		if (rc != SLURM_SUCCESS) {
187 			error("mpi/pmi2: failed to send temp kvs to %s",
188 			      tree_info.parent_node ?: "srun");
189 			send_kvs_fence_resp_to_clients(
190 				rc,
191 				"mpi/pmi2: failed to send temp kvs");
192 			/* cancel the step to avoid tasks hang */
193 			slurm_kill_job_step(job_info.jobid, job_info.stepid,
194 					    SIGKILL);
195 		} else {
196 			waiting_kvs_resp = 1;
197 		}
198 	}
199 	debug3("mpi/pmi2: out _handle_barrier_in, tasks_to_wait=%d, "
200 	       "children_to_wait=%d", tasks_to_wait, children_to_wait);
201 	return rc;
202 }
203 
204 static int
_handle_finalize(int fd,int lrank,client_req_t * req)205 _handle_finalize(int fd, int lrank, client_req_t *req)
206 {
207 	client_resp_t *resp;
208 	int rc = 0;
209 
210 	debug3("mpi/pmi2: in _handle_finalize");
211 	resp = client_resp_new();
212 	client_resp_append(resp, CMD_KEY"="FINALIZEACK_CMD" "
213 			RC_KEY"=%d\n", rc);
214 	rc = client_resp_send(resp, fd);
215 	client_resp_free(resp);
216 	debug3("mpi/pmi2: out _handle_finalize");
217 	/* shutdown the PMI fd */
218 	shutdown(fd, SHUT_RDWR);
219 	close(fd);
220 	task_finalize(lrank);
221 	return rc;
222 }
223 
224 static int
_handle_abort(int fd,int lrank,client_req_t * req)225 _handle_abort(int fd, int lrank, client_req_t *req)
226 {
227 	debug3("mpi/pmi2: in _handle_abort");
228 	/* no response needed. just cancel the job */
229 	slurm_kill_job_step(job_info.jobid, job_info.stepid, SIGKILL);
230 	debug3("mpi/pmi2: out _handle_abort");
231 	return SLURM_SUCCESS;
232 }
233 
234 static int
_handle_get_my_kvsname(int fd,int lrank,client_req_t * req)235 _handle_get_my_kvsname(int fd, int lrank, client_req_t *req)
236 {
237 	client_resp_t *resp;
238 	int rc = 0;
239 
240 	debug3("mpi/pmi2: in _handle_get_my_kvsname");
241 	resp = client_resp_new();
242 	client_resp_append(resp, CMD_KEY"="GETMYKVSNAMERESP_CMD" "
243 			   RC_KEY"=%d " KVSNAME_KEY"=%u.%u\n",
244 			   rc, job_info.jobid, job_info.stepid);
245 	rc = client_resp_send(resp, fd);
246 	client_resp_free(resp);
247 	debug3("mpi/pmi2: out _handle_get_my_kvsname");
248 	return rc;
249 }
250 
251 static int
_handle_create_kvs(int fd,int lrank,client_req_t * req)252 _handle_create_kvs(int fd, int lrank, client_req_t *req)
253 {
254 	/* not used in MPICH2 */
255 	error("mpi/pmi2: PMI1 request of '" CREATEKVS_CMD "' not supported");
256 	return SLURM_ERROR;
257 }
258 
259 static int
_handle_destroy_kvs(int fd,int lrank,client_req_t * req)260 _handle_destroy_kvs(int fd, int lrank, client_req_t *req)
261 {
262 	/* not used in MPICH2 */
263 	error("mpi/pmi2: PMI1 request of '" DESTROYKVS_CMD "' not supported");
264 	return SLURM_ERROR;
265 }
266 
267 
268 static int
_handle_put(int fd,int lrank,client_req_t * req)269 _handle_put(int fd, int lrank, client_req_t *req)
270 {
271 	int rc = SLURM_SUCCESS;
272 	client_resp_t *resp;
273 	char *kvsname = NULL, *key = NULL, *val = NULL;
274 
275 	debug3("mpi/pmi2: in _handle_put");
276 
277 	client_req_parse_body(req);
278 	client_req_get_str(req, KVSNAME_KEY, &kvsname); /* not used */
279 	client_req_get_str(req, KEY_KEY, &key);
280 	client_req_get_str(req, VALUE_KEY, &val);
281 	xfree(kvsname);
282 
283 	/* no need to add k-v to hash. just get it ready to be up-forward */
284 	rc = temp_kvs_add(key, val);
285 	xfree(key);
286 	xfree(val);
287 	if (rc == SLURM_SUCCESS)
288 		rc = 0;
289 	else
290 		rc = 1;
291 
292 	resp = client_resp_new();
293 	client_resp_append(resp, CMD_KEY"="PUTRESULT_CMD" " RC_KEY"=%d\n", rc);
294 	rc = client_resp_send(resp, fd);
295 	client_resp_free(resp);
296 
297 	debug3("mpi/pmi2: out _handle_put");
298 	return rc;
299 }
300 
301 static int
_handle_get(int fd,int lrank,client_req_t * req)302 _handle_get(int fd, int lrank, client_req_t *req)
303 {
304 	int rc;
305 	client_resp_t *resp;
306 	char *kvsname = NULL, *key = NULL, *val = NULL;
307 
308 	debug3("mpi/pmi2: in _handle_get");
309 
310 	client_req_parse_body(req);
311 	client_req_get_str(req, KVSNAME_KEY, &kvsname); /* not used */
312 	client_req_get_str(req, KEY_KEY, &key);
313 	xfree(kvsname);
314 
315 	val = kvs_get(key);
316 	xfree(key);
317 
318 	resp = client_resp_new();
319 	if (val != NULL) {
320 		client_resp_append(resp, CMD_KEY"="GETRESULT_CMD" "
321 				   RC_KEY"=0 " VALUE_KEY"=%s\n", val);
322 	} else {
323 		client_resp_append(resp, CMD_KEY"="GETRESULT_CMD" "
324 				   RC_KEY"=1\n");
325 	}
326 	rc = client_resp_send(resp, fd);
327 	client_resp_free(resp);
328 
329 	debug3("mpi/pmi2: out _handle_get");
330 	return rc;
331 }
332 
333 
334 static int
_handle_getbyidx(int fd,int lrank,client_req_t * req)335 _handle_getbyidx(int fd, int lrank, client_req_t *req)
336 {
337 	/* not used in MPICH2 */
338 	error("mpi/pmi2: PMI1 request of '" GETBYIDX_CMD "' not supported");
339 
340 	return SLURM_ERROR;
341 }
342 
343 static int
_handle_publish_name(int fd,int lrank,client_req_t * req)344 _handle_publish_name(int fd, int lrank, client_req_t *req)
345 {
346 	int rc;
347 	client_resp_t *resp;
348 	char *service = NULL, *port = NULL;
349 
350 	debug3("mpi/pmi2: in _handle_publish_name");
351 
352 	client_req_parse_body(req);
353 	client_req_get_str(req, SERVICE_KEY, &service);
354 	client_req_get_str(req, PORT_KEY, &port);
355 
356 	rc = name_publish_up(service, port);
357 	xfree(service);
358 	xfree(port);
359 
360 	resp = client_resp_new();
361 	client_resp_append(resp, CMD_KEY"="PUBLISHRESULT_CMD" "
362 			   INFO_KEY"=%s\n",
363 			   rc == SLURM_SUCCESS ? "ok" : "fail");
364 	rc = client_resp_send(resp, fd);
365 	client_resp_free(resp);
366 
367 	debug3("mpi/pmi2: out _handle_publish_name");
368 	return rc;
369 }
370 
371 static int
_handle_unpublish_name(int fd,int lrank,client_req_t * req)372 _handle_unpublish_name(int fd, int lrank, client_req_t *req)
373 {
374 	int rc;
375 	client_resp_t *resp;
376 	char *service = NULL;
377 
378 	debug3("mpi/pmi2: in _handle_unpublish_name");
379 
380 	client_req_parse_body(req);
381 	client_req_get_str(req, SERVICE_KEY, &service);
382 
383 	rc = name_unpublish_up(service);
384 	xfree(service);
385 
386 	resp = client_resp_new();
387 	client_resp_append(resp, CMD_KEY"="UNPUBLISHRESULT_CMD" "
388 			   INFO_KEY"=%s\n",
389 			   rc == SLURM_SUCCESS ? "ok" : "fail");
390 	rc = client_resp_send(resp, fd);
391 	client_resp_free(resp);
392 
393 	debug3("mpi/pmi2: out _handle_unpublish_name");
394 	return rc;
395 }
396 
397 /*
398  * this design is not scalable: each task that calls MPI_Lookup_name()
399  * will generate a RPC to srun.
400  */
401 static int
_handle_lookup_name(int fd,int lrank,client_req_t * req)402 _handle_lookup_name(int fd, int lrank, client_req_t *req)
403 {
404 	int rc;
405 	client_resp_t *resp;
406 	char *service = NULL, *port = NULL;
407 
408 	debug3("mpi/pmi2: in _handle_lookup_name");
409 
410 	client_req_parse_body(req);
411 	client_req_get_str(req, SERVICE_KEY, &service);
412 
413 	port = name_lookup_up(service);
414 
415 	resp = client_resp_new();
416 	client_resp_append(resp, CMD_KEY"="LOOKUPRESULT_CMD" ");
417 	if (port == NULL) {
418 		client_resp_append(resp, INFO_KEY"=fail\n");
419 	} else {
420 		client_resp_append(resp, INFO_KEY"=ok "PORT_KEY"=%s\n",
421 				   port);
422 	}
423 	rc = client_resp_send(resp, fd);
424 	client_resp_free(resp);
425 
426 	xfree(service);
427 	xfree(port);
428 
429 	debug3("mpi/pmi2: out _handle_lookup_name");
430 	return rc;
431 }
432 
433 static int
_handle_mcmd(int fd,int lrank,client_req_t * req)434 _handle_mcmd(int fd, int lrank, client_req_t *req)
435 {
436 	spawn_subcmd_t *subcmd = NULL;
437 	spawn_resp_t *spawn_resp = NULL;
438 	client_resp_t *task_resp = NULL;
439 	int spawnssofar = 0, rc = SLURM_SUCCESS, i;
440 	char buf[64];
441 
442 	debug3("mpi/pmi2: in _handle_mcmd");
443 
444 	client_req_parse_body(req);
445 	subcmd = client_req_parse_spawn_subcmd(req);
446 
447 	debug3("mpi/pmi2: got subcmd");
448 
449 	client_req_get_int(req, SPAWNSSOFAR_KEY, &spawnssofar);
450 	if (spawnssofar == 1) {
451 		pmi1_spawn = spawn_req_new();
452 		client_req_get_int(req, TOTSPAWNS_KEY,
453 				   (int *)&pmi1_spawn->subcmd_cnt);
454 		pmi1_spawn->subcmds = xmalloc(pmi1_spawn->subcmd_cnt *
455 					      sizeof(spawn_subcmd_t *));
456 		client_req_get_int(req, PREPUTNUM_KEY,
457 				   (int *)&pmi1_spawn->preput_cnt);
458 		pmi1_spawn->pp_keys =
459 			xmalloc(pmi1_spawn->preput_cnt * sizeof(char *));
460 		pmi1_spawn->pp_vals =
461 			xmalloc(pmi1_spawn->preput_cnt * sizeof(char *));
462 		for (i = 0; i < pmi1_spawn->preput_cnt; i ++) {
463 			snprintf(buf, 64, PREPUTKEY_KEY"%d", i);
464 			client_req_get_str(req, buf, &pmi1_spawn->pp_keys[i]);
465 			snprintf(buf, 64, PREPUTVAL_KEY"%d", i);
466 			client_req_get_str(req, buf, &pmi1_spawn->pp_vals[i]);
467 		}
468 	}
469 	pmi1_spawn->subcmds[spawnssofar - 1] = subcmd;
470 
471 	if (spawnssofar == pmi1_spawn->subcmd_cnt) {
472 		debug3("mpi/pmi2: got whole spawn req");
473 		/* a resp will be send back from srun.
474 		   this will not be forwarded to the tasks */
475 		rc = spawn_req_send_to_srun(pmi1_spawn, &spawn_resp);
476 		if (spawn_resp->rc != SLURM_SUCCESS) {
477 			task_resp = client_resp_new();
478 			client_resp_append(task_resp, CMD_KEY"="SPAWNRESP_CMD";"
479 					   RC_KEY"=%d;"
480 					   ERRMSG_KEY"=spawn failed;",
481 					   spawn_resp->rc);
482 			client_resp_send(task_resp, fd);
483 			client_resp_free(task_resp);
484 
485 			spawn_resp_free(spawn_resp);
486 			spawn_req_free(pmi1_spawn);
487 			pmi1_spawn = NULL;
488 			error("mpi/pmi2: spawn failed");
489 			rc = SLURM_ERROR;
490 			goto out;
491 		}
492 
493 		debug("mpi/pmi2: spawn request sent to srun");
494 		spawn_psr_enqueue(spawn_resp->seq, fd, lrank, NULL);
495 
496 		spawn_resp_free(spawn_resp);
497 		spawn_req_free(pmi1_spawn);
498 		pmi1_spawn = NULL;
499 	}
500 out:
501 	debug3("mpi/pmi2: out _handle_mcmd");
502 	return rc;
503 }
504 
505 /**************************************************/
506 
507 /* from src/pmi/simple/simeple_pmiutil.c */
508 #define MAX_READLINE 1024
509 
510 /* buf will be xfree-ed */
511 static int
_handle_pmi1_cmd_buf(int fd,int lrank,int buf_len,char * buf)512 _handle_pmi1_cmd_buf(int fd, int lrank, int buf_len, char *buf)
513 {
514 	client_req_t *req = NULL;
515 	int i = 0, rc;
516 
517 	debug3("mpi/pmi2: got client request: %s", buf);
518 
519 	/* buf taken by req */
520 	req = client_req_init(buf_len, buf);
521 	if (req == NULL) {
522 		error("mpi/pmi2: invalid client request");
523 		return SLURM_ERROR;
524 	}
525 
526 	i = 0;
527 	while (pmi1_cmd_handlers[i].cmd != NULL) {
528 		if (!xstrcmp(req->cmd, pmi1_cmd_handlers[i].cmd))
529 			break;
530 		i ++;
531 	}
532 	if (pmi1_cmd_handlers[i].cmd == NULL) {
533 		error("mpi/pmi2: invalid pmi1 command received: '%s'", req->cmd);
534 		rc = SLURM_ERROR;
535 	} else {
536 		rc = pmi1_cmd_handlers[i].handler(fd, lrank, req);
537 	}
538 	client_req_free(req);	/* free buf */
539 
540 	return rc;
541 }
542 
543 /* *pbuf not xfree-ed */
544 static int
_handle_pmi1_mcmd_buf(int fd,int lrank,int buf_size,int buf_len,char ** pbuf)545 _handle_pmi1_mcmd_buf(int fd, int lrank, int buf_size, int buf_len, char **pbuf)
546 {
547 	int n, len, endcmd_len, not_end;
548 	char *cmd_buf = NULL, *tmp_buf = NULL, *tmp_ptr = NULL, *buf;
549 	int rc = SLURM_SUCCESS;
550 
551 	/* read until "endcmd\n" */
552 	buf = *pbuf;
553 	n = buf_len;
554 	endcmd_len = strlen(ENDCMD_KEY"\n");
555 	not_end = xstrncmp(&buf[n - endcmd_len], ENDCMD_KEY"\n", endcmd_len);
556 	while(not_end) {
557 		if (n == buf_size) {
558 			buf_size += MAX_READLINE;
559 			xrealloc(buf, buf_size + 1);
560 			*pbuf = buf;
561 		}
562 		while((len = read(fd, &buf[n], buf_size - n)) < 0
563 		      && errno == EINTR );
564 		if (len < 0) {
565 			error("mpi/pmi2: failed to read PMI1 request");
566 			return SLURM_ERROR;
567 		} else if (len == 0) {
568 			debug("mpi/pmi2: read partial mcmd: %s", buf);
569 			usleep(100);
570 		} else {
571 			n += len;
572 			not_end = xstrncmp(&buf[n - endcmd_len],
573 					   ENDCMD_KEY"\n", endcmd_len);
574 		}
575 	}
576 	buf[n] = '\0';
577 
578 	/* there maybe multiple subcmds in the buffer */
579 	tmp_buf = buf;
580 	tmp_ptr = NULL;
581 	while (tmp_buf[0] != '\0') {
582 		tmp_ptr = strstr(tmp_buf, ENDCMD_KEY"\n");
583 		if (tmp_ptr == NULL) {
584 			error("mpi/pmi2: this is impossible");
585 			rc = SLURM_ERROR;
586 			break;
587 		}
588 		*tmp_ptr = '\0';
589 		n = tmp_ptr - tmp_buf;
590 		cmd_buf = xstrdup(tmp_buf);
591 		rc = _handle_pmi1_cmd_buf(fd, lrank, n, cmd_buf);
592 		if (rc != SLURM_SUCCESS)
593 			break;
594 		tmp_buf = tmp_ptr + endcmd_len;
595 	}
596 
597 	return rc;
598 }
599 
600 extern int
handle_pmi1_cmd(int fd,int lrank)601 handle_pmi1_cmd(int fd, int lrank)
602 {
603 	char *buf = NULL;
604 	int n, len, size, rc = SLURM_SUCCESS;
605 
606 	debug3("mpi/pmi2: in handle_pmi1_cmd");
607 
608 	/* TODO: read until newline */
609 	size = MAX_READLINE;
610 	buf = xmalloc(size + 1);
611 	while ( (n = read(fd, buf, size)) < 0 && errno == EINTR );
612 	if (n < 0) {
613 		error("mpi/pmi2: failed to read PMI1 request");
614 		xfree(buf);
615 		return SLURM_ERROR;
616 	} else if (n == 0) {
617 		error("mpi/pmi2: read length 0");
618 		xfree(buf);
619 		return SLURM_ERROR;
620 	}
621 
622 	len = strlen(MCMD_KEY"=");
623 	if (! xstrncmp(buf, MCMD_KEY"=", len)) {
624 		rc = _handle_pmi1_mcmd_buf(fd, lrank, size, n, &buf);
625 		xfree(buf);
626 	} else {
627 		buf[n] = '\0';
628 		rc = _handle_pmi1_cmd_buf(fd, lrank, n, buf);
629 	}
630 	debug3("mpi/pmi2: out handle_pmi1_cmd");
631 	return rc;
632 }
633