1 |
commit: 8f1127807f68bbb9c3c85622808677f8c7b60b5b |
2 |
Author: Christoph Junghans <ottxor <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri Aug 29 19:27:46 2014 +0000 |
4 |
Commit: Christoph Junghans <ottxor <AT> gentoo <DOT> org> |
5 |
CommitDate: Fri Aug 29 19:27:46 2014 +0000 |
6 |
URL: http://sources.gentoo.org/gitweb/?p=proj/sci.git;a=commit;h=8f112780 |
7 |
|
8 |
initial commit |
9 |
|
10 |
Package-Manager: portage-2.2.8-r1 |
11 |
|
12 |
--- |
13 |
app-shells/mpibash/ChangeLog | 11 + |
14 |
.../files/bash-4.3-append-process-segfault.patch | 18 + |
15 |
app-shells/mpibash/files/bash-4.3-compat-lvl.patch | 13 + |
16 |
.../files/bash-4.3-parse-time-keyword.patch | 30 + |
17 |
app-shells/mpibash/files/mpibash-4.3.patch | 1565 ++++++++++++++++++++ |
18 |
app-shells/mpibash/metadata.xml | 16 + |
19 |
app-shells/mpibash/mpibash-4.3_p24.ebuild | 259 ++++ |
20 |
7 files changed, 1912 insertions(+) |
21 |
|
22 |
diff --git a/app-shells/mpibash/ChangeLog b/app-shells/mpibash/ChangeLog |
23 |
new file mode 100644 |
24 |
index 0000000..58fda67 |
25 |
--- /dev/null |
26 |
+++ b/app-shells/mpibash/ChangeLog |
27 |
@@ -0,0 +1,11 @@ |
28 |
+# ChangeLog for app-shells/mpibash |
29 |
+# Copyright 1999-2014 Gentoo Foundation; Distributed under the GPL v2 |
30 |
+# $Header: $ |
31 |
+ |
32 |
+*mpibash-4.3_p24 (29 Aug 2014) |
33 |
+ |
34 |
+ 29 Aug 2014; Christoph Junghans <ottxor@g.o> |
35 |
+ +files/bash-4.3-append-process-segfault.patch, |
36 |
+ +files/bash-4.3-compat-lvl.patch, +files/bash-4.3-parse-time-keyword.patch, |
37 |
+ +files/mpibash-4.3.patch, +metadata.xml, +mpibash-4.3_p24.ebuild: |
38 |
+ initial commit |
39 |
|
40 |
diff --git a/app-shells/mpibash/files/bash-4.3-append-process-segfault.patch b/app-shells/mpibash/files/bash-4.3-append-process-segfault.patch |
41 |
new file mode 100644 |
42 |
index 0000000..6c9b2e8 |
43 |
--- /dev/null |
44 |
+++ b/app-shells/mpibash/files/bash-4.3-append-process-segfault.patch |
45 |
@@ -0,0 +1,18 @@ |
46 |
+https://lists.gnu.org/archive/html/bug-bash/2014-08/msg00048.html |
47 |
+ |
48 |
+*** ../bash-4.3-patched/execute_cmd.c 2014-07-30 10:26:52.000000000 -0400 |
49 |
+--- execute_cmd.c 2014-08-11 16:55:57.000000000 -0400 |
50 |
+*************** |
51 |
+*** 2406,2410 **** |
52 |
+ { |
53 |
+ #if defined (JOB_CONTROL) |
54 |
+! append_process (savestring (the_printed_command), dollar_dollar_pid, exec_result, lastpipe_jid); |
55 |
+ #endif |
56 |
+ lstdin = wait_for (lastpid); |
57 |
+--- 2433,2438 ---- |
58 |
+ { |
59 |
+ #if defined (JOB_CONTROL) |
60 |
+! if (INVALID_JOB (lastpipe_jid) == 0) |
61 |
+! append_process (savestring (the_printed_command_except_trap), dollar_dollar_pid, exec_result, lastpipe_jid); |
62 |
+ #endif |
63 |
+ lstdin = wait_for (lastpid); |
64 |
|
65 |
diff --git a/app-shells/mpibash/files/bash-4.3-compat-lvl.patch b/app-shells/mpibash/files/bash-4.3-compat-lvl.patch |
66 |
new file mode 100644 |
67 |
index 0000000..5734687 |
68 |
--- /dev/null |
69 |
+++ b/app-shells/mpibash/files/bash-4.3-compat-lvl.patch |
70 |
@@ -0,0 +1,13 @@ |
71 |
+https://lists.gnu.org/archive/html/bug-bash/2014-06/msg00046.html |
72 |
+ |
73 |
+--- a/builtins/shopt.def |
74 |
++++ b/builtins/shopt.def |
75 |
+@@ -160,7 +160,7 @@ static struct { |
76 |
+ { "compat32", &shopt_compat32, set_compatibility_level }, |
77 |
+ { "compat40", &shopt_compat40, set_compatibility_level }, |
78 |
+ { "compat41", &shopt_compat41, set_compatibility_level }, |
79 |
+- { "compat42", &shopt_compat41, set_compatibility_level }, |
80 |
++ { "compat42", &shopt_compat42, set_compatibility_level }, |
81 |
+ #if defined (READLINE) |
82 |
+ { "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL}, |
83 |
+ { "direxpand", &dircomplete_expand, shopt_set_complete_direxpand }, |
84 |
|
85 |
diff --git a/app-shells/mpibash/files/bash-4.3-parse-time-keyword.patch b/app-shells/mpibash/files/bash-4.3-parse-time-keyword.patch |
86 |
new file mode 100644 |
87 |
index 0000000..cd516e5 |
88 |
--- /dev/null |
89 |
+++ b/app-shells/mpibash/files/bash-4.3-parse-time-keyword.patch |
90 |
@@ -0,0 +1,30 @@ |
91 |
+https://lists.gnu.org/archive/html/bug-bash/2014-06/msg00034.html |
92 |
+ |
93 |
+*** ../bash-4.3-patched/parse.y 2014-04-07 11:56:12.000000000 -0400 |
94 |
+--- parse.y 2014-06-11 10:25:53.000000000 -0400 |
95 |
+*************** |
96 |
+*** 2789,2797 **** |
97 |
+ case OR_OR: |
98 |
+ case '&': |
99 |
+ case DO: |
100 |
+ case THEN: |
101 |
+ case ELSE: |
102 |
+ case '{': /* } */ |
103 |
+! case '(': /* ) */ |
104 |
+ case BANG: /* ! time pipeline */ |
105 |
+ case TIME: /* time time pipeline */ |
106 |
+--- 2789,2802 ---- |
107 |
+ case OR_OR: |
108 |
+ case '&': |
109 |
++ case WHILE: |
110 |
+ case DO: |
111 |
++ case UNTIL: |
112 |
++ case IF: |
113 |
+ case THEN: |
114 |
++ case ELIF: |
115 |
+ case ELSE: |
116 |
+ case '{': /* } */ |
117 |
+! case '(': /* )( */ |
118 |
+! case ')': /* only valid in case statement */ |
119 |
+ case BANG: /* ! time pipeline */ |
120 |
+ case TIME: /* time time pipeline */ |
121 |
|
122 |
diff --git a/app-shells/mpibash/files/mpibash-4.3.patch b/app-shells/mpibash/files/mpibash-4.3.patch |
123 |
new file mode 100644 |
124 |
index 0000000..20d4787 |
125 |
--- /dev/null |
126 |
+++ b/app-shells/mpibash/files/mpibash-4.3.patch |
127 |
@@ -0,0 +1,1565 @@ |
128 |
+diff -Naur bash-4.3/builtins/circle.def mpibash-4.3/builtins/circle.def |
129 |
+--- bash-4.3/builtins/circle.def 1969-12-31 17:00:00.000000000 -0700 |
130 |
++++ mpibash-4.3/builtins/circle.def 2014-05-13 11:27:37.314100671 -0600 |
131 |
+@@ -0,0 +1,620 @@ |
132 |
++This file is circle.def, from which is created circle.c. |
133 |
++It implements all of the "circle_*" builtins in Bash. |
134 |
++ |
135 |
++$PRODUCES circle.c |
136 |
++ |
137 |
++#include <config.h> |
138 |
++ |
139 |
++#include <stdio.h> |
140 |
++#if defined (HAVE_UNISTD_H) |
141 |
++# ifdef _MINIX |
142 |
++# include <sys/types.h> |
143 |
++# endif |
144 |
++# include <unistd.h> |
145 |
++#endif |
146 |
++ |
147 |
++#include "../bashintl.h" |
148 |
++#include "../shell.h" |
149 |
++#include "common.h" |
150 |
++#include "bashgetopt.h" |
151 |
++#include <libcircle.h> |
152 |
++ |
153 |
++extern int running_trap, trap_saved_exit_value; |
154 |
++ |
155 |
++static int circle_rank; /* Rank in the Libcircle job */ |
156 |
++static SHELL_VAR *create_func = NULL; /* User-defined callback function for CIRCLE_cb_create. */ |
157 |
++static SHELL_VAR *process_func = NULL; /* User-defined callback function for CIRCLE_cb_process. */ |
158 |
++static SHELL_VAR *reduce_init_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_init. */ |
159 |
++static SHELL_VAR *reduce_fini_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_fini. */ |
160 |
++static SHELL_VAR *reduce_op_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_op. */ |
161 |
++static CIRCLE_handle *current_handle = NULL; /* Active handle within a callback or NULL if not within a callback */ |
162 |
++static int within_reduction = 0; /* 1=within a reduction callback; 0=not */ |
163 |
++ |
164 |
++/* Return with a usage message if no arguments remain. */ |
165 |
++#define YES_ARGS(LIST) \ |
166 |
++ if ((LIST) == 0) \ |
167 |
++ { \ |
168 |
++ builtin_usage (); \ |
169 |
++ return (EX_USAGE); \ |
170 |
++ } |
171 |
++ |
172 |
++/* Perform the same operation as bind_variable, but with VALUE being a |
173 |
++ * number, not a string. */ |
174 |
++static SHELL_VAR * |
175 |
++bind_variable_number (name, value, flags) |
176 |
++ const char *name; |
177 |
++ long value; |
178 |
++ int flags; |
179 |
++{ |
180 |
++ char numstr[25]; /* String version of VALUE */ |
181 |
++ |
182 |
++ sprintf (numstr, "%ld", value); |
183 |
++ return bind_variable (name, numstr, flags); |
184 |
++} |
185 |
++ |
186 |
++/* Invoke the user-defined creation-callback function (create_func). */ |
187 |
++static void |
188 |
++internal_create_func (handle) |
189 |
++ CIRCLE_handle *handle; |
190 |
++{ |
191 |
++ WORD_LIST *funcargs; |
192 |
++ |
193 |
++ if (create_func == NULL) |
194 |
++ return; |
195 |
++ current_handle = handle; |
196 |
++ funcargs = make_word_list (make_word ("cb_create"), NULL); |
197 |
++ execute_shell_function (create_func, funcargs); |
198 |
++ dispose_words (funcargs); |
199 |
++ current_handle = NULL; |
200 |
++} |
201 |
++ |
202 |
++/* Invoke the user-defined process-callback function (process_func). */ |
203 |
++static void |
204 |
++internal_process_func (handle) |
205 |
++ CIRCLE_handle *handle; |
206 |
++{ |
207 |
++ WORD_LIST *funcargs; |
208 |
++ |
209 |
++ if (process_func == NULL) |
210 |
++ return; |
211 |
++ current_handle = handle; |
212 |
++ funcargs = make_word_list (make_word ("cb_process"), NULL); |
213 |
++ execute_shell_function (process_func, funcargs); |
214 |
++ dispose_words (funcargs); |
215 |
++ current_handle = NULL; |
216 |
++} |
217 |
++ |
218 |
++/* Invoke the user-defined reduction-initiation callback function |
219 |
++ * (reduce_init_func). */ |
220 |
++static void |
221 |
++internal_reduce_init_func (void) |
222 |
++{ |
223 |
++ WORD_LIST *funcargs; |
224 |
++ |
225 |
++ if (reduce_init_func == NULL) |
226 |
++ return; |
227 |
++ within_reduction = 1; |
228 |
++ funcargs = make_word_list (make_word ("cb_reduce_init"), NULL); |
229 |
++ execute_shell_function (reduce_init_func, funcargs); |
230 |
++ dispose_words (funcargs); |
231 |
++ within_reduction = 0; |
232 |
++} |
233 |
++ |
234 |
++/* Invoke the user-defined reduction callback function |
235 |
++ * (reduce_op_func). */ |
236 |
++static void |
237 |
++internal_reduce_op_func (buf1, size1, buf2, size2) |
238 |
++ const void* buf1; |
239 |
++ size_t size1; |
240 |
++ const void* buf2; |
241 |
++ size_t size2; |
242 |
++{ |
243 |
++ WORD_LIST *funcargs; |
244 |
++ |
245 |
++ if (reduce_op_func == NULL) |
246 |
++ return; |
247 |
++ within_reduction = 1; |
248 |
++ funcargs = make_word_list (make_word (buf2), NULL); |
249 |
++ funcargs = make_word_list (make_word (buf1), funcargs); |
250 |
++ funcargs = make_word_list (make_word ("cb_reduce_op"), funcargs); |
251 |
++ execute_shell_function (reduce_op_func, funcargs); |
252 |
++ dispose_words (funcargs); |
253 |
++ within_reduction = 0; |
254 |
++} |
255 |
++ |
256 |
++/* Invoke the user-defined reduction-finalization callback function |
257 |
++ * (reduce_fini_func). */ |
258 |
++static void |
259 |
++internal_reduce_fini_func (buf, size) |
260 |
++ const void* buf; |
261 |
++ size_t size; |
262 |
++{ |
263 |
++ WORD_LIST *funcargs; |
264 |
++ |
265 |
++ if (reduce_fini_func == NULL) |
266 |
++ return; |
267 |
++ funcargs = make_word_list (make_word (buf), NULL); |
268 |
++ funcargs = make_word_list (make_word ("cb_reduce_fini"), funcargs); |
269 |
++ execute_shell_function (reduce_fini_func, funcargs); |
270 |
++ dispose_words (funcargs); |
271 |
++} |
272 |
++ |
273 |
++/* Look up a user-provided callback function. */ |
274 |
++static int |
275 |
++find_callback_function (list, user_func) |
276 |
++ WORD_LIST *list; |
277 |
++ SHELL_VAR **user_func; |
278 |
++{ |
279 |
++ char *funcname; /* Name of the user-defined function. */ |
280 |
++ |
281 |
++ /* If no argument was provided, nullify the callback function. */ |
282 |
++ if (list == NULL) |
283 |
++ { |
284 |
++ *user_func = NULL; |
285 |
++ return EXECUTION_SUCCESS; |
286 |
++ } |
287 |
++ |
288 |
++ /* Get the callback function. */ |
289 |
++ funcname = list->word->word; |
290 |
++ list = list->next; |
291 |
++ no_args (list); |
292 |
++ *user_func = find_function (funcname); |
293 |
++ if (*user_func == NULL) |
294 |
++ { |
295 |
++ builtin_error (_("function %s not found"), funcname); |
296 |
++ return EXECUTION_FAILURE; |
297 |
++ } |
298 |
++ return EXECUTION_SUCCESS; |
299 |
++} |
300 |
++ |
301 |
++/* Initialize Libcircle. */ |
302 |
++void |
303 |
++initialize_libcircle (argc, argv) |
304 |
++ int argc; |
305 |
++ char **argv; |
306 |
++{ |
307 |
++ circle_rank = CIRCLE_init (argc, argv, CIRCLE_DEFAULT_FLAGS); |
308 |
++ bind_variable_number ("circle_rank", circle_rank, 0); |
309 |
++ CIRCLE_enable_logging (CIRCLE_LOG_WARN); |
310 |
++ CIRCLE_cb_create (internal_create_func); |
311 |
++ CIRCLE_cb_process (internal_process_func); |
312 |
++ CIRCLE_cb_reduce_init (internal_reduce_init_func); |
313 |
++ CIRCLE_cb_reduce_op (internal_reduce_op_func); |
314 |
++ CIRCLE_cb_reduce_fini (internal_reduce_fini_func); |
315 |
++} |
316 |
++ |
317 |
++/* Finalize Libcircle. */ |
318 |
++void |
319 |
++finalize_libcircle (void) |
320 |
++{ |
321 |
++ CIRCLE_finalize (); |
322 |
++} |
323 |
++ |
324 |
++/* ---------------------------------------------------------------------- */ |
325 |
++ |
326 |
++$BUILTIN circle_set_options |
327 |
++$FUNCTION circle_set_options_builtin |
328 |
++$SHORT_DOC circle_set_options [flag]... |
329 |
++Change Libcircle's run-time behavior. |
330 |
++ |
331 |
++Arguments: |
332 |
++ FLAG "split_random", "split_equal", or "create_global" |
333 |
++ |
334 |
++Multiple flags can be provided. If no flags are provided, Libcircle |
335 |
++reverts to its default options. |
336 |
++ |
337 |
++Exit Status: |
338 |
++Returns 0 unless an invalid option is given. |
339 |
++$END |
340 |
++/*'*/ |
341 |
++ |
342 |
++/* Here is the circle_set_options builtin. */ |
343 |
++int |
344 |
++circle_set_options_builtin (list) |
345 |
++ WORD_LIST *list; |
346 |
++{ |
347 |
++ char *word; /* One argument */ |
348 |
++ int flags = 0; /* Flags to pass to CIRCLE_set_options */ |
349 |
++ |
350 |
++ if (list == NULL) |
351 |
++ flags = CIRCLE_DEFAULT_FLAGS; |
352 |
++ else |
353 |
++ while (list != NULL) |
354 |
++ { |
355 |
++ word = list->word->word; |
356 |
++ if (!strcmp (word, "split_random")) |
357 |
++ flags |= CIRCLE_SPLIT_RANDOM; |
358 |
++ else if (!strcmp (word, "split_equal")) |
359 |
++ flags |= CIRCLE_SPLIT_EQUAL; |
360 |
++ else if (!strcmp (word, "create_global")) |
361 |
++ flags |= CIRCLE_CREATE_GLOBAL; |
362 |
++ else |
363 |
++ { |
364 |
++ builtin_error (_("invalid flag \"%s\""), word); |
365 |
++ return (EXECUTION_FAILURE); |
366 |
++ } |
367 |
++ list = list->next; |
368 |
++ } |
369 |
++ CIRCLE_set_options (flags); |
370 |
++ return EXECUTION_SUCCESS; |
371 |
++} |
372 |
++ |
373 |
++$BUILTIN circle_cb_create |
374 |
++$FUNCTION circle_cb_create_builtin |
375 |
++$SHORT_DOC circle_cb_create [func] |
376 |
++Register a function that will create work when asked. |
377 |
++ |
378 |
++Arguments: |
379 |
++ FUNC User-defined callback function that will invoke |
380 |
++ circle_enqueue when called |
381 |
++ |
382 |
++If FUNC is omitted, no function will be associated with work creation. |
383 |
++This can be used to nullify a previous circle_cb_create invocation. |
384 |
++ |
385 |
++Exit Status: |
386 |
++Returns 0 unless an invalid function is given or an error occurs. |
387 |
++$END |
388 |
++ |
389 |
++/* Here is the circle_cb_create builtin. */ |
390 |
++int |
391 |
++circle_cb_create_builtin (list) |
392 |
++ WORD_LIST *list; |
393 |
++{ |
394 |
++ return find_callback_function (list, &create_func); |
395 |
++} |
396 |
++ |
397 |
++$BUILTIN circle_cb_process |
398 |
++$FUNCTION circle_cb_process_builtin |
399 |
++$SHORT_DOC circle_cb_process [func] |
400 |
++Register a function that will process work when asked. |
401 |
++ |
402 |
++Arguments: |
403 |
++ FUNC User-defined callback function that will invoke |
404 |
++ circle_enqueue when called |
405 |
++ |
406 |
++If FUNC is omitted, no function will be associated with work processing. |
407 |
++This can be used to nullify a previous circle_cb_process invocation. |
408 |
++ |
409 |
++Exit Status: |
410 |
++Returns 0 unless an invalid function is given or an error occurs. |
411 |
++$END |
412 |
++ |
413 |
++/* Here is the circle_cb_process builtin. */ |
414 |
++int |
415 |
++circle_cb_process_builtin (list) |
416 |
++ WORD_LIST *list; |
417 |
++{ |
418 |
++ return find_callback_function (list, &process_func); |
419 |
++} |
420 |
++ |
421 |
++$BUILTIN circle_begin |
422 |
++$FUNCTION circle_begin_builtin |
423 |
++$SHORT_DOC circle_begin |
424 |
++Begin creation and processing of the distributed work queue. |
425 |
++ |
426 |
++Exit Status: |
427 |
++Returns 0 unless an error occurs. |
428 |
++$END |
429 |
++ |
430 |
++/* Here is the circle_begin builtin. */ |
431 |
++int |
432 |
++circle_begin_builtin (list) |
433 |
++ WORD_LIST *list; |
434 |
++{ |
435 |
++ no_args (list); |
436 |
++ CIRCLE_begin (); |
437 |
++ return EXECUTION_SUCCESS; |
438 |
++} |
439 |
++ |
440 |
++$BUILTIN circle_enqueue |
441 |
++$FUNCTION circle_enqueue_builtin |
442 |
++$SHORT_DOC circle_enqueue work |
443 |
++Enqueue work onto the distributed queue. |
444 |
++ |
445 |
++Arguments: |
446 |
++ WORK "Work" as represented by an arbitrary string of limited |
447 |
++ size (generally around 4KB) |
448 |
++ |
449 |
++Exit Status: |
450 |
++Returns 0 unless an error occurs. |
451 |
++$END |
452 |
++ |
453 |
++/* Here is the circle_enqueue builtin. */ |
454 |
++int |
455 |
++circle_enqueue_builtin (list) |
456 |
++ WORD_LIST *list; |
457 |
++{ |
458 |
++ char *work; /* Work to perform */ |
459 |
++ |
460 |
++ /* Extract the work argument. */ |
461 |
++ YES_ARGS (list); |
462 |
++ work = list->word->word; |
463 |
++ list = list->next; |
464 |
++ no_args (list); |
465 |
++ |
466 |
++ /* Complain if we're not within a proper callback function. */ |
467 |
++ if (current_handle == NULL) |
468 |
++ { |
469 |
++ builtin_error (_("not within a Libcircle \"create\" or \"process\" callback function")); |
470 |
++ return EXECUTION_FAILURE; |
471 |
++ } |
472 |
++ |
473 |
++ /* Enqueue the work. */ |
474 |
++ if (current_handle->enqueue (work) == -1) |
475 |
++ return EXECUTION_FAILURE; |
476 |
++ return EXECUTION_SUCCESS; |
477 |
++} |
478 |
++ |
479 |
++$BUILTIN circle_dequeue |
480 |
++$FUNCTION circle_dequeue_builtin |
481 |
++$SHORT_DOC circle_dequeue var |
482 |
++Dequeue work from the distributed queue into a variable. |
483 |
++ |
484 |
++Arguments: |
485 |
++ VAR Variable in which to receive previously enqueued "work" |
486 |
++ |
487 |
++Exit Status: |
488 |
++Returns 0 unless an error occurs. |
489 |
++$END |
490 |
++ |
491 |
++/* Here is the circle_dequeue builtin. */ |
492 |
++int |
493 |
++circle_dequeue_builtin (list) |
494 |
++ WORD_LIST *list; |
495 |
++{ |
496 |
++ char *varname; /* Variable in which to store the work string */ |
497 |
++ char work[CIRCLE_MAX_STRING_LEN+1]; /* Work to perform */ |
498 |
++ |
499 |
++ /* Extract the variable-name argument. */ |
500 |
++ YES_ARGS (list); |
501 |
++ varname = list->word->word; |
502 |
++ list = list->next; |
503 |
++ no_args (list); |
504 |
++ |
505 |
++ /* Complain if we're not within a callback function. */ |
506 |
++ if (current_handle == NULL) |
507 |
++ { |
508 |
++ builtin_error (_("not within a Libcircle callback function")); |
509 |
++ return EXECUTION_FAILURE; |
510 |
++ } |
511 |
++ |
512 |
++ /* Dequeue the work and bind it to the given variable. */ |
513 |
++ if (current_handle->dequeue (work) == -1) |
514 |
++ return EXECUTION_FAILURE; |
515 |
++ bind_variable (varname, work, 0); |
516 |
++ return EXECUTION_SUCCESS; |
517 |
++} |
518 |
++ |
519 |
++$BUILTIN circle_enable_logging |
520 |
++$FUNCTION circle_enable_logging_builtin |
521 |
++$SHORT_DOC circle_enable_logging log_level |
522 |
++Change Libcircle's logging verbosity |
523 |
++ |
524 |
++Arguments: |
525 |
++ LOG_LEVEL "fatal", "error", "warning", "info", or "debug" |
526 |
++ |
527 |
++Exit Status: |
528 |
++Returns 0 unless an invalid option is given. |
529 |
++$END |
530 |
++/*'*/ |
531 |
++ |
532 |
++/* Here is the circle_enable_logging builtin. */ |
533 |
++int |
534 |
++circle_enable_logging_builtin (list) |
535 |
++ WORD_LIST *list; |
536 |
++{ |
537 |
++ char *word; /* One argument */ |
538 |
++ CIRCLE_loglevel loglevel; /* Level to set */ |
539 |
++ |
540 |
++ /* Parse the log level. */ |
541 |
++ YES_ARGS (list); |
542 |
++ word = list->word->word; |
543 |
++ if (!strcmp (word, "fatal")) |
544 |
++ loglevel = CIRCLE_LOG_FATAL; |
545 |
++ else if (!strcmp (word, "error")) |
546 |
++ loglevel = CIRCLE_LOG_ERR; |
547 |
++ else if (!strcmp (word, "warning")) |
548 |
++ loglevel = CIRCLE_LOG_WARN; |
549 |
++ else if (!strcmp (word, "info")) |
550 |
++ loglevel = CIRCLE_LOG_INFO; |
551 |
++ else if (!strcmp (word, "debug")) |
552 |
++ loglevel = CIRCLE_LOG_DBG; |
553 |
++ else |
554 |
++ { |
555 |
++ builtin_error (_("invalid log level \"%s\""), word); |
556 |
++ return (EXECUTION_FAILURE); |
557 |
++ } |
558 |
++ |
559 |
++ /* Set the log level. */ |
560 |
++ CIRCLE_enable_logging (loglevel); |
561 |
++ return EXECUTION_SUCCESS; |
562 |
++} |
563 |
++ |
564 |
++$BUILTIN circle_abort |
565 |
++$FUNCTION circle_abort_builtin |
566 |
++$SHORT_DOC circle_abort |
567 |
++Terminate queue processing. |
568 |
++ |
569 |
++Exit Status: |
570 |
++Returns 0 unless an error occurs. |
571 |
++$END |
572 |
++ |
573 |
++/* Here is the circle_abort builtin. */ |
574 |
++int |
575 |
++circle_abort_builtin (list) |
576 |
++ WORD_LIST *list; |
577 |
++{ |
578 |
++ no_args (list); |
579 |
++ CIRCLE_abort (); |
580 |
++ return EXECUTION_SUCCESS; |
581 |
++} |
582 |
++ |
583 |
++$BUILTIN circle_checkpoint |
584 |
++$FUNCTION circle_checkpoint_builtin |
585 |
++$SHORT_DOC circle_checkpoint |
586 |
++Checkpoint a work queue to disk. |
587 |
++ |
588 |
++Write a file called circle${circle_rank}.txt containing the current |
589 |
++queue state of rank ${circle_rank}. On a later run, a worker can |
590 |
++invoke circle_read_restarts to repopulate its queue from such a |
591 |
++checkpoint file. |
592 |
++ |
593 |
++Exit Status: |
594 |
++Returns 0 unless an error occurs. |
595 |
++$END |
596 |
++/*'*/ |
597 |
++ |
598 |
++/* Here is the circle_checkpoint builtin. */ |
599 |
++int |
600 |
++circle_checkpoint_builtin (list) |
601 |
++ WORD_LIST *list; |
602 |
++{ |
603 |
++ no_args (list); |
604 |
++ CIRCLE_checkpoint (); |
605 |
++ return EXECUTION_SUCCESS; |
606 |
++} |
607 |
++ |
608 |
++$BUILTIN circle_read_restarts |
609 |
++$FUNCTION circle_read_restarts_builtin |
610 |
++$SHORT_DOC circle_read_restarts |
611 |
++Repopulate a work queue from a disk checkpoint. |
612 |
++ |
613 |
++Read queue contents from a file called circle${circle_rank}.txt, which |
614 |
++was previously produced by circle_checkpoint. |
615 |
++ |
616 |
++Exit Status: |
617 |
++Returns 0 unless an error occurs. |
618 |
++$END |
619 |
++/*'*/ |
620 |
++ |
621 |
++/* Here is the circle_read_restarts builtin. */ |
622 |
++int |
623 |
++circle_read_restarts_builtin (list) |
624 |
++ WORD_LIST *list; |
625 |
++{ |
626 |
++ no_args (list); |
627 |
++ CIRCLE_read_restarts (); |
628 |
++ return EXECUTION_SUCCESS; |
629 |
++} |
630 |
++ |
631 |
++$BUILTIN circle_cb_reduce_init |
632 |
++$FUNCTION circle_cb_reduce_init_builtin |
633 |
++$SHORT_DOC circle_cb_reduce_init [func] |
634 |
++Register a function that will initiate a reduction operation. |
635 |
++ |
636 |
++Arguments: |
637 |
++ FUNC User-defined callback function that will invoke |
638 |
++ circle_reduce when called |
639 |
++ |
640 |
++FUNC will be invoked on all ranks. |
641 |
++ |
642 |
++If FUNC is omitted, no function will be associated with reduction |
643 |
++initialization. This can be used to nullify a previous |
644 |
++circle_cb_reduce_init invocation. |
645 |
++ |
646 |
++Exit Status: |
647 |
++Returns 0 unless an invalid function is given or an error occurs. |
648 |
++$END |
649 |
++ |
650 |
++/* Here is the circle_cb_reduce_init builtin. */ |
651 |
++int |
652 |
++circle_cb_reduce_init_builtin (list) |
653 |
++ WORD_LIST *list; |
654 |
++{ |
655 |
++ return find_callback_function (list, &reduce_init_func); |
656 |
++} |
657 |
++ |
658 |
++$BUILTIN circle_cb_reduce_op |
659 |
++$FUNCTION circle_cb_reduce_op_builtin |
660 |
++$SHORT_DOC circle_cb_reduce_op [func] |
661 |
++Register a function that will complete a reduction operation. |
662 |
++ |
663 |
++Arguments: |
664 |
++ FUNC User-defined callback function that will receive |
665 |
++ two items to reduce and invoke circle_reduce on |
666 |
++ the reduced value |
667 |
++ |
668 |
++If FUNC is omitted, no function will be associated with reduction |
669 |
++execution. This can be used to nullify a previous circle_cb_reduce_op |
670 |
++invocation. |
671 |
++ |
672 |
++Exit Status: |
673 |
++Returns 0 unless an invalid function is given or an error occurs. |
674 |
++$END |
675 |
++ |
676 |
++/* Here is the circle_cb_reduce_op builtin. */ |
677 |
++int |
678 |
++circle_cb_reduce_op_builtin (list) |
679 |
++ WORD_LIST *list; |
680 |
++{ |
681 |
++ return find_callback_function (list, &reduce_op_func); |
682 |
++} |
683 |
++ |
684 |
++$BUILTIN circle_cb_reduce_fini |
685 |
++$FUNCTION circle_cb_reduce_fini_builtin |
686 |
++$SHORT_DOC circle_cb_reduce_fini [func] |
687 |
++Register a function that will complete a reduction operation. |
688 |
++ |
689 |
++Arguments: |
690 |
++ FUNC User-defined callback function that will receive |
691 |
++ the final reduced data |
692 |
++ |
693 |
++If FUNC is omitted, no function will be associated with reduction |
694 |
++completion. This can be used to nullify a previous |
695 |
++circle_cb_reduce_fini invocation. |
696 |
++ |
697 |
++Libcircle guarantees that FUNC will be invoked only on rank 0. |
698 |
++ |
699 |
++Exit Status: |
700 |
++Returns 0 unless an invalid function is given or an error occurs. |
701 |
++$END |
702 |
++ |
703 |
++/* Here is the circle_cb_reduce_fini builtin. */ |
704 |
++int |
705 |
++circle_cb_reduce_fini_builtin (list) |
706 |
++ WORD_LIST *list; |
707 |
++{ |
708 |
++ return find_callback_function (list, &reduce_fini_func); |
709 |
++} |
710 |
++ |
711 |
++$BUILTIN circle_reduce |
712 |
++$FUNCTION circle_reduce_builtin |
713 |
++$SHORT_DOC circle_reduce work |
714 |
++Seed the next phase of a reduction operation |
715 |
++ |
716 |
++Arguments: |
717 |
++ WORK "Work" as represented by an arbitrary string of limited |
718 |
++ size (generally around 4KB) |
719 |
++ |
720 |
++This function should be called both by the callback function |
721 |
++registered with circle_reduce_init and the callback function |
722 |
++registered with circle_reduce_op. |
723 |
++ |
724 |
++Exit Status: |
725 |
++Returns 0 unless an error occurs. |
726 |
++$END |
727 |
++ |
728 |
++/* Here is the circle_reduce builtin. */ |
729 |
++int |
730 |
++circle_reduce_builtin (list) |
731 |
++ WORD_LIST *list; |
732 |
++{ |
733 |
++ char *work; /* Work to perform */ |
734 |
++ |
735 |
++ /* Extract the work argument. */ |
736 |
++ YES_ARGS (list); |
737 |
++ work = list->word->word; |
738 |
++ list = list->next; |
739 |
++ no_args (list); |
740 |
++ |
741 |
++ /* Complain if we're not within a proper callback function. */ |
742 |
++ if (!within_reduction) |
743 |
++ { |
744 |
++ builtin_error (_("not within a Libcircle \"reduce_init\" or \"reduce_op\" callback function")); |
745 |
++ return EXECUTION_FAILURE; |
746 |
++ } |
747 |
++ |
748 |
++ /* Reduce the work. */ |
749 |
++ CIRCLE_reduce (work, strlen (work)); |
750 |
++ return EXECUTION_SUCCESS; |
751 |
++} |
752 |
+diff -Naur bash-4.3/builtins/Makefile.in mpibash-4.3/builtins/Makefile.in |
753 |
+--- bash-4.3/builtins/Makefile.in 2012-05-25 07:29:19.000000000 -0600 |
754 |
++++ mpibash-4.3/builtins/Makefile.in 2014-05-13 11:27:37.314100671 -0600 |
755 |
+@@ -141,7 +141,9 @@ |
756 |
+ $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ |
757 |
+ $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ |
758 |
+ $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \ |
759 |
+- $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def |
760 |
++ $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def \ |
761 |
++ $(srcdir)/mpi.def \ |
762 |
++@CIRCLE@ $(srcdir)/circle.def |
763 |
+ |
764 |
+ STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ |
765 |
+ getopt.h |
766 |
+@@ -153,7 +155,9 @@ |
767 |
+ jobs.o kill.o let.o mapfile.o \ |
768 |
+ pushd.o read.o return.o set.o setattr.o shift.o source.o \ |
769 |
+ suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ |
770 |
+- wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o |
771 |
++ wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o \ |
772 |
++ mpi.o \ |
773 |
++@CIRCLE@ circle.o |
774 |
+ |
775 |
+ CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \ |
776 |
+ tmpbuiltins.h |
777 |
+@@ -317,6 +321,8 @@ |
778 |
+ getopts.o: getopts.def |
779 |
+ reserved.o: reserved.def |
780 |
+ complete.o: complete.def |
781 |
++@CIRCLE@ circle.o: circle.def |
782 |
++mpi.o: mpi.def |
783 |
+ |
784 |
+ # C files |
785 |
+ bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h |
786 |
+@@ -644,6 +650,19 @@ |
787 |
+ mapfile.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h |
788 |
+ mapfile.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/variables.h $(topdir)/conftypes.h |
789 |
+ mapfile.o: $(topdir)/arrayfunc.h ../pathnames.h |
790 |
++@CIRCLE@ circle.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h |
791 |
++@CIRCLE@ circle.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h |
792 |
++@CIRCLE@ circle.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h |
793 |
++@CIRCLE@ circle.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h |
794 |
++@CIRCLE@ circle.o: $(BASHINCDIR)/maxpath.h ../pathnames.h |
795 |
++mpi.o: ../config.h ../config-top.h ../config-bot.h ../bashintl.h |
796 |
++mpi.o: ../include/gettext.h ../shell.h ../config.h ../bashjmp.h |
797 |
++mpi.o: ../include/posixjmp.h ../command.h ../syntax.h ../general.h |
798 |
++mpi.o: ../bashtypes.h ../include/chartypes.h ../xmalloc.h ../bashansi.h |
799 |
++mpi.o: ../error.h ../variables.h ../array.h ../assoc.h ../hashlib.h |
800 |
++mpi.o: ../conftypes.h ../arrayfunc.h ../quit.h ../sig.h ../include/maxpath.h |
801 |
++mpi.o: ../unwind_prot.h ../dispose_cmd.h ../make_cmd.h ../include/ocache.h |
802 |
++mpi.o: ../subst.h ../pathnames.h ../externs.h common.h bashgetopt.h |
803 |
+ |
804 |
+ #bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h |
805 |
+ |
806 |
+diff -Naur bash-4.3/builtins/mpi.def mpibash-4.3/builtins/mpi.def |
807 |
+--- bash-4.3/builtins/mpi.def 1969-12-31 17:00:00.000000000 -0700 |
808 |
++++ mpibash-4.3/builtins/mpi.def 2014-05-13 11:27:37.314100671 -0600 |
809 |
+@@ -0,0 +1,744 @@ |
810 |
++This file is mpi.def, from which is created mpi.c. |
811 |
++It implements all of the "mpi_*" builtins in Bash. |
812 |
++ |
813 |
++$PRODUCES mpi.c |
814 |
++ |
815 |
++#include <config.h> |
816 |
++ |
817 |
++#include <stdio.h> |
818 |
++#if defined (HAVE_UNISTD_H) |
819 |
++# ifdef _MINIX |
820 |
++# include <sys/types.h> |
821 |
++# endif |
822 |
++# include <unistd.h> |
823 |
++#endif |
824 |
++ |
825 |
++#include "../bashintl.h" |
826 |
++#include "../shell.h" |
827 |
++#include "common.h" |
828 |
++#include "bashgetopt.h" |
829 |
++#include <mpi.h> |
830 |
++ |
831 |
++extern int running_trap, trap_saved_exit_value; |
832 |
++ |
833 |
++/* Keep track of who we are within MPI_COMM_WORLD. */ |
834 |
++static int mpi_rank; |
835 |
++static int mpi_num_ranks; |
836 |
++ |
837 |
++/* Try an MPI operation. Return with an error message on failure. */ |
838 |
++#define MPI_TRY(STMT) \ |
839 |
++ do \ |
840 |
++ { \ |
841 |
++ int mpierr; \ |
842 |
++ mpierr = STMT; \ |
843 |
++ if (mpierr != MPI_SUCCESS) \ |
844 |
++ return report_mpi_error (mpierr); \ |
845 |
++ } \ |
846 |
++ while (0) |
847 |
++ |
848 |
++/* Return with a usage message if no arguments remain. */ |
849 |
++#define YES_ARGS(LIST) \ |
850 |
++ if ((LIST) == 0) \ |
851 |
++ { \ |
852 |
++ builtin_usage (); \ |
853 |
++ return (EX_USAGE); \ |
854 |
++ } |
855 |
++ |
856 |
++/* Return with an error message if a given variable is read-only or if |
857 |
++ * we can't write to it for any other reason (e.g., it's defined as a |
858 |
++ * function). */ |
859 |
++#define REQUIRE_WRITABLE(NAME) \ |
860 |
++ do \ |
861 |
++ { \ |
862 |
++ SHELL_VAR *bindvar = find_shell_variable (NAME); \ |
863 |
++ if (bindvar) \ |
864 |
++ { \ |
865 |
++ if (readonly_p (bindvar)) \ |
866 |
++ { \ |
867 |
++ err_readonly (NAME); \ |
868 |
++ return (EXECUTION_FAILURE); \ |
869 |
++ } \ |
870 |
++ if (unbind_variable (NAME) == -1) \ |
871 |
++ { \ |
872 |
++ builtin_error ("Failed to write to variable %s", NAME); \ |
873 |
++ return (EXECUTION_FAILURE); \ |
874 |
++ } \ |
875 |
++ } \ |
876 |
++ } \ |
877 |
++ while (0) |
878 |
++ |
879 |
++/* Initialize MPI. */ |
880 |
++void |
881 |
++initialize_mpi (argc, argv) |
882 |
++ int argc; |
883 |
++ char **argv; |
884 |
++{ |
885 |
++ int init_done; |
886 |
++ |
887 |
++ MPI_Initialized (&init_done); |
888 |
++ if (!init_done) |
889 |
++ MPI_Init (&argc, &argv); |
890 |
++ MPI_Errhandler_set (MPI_COMM_WORLD, MPI_ERRORS_RETURN); |
891 |
++ MPI_Comm_rank (MPI_COMM_WORLD, &mpi_rank); |
892 |
++ MPI_Comm_size (MPI_COMM_WORLD, &mpi_num_ranks); |
893 |
++} |
894 |
++ |
895 |
++/* Finalize MPI. */ |
896 |
++void |
897 |
++finalize_mpi () |
898 |
++{ |
899 |
++ MPI_Finalize (); |
900 |
++} |
901 |
++ |
902 |
++/* Parse an operation name into an MPI_Op. Return 1 on success, 0 on |
903 |
++ * failure. */ |
904 |
++static int |
905 |
++parse_operation (char *name, MPI_Op *op) |
906 |
++{ |
907 |
++ /* Define a mapping from operator names to MPI_Op values. */ |
908 |
++ typedef struct { |
909 |
++ char *name; /* Operation name (e.g., "sum") */ |
910 |
++ MPI_Op value; /* Operation value (e.g., MPI_SUM) */ |
911 |
++ } opname2value_t; |
912 |
++ static opname2value_t oplist[] = { |
913 |
++ {"max", MPI_MAX}, |
914 |
++ {"min", MPI_MIN}, |
915 |
++ {"sum", MPI_SUM}, |
916 |
++ {"prod", MPI_PROD}, |
917 |
++ {"land", MPI_LAND}, |
918 |
++ {"band", MPI_BAND}, |
919 |
++ {"lor", MPI_LOR}, |
920 |
++ {"bor", MPI_BOR}, |
921 |
++ {"lxor", MPI_LXOR}, |
922 |
++ {"bxor", MPI_BXOR}, |
923 |
++ {"maxloc", MPI_MAXLOC}, |
924 |
++ {"minloc", MPI_MINLOC} |
925 |
++ }; |
926 |
++ size_t i; |
927 |
++ |
928 |
++ for (i = 0; i < sizeof(oplist)/sizeof(opname2value_t); i++) |
929 |
++ if (!strcmp(name, oplist[i].name)) |
930 |
++ { |
931 |
++ *op = oplist[i].value; |
932 |
++ if (i > 0) |
933 |
++ { |
934 |
++ /* As a performance optimization, bubble up the value we |
935 |
++ * just found. */ |
936 |
++ opname2value_t prev = oplist[i - 1]; |
937 |
++ oplist[i - 1] = oplist[i]; |
938 |
++ oplist[i] = prev; |
939 |
++ } |
940 |
++ return 1; |
941 |
++ } |
942 |
++ return 0; |
943 |
++} |
944 |
++ |
945 |
++/* Report an error to the user and return EXECUTION_FAILURE. */ |
946 |
++static int |
947 |
++report_mpi_error (mpierr) |
948 |
++ int mpierr; |
949 |
++{ |
950 |
++ char errstr[MPI_MAX_ERROR_STRING]; |
951 |
++ int errstrlen; |
952 |
++ |
953 |
++ MPI_Error_string (mpierr, errstr, &errstrlen); |
954 |
++ builtin_error ("%s", errstr); |
955 |
++ return EXECUTION_FAILURE; |
956 |
++} |
957 |
++ |
958 |
++/* Perform the same operation as bind_variable, but with VALUE being a |
959 |
++ * number, not a string. */ |
960 |
++static SHELL_VAR * |
961 |
++bind_variable_number (name, value, flags) |
962 |
++ const char *name; |
963 |
++ long value; |
964 |
++ int flags; |
965 |
++{ |
966 |
++ char numstr[25]; /* String version of VALUE */ |
967 |
++ |
968 |
++ sprintf (numstr, "%ld", value); |
969 |
++ return bind_variable (name, numstr, flags); |
970 |
++} |
971 |
++ |
972 |
++/* Perform the same operation as bind_array_variable, but with VALUE |
973 |
++ * being a number, not a string. */ |
974 |
++static SHELL_VAR * |
975 |
++bind_array_variable_number (name, ind, value, flags) |
976 |
++ char *name; |
977 |
++ arrayind_t ind; |
978 |
++ long value; |
979 |
++ int flags; |
980 |
++{ |
981 |
++ char numstr[25]; /* String version of VALUE */ |
982 |
++ |
983 |
++ sprintf (numstr, "%ld", value); |
984 |
++ return bind_array_variable (name, ind, numstr, flags); |
985 |
++} |
986 |
++ |
987 |
++/* Define a reduction-type function (allreduce, scan, exscan, etc.). */ |
988 |
++typedef int (*reduction_func_t)(void *, void *, int, MPI_Datatype, MPI_Op, MPI_Comm); |
989 |
++ |
990 |
++/* Perform any reduction-type operation (allreduce, scan, exscan, etc.). */ |
991 |
++static int |
992 |
++reduction_like (list, funcname, func) |
993 |
++ WORD_LIST *list; |
994 |
++ char *funcname; |
995 |
++ reduction_func_t func; |
996 |
++{ |
997 |
++ char *word; /* One argument */ |
998 |
++ struct { |
999 |
++ long int value; /* Reduced value */ |
1000 |
++ int rank; /* Rank associated with the above */ |
1001 |
++ } number, result; |
1002 |
++ MPI_Op operation = MPI_SUM; /* Operation to perform */ |
1003 |
++ char *varname; /* Name of the variable to bind the results to */ |
1004 |
++ intmax_t n; |
1005 |
++ int i; |
1006 |
++ |
1007 |
++ /* Parse "-O OPERATION" (optional), where OPERATION is a reduction |
1008 |
++ * operation. */ |
1009 |
++ YES_ARGS (list); |
1010 |
++ word = list->word->word; |
1011 |
++ if (ISOPTION (word, 'O')) |
1012 |
++ { |
1013 |
++ list = list->next; |
1014 |
++ if (list == 0) |
1015 |
++ { |
1016 |
++ sh_needarg (funcname); |
1017 |
++ return (EX_USAGE); |
1018 |
++ } |
1019 |
++ word = list->word->word; |
1020 |
++ if (!parse_operation (word, &operation)) |
1021 |
++ { |
1022 |
++ sh_invalidopt ("-O"); |
1023 |
++ return (EX_USAGE); |
1024 |
++ } |
1025 |
++ list = list->next; |
1026 |
++ } |
1027 |
++ |
1028 |
++ /* Parse the argument, which must be a number. */ |
1029 |
++ YES_ARGS (list); |
1030 |
++ word = list->word->word; |
1031 |
++ if (!legal_number (word, &n)) |
1032 |
++ { |
1033 |
++ sh_neednumarg (funcname); |
1034 |
++ return (EX_USAGE); |
1035 |
++ } |
1036 |
++ number.value = (long int) n; |
1037 |
++ number.rank = mpi_rank; |
1038 |
++ list = list->next; |
1039 |
++ |
1040 |
++ /* Parse the target variable, which must not be read-only. */ |
1041 |
++ YES_ARGS (list); |
1042 |
++ varname = list->word->word; |
1043 |
++ if (mpi_rank != 0 || func != MPI_Exscan) |
1044 |
++ REQUIRE_WRITABLE (varname); |
1045 |
++ list = list->next; |
1046 |
++ no_args (list); |
1047 |
++ |
1048 |
++ /* Perform the reduction operation. Bind the given array variable |
1049 |
++ * to the result and, for minloc/maxloc, the associated rank. */ |
1050 |
++ if (mpi_rank != 0 || func != MPI_Exscan) { |
1051 |
++ bind_array_variable (varname, 0, "", 0); |
1052 |
++ bind_array_variable (varname, 1, "", 0); |
1053 |
++ } |
1054 |
++ if (operation == MPI_MINLOC || operation == MPI_MAXLOC) |
1055 |
++ { |
1056 |
++ MPI_TRY (func (&number, &result, 1, MPI_LONG_INT, operation, MPI_COMM_WORLD)); |
1057 |
++ if (mpi_rank != 0 || func != MPI_Exscan) |
1058 |
++ bind_array_variable_number (varname, 1, result.rank, 0); |
1059 |
++ } |
1060 |
++ else |
1061 |
++ MPI_TRY (func (&number.value, &result.value, 1, MPI_LONG, operation, MPI_COMM_WORLD)); |
1062 |
++ if (mpi_rank != 0 || func != MPI_Exscan) |
1063 |
++ bind_array_variable_number (varname, 0, result.value, 0); |
1064 |
++ return EXECUTION_SUCCESS; |
1065 |
++} |
1066 |
++ |
1067 |
++$BUILTIN mpi_comm_rank |
1068 |
++$FUNCTION mpi_comm_rank_builtin |
1069 |
++$SHORT_DOC mpi_comm_rank name |
1070 |
++Return the process's rank in the MPI job. |
1071 |
++ |
1072 |
++Arguments: |
1073 |
++ NAME Scalar variable in which to receive the rank |
1074 |
++ |
1075 |
++Exit Status: |
1076 |
++Returns 0 unless an invalid option is given. |
1077 |
++$END |
1078 |
++/*'*/ |
1079 |
++ |
1080 |
++/* Here is the mpi_comm_rank builtin. */ |
1081 |
++int |
1082 |
++mpi_comm_rank_builtin (list) |
1083 |
++ WORD_LIST *list; |
1084 |
++{ |
1085 |
++ char *varname; /* Name of the variable to bind the results to */ |
1086 |
++ |
1087 |
++ YES_ARGS (list); |
1088 |
++ varname = list->word->word; |
1089 |
++ REQUIRE_WRITABLE (varname); |
1090 |
++ list = list->next; |
1091 |
++ no_args (list); |
1092 |
++ bind_variable_number (varname, mpi_rank, 0); |
1093 |
++ return EXECUTION_SUCCESS; |
1094 |
++} |
1095 |
++ |
1096 |
++$BUILTIN mpi_comm_size |
1097 |
++$FUNCTION mpi_comm_size_builtin |
1098 |
++$SHORT_DOC mpi_comm_size name |
1099 |
++Return the total number of ranks in the MPI job. |
1100 |
++ |
1101 |
++Arguments: |
1102 |
++ NAME Scalar variable in which to receive the number of ranks |
1103 |
++ |
1104 |
++Exit Status: |
1105 |
++Returns 0 unless an invalid option is given. |
1106 |
++$END |
1107 |
++ |
1108 |
++/* Here is the mpi_comm_size builtin. */ |
1109 |
++int |
1110 |
++mpi_comm_size_builtin (list) |
1111 |
++ WORD_LIST *list; |
1112 |
++{ |
1113 |
++ char *varname; /* Name of the variable to bind the results to */ |
1114 |
++ |
1115 |
++ YES_ARGS (list); |
1116 |
++ varname = list->word->word; |
1117 |
++ REQUIRE_WRITABLE (varname); |
1118 |
++ list = list->next; |
1119 |
++ no_args (list); |
1120 |
++ bind_variable_number (varname, mpi_num_ranks, 0); |
1121 |
++ return EXECUTION_SUCCESS; |
1122 |
++} |
1123 |
++ |
1124 |
++$BUILTIN mpi_abort |
1125 |
++$FUNCTION mpi_abort_builtin |
1126 |
++$SHORT_DOC mpi_abort [n] |
1127 |
++Abort all processes in the MPI job and exit the shell. |
1128 |
++ |
1129 |
++Exits not only the caller's shell (with a status of N) but also all |
1130 |
++remote shells that are part of the same MPI job. If N is omitted, the |
1131 |
++exit status is that of the last command executed. |
1132 |
++ |
1133 |
++This command should be used only in extreme circumstances. It is |
1134 |
++better for each process to exit normally on its own. |
1135 |
++$END |
1136 |
++/*'*/ |
1137 |
++ |
1138 |
++/* Here is the mpi_abort builtin. */ |
1139 |
++int |
1140 |
++mpi_abort_builtin (list) |
1141 |
++ WORD_LIST *list; |
1142 |
++{ |
1143 |
++ int exit_value; |
1144 |
++ |
1145 |
++ exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list); /* Copied from exit.def */ |
1146 |
++ MPI_TRY (MPI_Abort (MPI_COMM_WORLD, exit_value)); |
1147 |
++ return EXECUTION_FAILURE; |
1148 |
++} |
1149 |
++ |
1150 |
++$BUILTIN mpi_send |
1151 |
++$FUNCTION mpi_send_builtin |
1152 |
++$SHORT_DOC mpi_send [-t tag] rank message |
1153 |
++Send a message to a remote process in the same MPI job. |
1154 |
++ |
1155 |
++Options: |
1156 |
++ -t TAG Send the message using tag TAG (default: 0). TAG must |
1157 |
++ be a nonnegative integer. |
1158 |
++ |
1159 |
++Arguments: |
1160 |
++ RANK Whom to send the message to. RANK must be an integer in |
1161 |
++ the range [0, $(mpi_comm_size)-1]. |
1162 |
++ |
1163 |
++ MESSAGE String to send to rank RANK. |
1164 |
++ |
1165 |
++Exit Status: |
1166 |
++Returns 0 unless an invalid option is given or an error occurs. |
1167 |
++$END |
1168 |
++ |
1169 |
++/* Here is the mpi_send builtin. */ |
1170 |
++int |
1171 |
++mpi_send_builtin (list) |
1172 |
++ WORD_LIST *list; |
1173 |
++{ |
1174 |
++ char *word; /* One argument */ |
1175 |
++ intmax_t target_rank; /* MPI target rank */ |
1176 |
++ char *message; /* Message to send to rank target_rank */ |
1177 |
++ intmax_t tag = 0; /* Message tag to use */ |
1178 |
++ |
1179 |
++ /* Parse "-t TAG" (optional), where TAG is a number or "any". */ |
1180 |
++ YES_ARGS (list); |
1181 |
++ word = list->word->word; |
1182 |
++ if (ISOPTION (word, 't')) |
1183 |
++ { |
1184 |
++ list = list->next; |
1185 |
++ if (list == 0) |
1186 |
++ { |
1187 |
++ sh_needarg ("mpi_recv"); |
1188 |
++ return (EX_USAGE); |
1189 |
++ } |
1190 |
++ word = list->word->word; |
1191 |
++ if (!legal_number (word, &tag)) |
1192 |
++ { |
1193 |
++ sh_neednumarg ("-t"); |
1194 |
++ return (EX_USAGE); |
1195 |
++ } |
1196 |
++ list = list->next; |
1197 |
++ } |
1198 |
++ else if (*word == '-') |
1199 |
++ { |
1200 |
++ sh_invalidopt (word); |
1201 |
++ builtin_usage (); |
1202 |
++ return (EX_USAGE); |
1203 |
++ } |
1204 |
++ |
1205 |
++ /* Parse the target rank, which must be a number. */ |
1206 |
++ YES_ARGS (list); |
1207 |
++ word = list->word->word; |
1208 |
++ if (!legal_number (word, &target_rank)) |
1209 |
++ { |
1210 |
++ builtin_error (_("mpi_send: numeric rank required")); |
1211 |
++ return (EX_USAGE); |
1212 |
++ } |
1213 |
++ list = list->next; |
1214 |
++ |
1215 |
++ /* Parse the message to send. */ |
1216 |
++ YES_ARGS (list); |
1217 |
++ message = list->word->word; |
1218 |
++ list = list->next; |
1219 |
++ no_args (list); |
1220 |
++ |
1221 |
++ /* Send the message. */ |
1222 |
++ MPI_TRY (MPI_Send (message, strlen(message)+1, MPI_BYTE, (int)target_rank, (int)tag, MPI_COMM_WORLD)); |
1223 |
++ return EXECUTION_SUCCESS; |
1224 |
++} |
1225 |
++ |
1226 |
++ |
1227 |
++$BUILTIN mpi_recv |
1228 |
++$FUNCTION mpi_recv_builtin |
1229 |
++$SHORT_DOC mpi_recv [-t tag] rank name |
1230 |
++Receive a message from a remote process in the same MPI job. |
1231 |
++ |
1232 |
++Options: |
1233 |
++ -t TAG Receive only messages sent using tag TAG (default: 0). |
1234 |
++ TAG must be either a nonnegative integer or the string |
1235 |
++ "any" to receive messages sent using any tag. |
1236 |
++ |
1237 |
++Arguments: |
1238 |
++ RANK Receive only messages sent from sender RANK. RANK |
1239 |
++ must either be in the range [0, $(mpi_comm_size)-1] or |
1240 |
++ be the string "any" to receive messages from any sender. |
1241 |
++ |
1242 |
++ NAME Array variable in which to receive the message, sender |
1243 |
++ rank, and tag. |
1244 |
++ |
1245 |
++Exit Status: |
1246 |
++Returns 0 unless an invalid option is given or an error occurs. |
1247 |
++$END |
1248 |
++ |
1249 |
++/* Here is the mpi_recv builtin. */ |
1250 |
++int |
1251 |
++mpi_recv_builtin (list) |
1252 |
++ WORD_LIST *list; |
1253 |
++{ |
1254 |
++ char *word; /* One argument */ |
1255 |
++ intmax_t source_rank; /* MPI source rank */ |
1256 |
++ char *endptr; /* Used for parsing strings into numbers */ |
1257 |
++ MPI_Status status; /* Status of an MPI operation */ |
1258 |
++ int count; /* Message length in bytes */ |
1259 |
++ intmax_t tag = 0; /* Message tag to use */ |
1260 |
++ char *varname; /* Name of the variable to bind the results to */ |
1261 |
++ static char *message = NULL; /* Message received from MPI */ |
1262 |
++ static size_t alloced = 0; /* Number of bytes allocated for the above */ |
1263 |
++ int opt; /* Parsed option */ |
1264 |
++ |
1265 |
++ /* Parse any options provided. */ |
1266 |
++ reset_internal_getopt (); |
1267 |
++ while ((opt = internal_getopt (list, "t:")) != -1) |
1268 |
++ { |
1269 |
++ switch (opt) |
1270 |
++ { |
1271 |
++ case 't': |
1272 |
++ if (!strcmp (list_optarg, "any")) |
1273 |
++ tag = MPI_ANY_TAG; |
1274 |
++ else if (!legal_number (list_optarg, &tag)) |
1275 |
++ { |
1276 |
++ builtin_error (_("-t: numeric argument or \"any\" required")); |
1277 |
++ return (EX_USAGE); |
1278 |
++ } |
1279 |
++ break; |
1280 |
++ |
1281 |
++ default: |
1282 |
++ sh_invalidopt (word); |
1283 |
++ builtin_usage (); |
1284 |
++ return (EX_USAGE); |
1285 |
++ } |
1286 |
++ } |
1287 |
++ list = loptend; |
1288 |
++ |
1289 |
++ /* Parse the source rank, which must be a number or "any". */ |
1290 |
++ YES_ARGS (list); |
1291 |
++ word = list->word->word; |
1292 |
++ if (!legal_number (word, &source_rank)) |
1293 |
++ { |
1294 |
++ if (!strcmp (word, "any")) |
1295 |
++ source_rank = MPI_ANY_SOURCE; |
1296 |
++ else |
1297 |
++ { |
1298 |
++ builtin_error (_("mpi_recv: numeric rank or \"any\" required")); |
1299 |
++ return (EX_USAGE); |
1300 |
++ } |
1301 |
++ } |
1302 |
++ list = list->next; |
1303 |
++ |
1304 |
++ /* Parse the target variable, which must not be read-only. */ |
1305 |
++ YES_ARGS (list); |
1306 |
++ varname = list->word->word; |
1307 |
++ REQUIRE_WRITABLE (varname); |
1308 |
++ list = list->next; |
1309 |
++ no_args (list); |
1310 |
++ |
1311 |
++ /* Receive a message. Because we don't know long the message will |
1312 |
++ * be, we first probe to get the length. */ |
1313 |
++ MPI_TRY (MPI_Probe ((int)source_rank, (int)tag, MPI_COMM_WORLD, &status)); |
1314 |
++ MPI_TRY (MPI_Get_count (&status, MPI_BYTE, &count)); |
1315 |
++ if (alloced < count) |
1316 |
++ { |
1317 |
++ message = xrealloc (message, count); |
1318 |
++ alloced = count; |
1319 |
++ } |
1320 |
++ MPI_TRY (MPI_Recv (message, count, MPI_BYTE, status.MPI_SOURCE, status.MPI_TAG, MPI_COMM_WORLD, &status)); |
1321 |
++ bind_array_variable (varname, 0, message, 0); |
1322 |
++ bind_array_variable_number (varname, 1, status.MPI_SOURCE, 0); |
1323 |
++ bind_array_variable_number (varname, 2, status.MPI_TAG, 0); |
1324 |
++ return EXECUTION_SUCCESS; |
1325 |
++} |
1326 |
++ |
1327 |
++$BUILTIN mpi_barrier |
1328 |
++$FUNCTION mpi_barrier_builtin |
1329 |
++$SHORT_DOC mpi_barrier |
1330 |
++Synchronizes all of the processes in the MPI job. |
1331 |
++ |
1332 |
++No process will return from mpi_barrier until all processes have |
1333 |
++called mpi_barrier. |
1334 |
++ |
1335 |
++Exit Status: |
1336 |
++Returns 0 unless an invalid option is given or an error occurs. |
1337 |
++$END |
1338 |
++ |
1339 |
++/* Here is the mpi_barrier builtin. */ |
1340 |
++int |
1341 |
++mpi_barrier_builtin (list) |
1342 |
++ WORD_LIST *list; |
1343 |
++{ |
1344 |
++ no_args (list); |
1345 |
++ MPI_TRY (MPI_Barrier (MPI_COMM_WORLD)); |
1346 |
++ return EXECUTION_SUCCESS; |
1347 |
++} |
1348 |
++ |
1349 |
++$BUILTIN mpi_bcast |
1350 |
++$FUNCTION mpi_bcast_builtin |
1351 |
++$SHORT_DOC mpi_bcast [message] name |
1352 |
++Broadcast a message to all processes in the same MPI job. |
1353 |
++ |
1354 |
++Arguments: |
1355 |
++ MESSAGE String to broadcast from one process to all the others. |
1356 |
++ |
1357 |
++ NAME Scalar variable in which to receive the broadcast message. |
1358 |
++ |
1359 |
++Exactly one process in the MPI job must specify a message to |
1360 |
++broadcast. No process will return from mpi_bcast until all processes |
1361 |
++have called mpi_bcast. |
1362 |
++ |
1363 |
++Exit Status: |
1364 |
++Returns 0 unless an invalid option is given or an error occurs. |
1365 |
++$END |
1366 |
++ |
1367 |
++/* Here is the mpi_bcast builtin. */ |
1368 |
++int |
1369 |
++mpi_bcast_builtin (list) |
1370 |
++ WORD_LIST *list; |
1371 |
++{ |
1372 |
++ char *word; /* One argument */ |
1373 |
++ int root; /* MPI root rank */ |
1374 |
++ char *root_message; /* Message to broadcast */ |
1375 |
++ int msglen; /* Length in bytes of the above (including the NULL byte) */ |
1376 |
++ char *varname; /* Name of the variable to bind the results to */ |
1377 |
++ static int *all_lengths = NULL; /* List of every rank's msglen */ |
1378 |
++ static char *message = NULL; /* Message received from the root */ |
1379 |
++ static int alloced = 0; /* Bytes allocated for the above */ |
1380 |
++ int i; |
1381 |
++ |
1382 |
++ /* Parse the optional message and target variable, which must not be |
1383 |
++ * read-only. */ |
1384 |
++ YES_ARGS (list); |
1385 |
++ if (list->next == NULL) |
1386 |
++ { |
1387 |
++ /* Non-root */ |
1388 |
++ root_message = NULL; |
1389 |
++ msglen = -1; |
1390 |
++ } |
1391 |
++ else |
1392 |
++ { |
1393 |
++ /* Root */ |
1394 |
++ root_message = list->word->word; |
1395 |
++ msglen = (int) strlen(root_message) + 1; |
1396 |
++ list = list->next; |
1397 |
++ } |
1398 |
++ varname = list->word->word; |
1399 |
++ REQUIRE_WRITABLE (varname); |
1400 |
++ list = list->next; |
1401 |
++ no_args (list); |
1402 |
++ |
1403 |
++ /* Acquire global agreement on the root and the message size. */ |
1404 |
++ if (all_lengths == NULL) |
1405 |
++ all_lengths = xmalloc (mpi_num_ranks*sizeof(int)); |
1406 |
++ MPI_TRY (MPI_Allgather (&msglen, 1, MPI_INT, all_lengths, 1, MPI_INT, MPI_COMM_WORLD)); |
1407 |
++ root = -1; |
1408 |
++ for (i = 0; i < mpi_num_ranks; i++) |
1409 |
++ { |
1410 |
++ if (all_lengths[i] == -1) |
1411 |
++ continue; |
1412 |
++ if (root != -1) |
1413 |
++ { |
1414 |
++ builtin_error (_("mpi_bcast: more than one process specified a message")); |
1415 |
++ return (EXECUTION_FAILURE); |
1416 |
++ } |
1417 |
++ root = i; |
1418 |
++ msglen = all_lengths[i]; |
1419 |
++ } |
1420 |
++ if (root == -1) |
1421 |
++ { |
1422 |
++ builtin_error (_("mpi_bcast: no process specified a message")); |
1423 |
++ return (EXECUTION_FAILURE); |
1424 |
++ } |
1425 |
++ |
1426 |
++ /* Broadcast the message. */ |
1427 |
++ if (mpi_rank == root) |
1428 |
++ { |
1429 |
++ MPI_TRY (MPI_Bcast (root_message, msglen, MPI_BYTE, root, MPI_COMM_WORLD)); |
1430 |
++ bind_variable (varname, root_message, 0); |
1431 |
++ } |
1432 |
++ else |
1433 |
++ { |
1434 |
++ if (alloced < msglen) |
1435 |
++ { |
1436 |
++ message = xrealloc (message, msglen); |
1437 |
++ alloced = msglen; |
1438 |
++ } |
1439 |
++ MPI_TRY (MPI_Bcast (message, msglen, MPI_BYTE, root, MPI_COMM_WORLD)); |
1440 |
++ bind_variable (varname, message, 0); |
1441 |
++ } |
1442 |
++ return EXECUTION_SUCCESS; |
1443 |
++} |
1444 |
++ |
1445 |
++$BUILTIN mpi_scan |
1446 |
++$FUNCTION mpi_scan_builtin |
1447 |
++$SHORT_DOC mpi_scan number name |
1448 |
++Perform an inclusive scan across all processes in the same MPI job. |
1449 |
++ |
1450 |
++ -O OPERATION Operation to perform. Must be one of "max", "min", |
1451 |
++ "sum", "prod", "land", "band", "lor", "bor", "lxor", |
1452 |
++ "bxor", "maxloc", or "minloc" (default: "sum"). |
1453 |
++ |
1454 |
++Arguments: |
1455 |
++ NUMBER Integer to use in the scan operation. |
1456 |
++ |
1457 |
++ NAME Array variable in which to receive the result and, in |
1458 |
++ the case of maxloc and minloc, the associated rank. |
1459 |
++ |
1460 |
++In an inclusive-scan operation, each process i presents a number, |
1461 |
++a[i]. Once all processes in the MPI job have presented their number, |
1462 |
++the command returns a[0] to rank 0, a[0]+a[1] to rank 1, |
1463 |
++a[0]+a[1]+a[2] to rank 2, and so forth. The -O option enables "+" to |
1464 |
++be replaced with other operations. |
1465 |
++ |
1466 |
++Inclusive scans can be useful for assigning a unique index to each |
1467 |
++process in the MPI job. |
1468 |
++ |
1469 |
++Exit Status: |
1470 |
++Returns 0 unless an invalid option is given or an error occurs. |
1471 |
++$END |
1472 |
++ |
1473 |
++/* Here is the mpi_scan builtin. */ |
1474 |
++int |
1475 |
++mpi_scan_builtin (list) |
1476 |
++ WORD_LIST *list; |
1477 |
++{ |
1478 |
++ return reduction_like (list, "mpi_scan", MPI_Scan); |
1479 |
++} |
1480 |
++ |
1481 |
++$BUILTIN mpi_exscan |
1482 |
++$FUNCTION mpi_exscan_builtin |
1483 |
++$SHORT_DOC mpi_exscan number name |
1484 |
++Perform an exclusive scan across all processes in the same MPI job. |
1485 |
++ |
1486 |
++ -O OPERATION Operation to perform. Must be one of "max", "min", |
1487 |
++ "sum", "prod", "land", "band", "lor", "bor", "lxor", |
1488 |
++ "bxor", "maxloc", or "minloc" (default: "sum"). |
1489 |
++ |
1490 |
++Arguments: |
1491 |
++ NUMBER Integer to use in the scan operation. |
1492 |
++ |
1493 |
++ NAME Array variable in which to receive the result and, in |
1494 |
++ the case of maxloc and minloc, the associated rank. |
1495 |
++ |
1496 |
++In a exclusive-scan operation, each process i presents a number, a[i]. |
1497 |
++Once all processes in the MPI job have presented their number, the |
1498 |
++command assigns a[0] to NAME on rank 1, a[0]+a[1] to NAME on rank 2, |
1499 |
++a[0]+a[1]+a[2] to NAME on rank 3, and so forth. No assignment is |
1500 |
++performed on rank 0. The -O option enables "+" to be replaced with |
1501 |
++other operations. |
1502 |
++ |
1503 |
++Exclusive scans can be useful for assigning a unique index to each |
1504 |
++process in the MPI job. |
1505 |
++ |
1506 |
++Exit Status: |
1507 |
++Returns 0 unless an invalid option is given or an error occurs. |
1508 |
++$END |
1509 |
++ |
1510 |
++/* Here is the mpi_exscan builtin. */ |
1511 |
++int |
1512 |
++mpi_exscan_builtin (list) |
1513 |
++ WORD_LIST *list; |
1514 |
++{ |
1515 |
++ return reduction_like (list, "mpi_exscan", MPI_Exscan); |
1516 |
++} |
1517 |
++ |
1518 |
++$BUILTIN mpi_allreduce |
1519 |
++$FUNCTION mpi_allreduce_builtin |
1520 |
++$SHORT_DOC mpi_allreduce number name |
1521 |
++Reduce numbers from all processes in an MPI job to a single number. |
1522 |
++ |
1523 |
++Options: |
1524 |
++ |
1525 |
++ -O OPERATION Operation to perform. Must be one of "max", "min", |
1526 |
++ "sum", "prod", "land", "band", "lor", "bor", "lxor", |
1527 |
++ "bxor", "maxloc", or "minloc" (default: "sum"). |
1528 |
++ |
1529 |
++Arguments: |
1530 |
++ NUMBER Integer to use in the allreduce operation. |
1531 |
++ |
1532 |
++ NAME Array variable in which to receive the result and, in |
1533 |
++ the case of maxloc and minloc, the associated rank. |
1534 |
++ |
1535 |
++In an all-reduce operation, each process i presents a number, a[i]. |
1536 |
++Once all processes in the MPI job have presented their number, the |
1537 |
++command returns a[0]+a[1]+...+a[n-1] to all ranks. The -O option |
1538 |
++enables "+" to be replaced with other operations. |
1539 |
++ |
1540 |
++All-reduces can be useful for reaching global agreement (e.g., of a |
1541 |
++termination condition). |
1542 |
++ |
1543 |
++Exit Status: |
1544 |
++Returns 0 unless an invalid option is given or an error occurs. |
1545 |
++$END |
1546 |
++ |
1547 |
++/* Here is the mpi_allreduce builtin. */ |
1548 |
++int |
1549 |
++mpi_allreduce_builtin (list) |
1550 |
++ WORD_LIST *list; |
1551 |
++{ |
1552 |
++ return reduction_like (list, "mpi_allreduce", MPI_Allreduce); |
1553 |
++} |
1554 |
+diff -Naur bash-4.3/config.h.in mpibash-4.3/config.h.in |
1555 |
+--- bash-4.3/config.h.in 2013-06-29 15:35:33.000000000 -0600 |
1556 |
++++ mpibash-4.3/config.h.in 2014-05-13 11:27:37.314100671 -0600 |
1557 |
+@@ -1147,6 +1147,12 @@ |
1558 |
+ /* Define if you have the `__argz_stringify' function. */ |
1559 |
+ #undef HAVE___ARGZ_STRINGIFY |
1560 |
+ |
1561 |
++/* Define if you have both the <libcircle.h> header file and the libcircle library. */ |
1562 |
++#undef HAVE_LIBCIRCLE |
1563 |
++ |
1564 |
++/* Define if you have the `CIRCLE_cb_reduce_op' function. */ |
1565 |
++#undef HAVE_CIRCLE_CB_REDUCE_OP |
1566 |
++ |
1567 |
+ /* End additions for lib/intl */ |
1568 |
+ |
1569 |
+ #include "config-bot.h" |
1570 |
+diff -Naur bash-4.3/configure.ac mpibash-4.3/configure.ac |
1571 |
+--- bash-4.3/configure.ac 2014-02-11 08:37:53.000000000 -0700 |
1572 |
++++ mpibash-4.3/configure.ac 2014-05-13 11:27:37.302100179 -0600 |
1573 |
+@@ -24,7 +24,7 @@ |
1574 |
+ AC_REVISION([for Bash 4.3, version 4.063])dnl |
1575 |
+ |
1576 |
+ define(bashvers, 4.3) |
1577 |
+-define(relstatus, release) |
1578 |
++define(relstatus, MPI) |
1579 |
+ |
1580 |
+ AC_INIT([bash], bashvers-relstatus, [bug-bash@×××.org]) |
1581 |
+ |
1582 |
+@@ -813,6 +813,21 @@ |
1583 |
+ fi |
1584 |
+ ]) |
1585 |
+ |
1586 |
++dnl Ensure that we can find an MPI library. |
1587 |
++AC_CHECK_FUNCS([MPI_Init], [], [ |
1588 |
++ AC_MSG_ERROR([Cannot continue without MPI. Consider specifying CC=mpicc.])]) |
1589 |
++ |
1590 |
++dnl If we have Libcircle, use it, too. |
1591 |
++AC_SEARCH_LIBS([CIRCLE_cb_create], [circle], [AC_CHECK_HEADERS([libcircle.h])]) |
1592 |
++if test "x$ac_cv_header_libcircle_h" = xyes; then |
1593 |
++ libcircle_make_prefix="" |
1594 |
++ AC_DEFINE([HAVE_LIBCIRCLE], [1], [Define if you have the Libcircle header and library.]) |
1595 |
++ AC_CHECK_FUNCS([CIRCLE_cb_reduce_op]) |
1596 |
++else |
1597 |
++ libcircle_make_prefix="#" |
1598 |
++fi |
1599 |
++AC_SUBST([CIRCLE], [$libcircle_make_prefix]) |
1600 |
++ |
1601 |
+ BASH_CHECK_DECL(strtoimax) |
1602 |
+ BASH_CHECK_DECL(strtol) |
1603 |
+ BASH_CHECK_DECL(strtoll) |
1604 |
+diff -Naur bash-4.3/Makefile.in mpibash-4.3/Makefile.in |
1605 |
+--- bash-4.3/Makefile.in 2014-01-25 14:27:30.000000000 -0700 |
1606 |
++++ mpibash-4.3/Makefile.in 2014-05-13 11:27:37.314100671 -0600 |
1607 |
+@@ -104,7 +104,7 @@ |
1608 |
+ VERSPROG = bashversion$(EXEEXT) |
1609 |
+ VERSOBJ = bashversion.$(OBJEXT) |
1610 |
+ |
1611 |
+-Program = bash$(EXEEXT) |
1612 |
++Program = mpibash$(EXEEXT) |
1613 |
+ Version = @BASHVERS@ |
1614 |
+ PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` |
1615 |
+ RELSTATUS = @RELSTATUS@ |
1616 |
+diff -Naur bash-4.3/shell.c mpibash-4.3/shell.c |
1617 |
+--- bash-4.3/shell.c 2014-01-14 06:04:32.000000000 -0700 |
1618 |
++++ mpibash-4.3/shell.c 2014-05-13 11:27:37.314100671 -0600 |
1619 |
+@@ -107,6 +107,13 @@ |
1620 |
+ extern char *primary_prompt, *secondary_prompt; |
1621 |
+ extern char *this_command_name; |
1622 |
+ |
1623 |
++extern void initialize_mpi __P((int, char **)); |
1624 |
++extern void finalize_mpi __P((void)); |
1625 |
++#ifdef HAVE_LIBCIRCLE |
1626 |
++extern void initialize_libcircle __P((int, char **)); |
1627 |
++extern void finalize_libcircle __P((void)); |
1628 |
++#endif |
1629 |
++ |
1630 |
+ /* Non-zero means that this shell has already been run; i.e. you should |
1631 |
+ call shell_reinitialize () if you need to start afresh. */ |
1632 |
+ int shell_initialized = 0; |
1633 |
+@@ -324,7 +331,7 @@ |
1634 |
+ static void init_interactive_script __P((void)); |
1635 |
+ |
1636 |
+ static void set_shell_name __P((char *)); |
1637 |
+-static void shell_initialize __P((void)); |
1638 |
++static void shell_initialize __P((int, char **)); |
1639 |
+ static void shell_reinitialize __P((void)); |
1640 |
+ |
1641 |
+ static void show_shell_usage __P((FILE *, int)); |
1642 |
+@@ -561,7 +568,7 @@ |
1643 |
+ |
1644 |
+ /* From here on in, the shell must be a normal functioning shell. |
1645 |
+ Variables from the environment are expected to be set, etc. */ |
1646 |
+- shell_initialize (); |
1647 |
++ shell_initialize (argc, argv); |
1648 |
+ |
1649 |
+ set_default_lang (); |
1650 |
+ set_default_locale_vars (); |
1651 |
+@@ -941,6 +948,12 @@ |
1652 |
+ end_job_control (); |
1653 |
+ #endif /* JOB_CONTROL */ |
1654 |
+ |
1655 |
++#ifdef HAVE_LIBCIRCLE |
1656 |
++ finalize_libcircle (); |
1657 |
++#else |
1658 |
++ finalize_mpi (); |
1659 |
++#endif |
1660 |
++ |
1661 |
+ /* Always return the exit status of the last command to our parent. */ |
1662 |
+ sh_exit (s); |
1663 |
+ } |
1664 |
+@@ -1691,7 +1704,9 @@ |
1665 |
+ /* Do whatever is necessary to initialize the shell. |
1666 |
+ Put new initializations in here. */ |
1667 |
+ static void |
1668 |
+-shell_initialize () |
1669 |
++shell_initialize (argc, argv) |
1670 |
++ int argc; |
1671 |
++ char **argv; |
1672 |
+ { |
1673 |
+ char hostname[256]; |
1674 |
+ |
1675 |
+@@ -1760,6 +1775,17 @@ |
1676 |
+ initialize_shell_options (privileged_mode||running_setuid); |
1677 |
+ initialize_bashopts (privileged_mode||running_setuid); |
1678 |
+ #endif |
1679 |
++ |
1680 |
++ /* Initialize Libcircle and MPI. */ |
1681 |
++#ifdef HAVE_LIBCIRCLE |
1682 |
++ initialize_libcircle (argc, argv); |
1683 |
++ initialize_mpi (argc, argv); |
1684 |
++ bind_variable ("libcircle", "yes", 0); |
1685 |
++#else |
1686 |
++ initialize_mpi (argc, argv); |
1687 |
++ bind_variable ("libcircle", "no", 0); |
1688 |
++#endif |
1689 |
++ bind_variable ("mpibash", "yes", 0); |
1690 |
+ } |
1691 |
+ |
1692 |
+ /* Function called by main () when it appears that the shell has already |
1693 |
|
1694 |
diff --git a/app-shells/mpibash/metadata.xml b/app-shells/mpibash/metadata.xml |
1695 |
new file mode 100644 |
1696 |
index 0000000..8598dc9 |
1697 |
--- /dev/null |
1698 |
+++ b/app-shells/mpibash/metadata.xml |
1699 |
@@ -0,0 +1,16 @@ |
1700 |
+<?xml version="1.0" encoding="UTF-8"?> |
1701 |
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> |
1702 |
+<pkgmetadata> |
1703 |
+<herd>base-system</herd> |
1704 |
+<use> |
1705 |
+ <flag name='bashlogger'>Log ALL commands typed into bash; should ONLY be |
1706 |
+ used in restricted environments such as honeypots</flag> |
1707 |
+ <flag name='mem-scramble'>Build with custom malloc/free overwriting allocated/freed memory</flag> |
1708 |
+ <flag name='net'>Enable /dev/tcp/host/port redirection</flag> |
1709 |
+ <flag name='plugins'>Add support for loading builtins at runtime via |
1710 |
+ 'enable'</flag> |
1711 |
+</use> |
1712 |
+<upstream> |
1713 |
+ <remote-id type="cpe">cpe:/a:gnu:bash</remote-id> |
1714 |
+</upstream> |
1715 |
+</pkgmetadata> |
1716 |
|
1717 |
diff --git a/app-shells/mpibash/mpibash-4.3_p24.ebuild b/app-shells/mpibash/mpibash-4.3_p24.ebuild |
1718 |
new file mode 100644 |
1719 |
index 0000000..cf8e545 |
1720 |
--- /dev/null |
1721 |
+++ b/app-shells/mpibash/mpibash-4.3_p24.ebuild |
1722 |
@@ -0,0 +1,259 @@ |
1723 |
+# Copyright 1999-2014 Gentoo Foundation |
1724 |
+# Distributed under the terms of the GNU General Public License v2 |
1725 |
+# $Header: /var/cvsroot/gentoo-x86/app-shells/bash/bash-4.3_p24.ebuild,v 1.1 2014/08/24 17:53:01 polynomial-c Exp $ |
1726 |
+ |
1727 |
+EAPI="4" |
1728 |
+ |
1729 |
+inherit autotools eutils flag-o-matic toolchain-funcs multilib |
1730 |
+ |
1731 |
+# Official patchlevel |
1732 |
+# See ftp://ftp.cwru.edu/pub/bash/bash-4.3-patches/ |
1733 |
+PLEVEL=${PV##*_p} |
1734 |
+MY_PV=${PV/_p*} |
1735 |
+MY_PV=${MY_PV/_/-} |
1736 |
+MY_P=${PN#mpi}-${MY_PV} |
1737 |
+[[ ${PV} != *_p* ]] && PLEVEL=0 |
1738 |
+patches() { |
1739 |
+ local opt=$1 plevel=${2:-${PLEVEL}} pn=${3:-${PN#mpi}} pv=${4:-${MY_PV}} |
1740 |
+ [[ ${plevel} -eq 0 ]] && return 1 |
1741 |
+ eval set -- {1..${plevel}} |
1742 |
+ set -- $(printf "${pn}${pv/\.}-%03d " "$@") |
1743 |
+ if [[ ${opt} == -s ]] ; then |
1744 |
+ echo "${@/#/${DISTDIR}/}" |
1745 |
+ else |
1746 |
+ local u |
1747 |
+ for u in ftp://ftp.cwru.edu/pub/bash mirror://gnu/${pn} ; do |
1748 |
+ printf "${u}/${pn}-${pv}-patches/%s " "$@" |
1749 |
+ done |
1750 |
+ fi |
1751 |
+} |
1752 |
+ |
1753 |
+# The version of readline this bash normally ships with. |
1754 |
+READLINE_VER="6.3" |
1755 |
+ |
1756 |
+DESCRIPTION="Parallel scripting right from the Bourne-Again Shell (Bash)" |
1757 |
+HOMEPAGE="http://www.ccs3.lanl.gov/~pakin/software/mpibash-4.3.html" |
1758 |
+SRC_URI="mirror://gnu/bash/${MY_P}.tar.gz $(patches)" |
1759 |
+[[ ${PV} == *_rc* ]] && SRC_URI+=" ftp://ftp.cwru.edu/pub/bash/${MY_P}.tar.gz" |
1760 |
+ |
1761 |
+LICENSE="GPL-3" |
1762 |
+SLOT="0" |
1763 |
+#KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~sparc-fbsd ~x86-fbsd" |
1764 |
+IUSE="afs bashlogger examples mem-scramble +net nls plugins +readline vanilla" |
1765 |
+ |
1766 |
+DEPEND=">=sys-libs/ncurses-5.2-r2 |
1767 |
+ readline? ( >=sys-libs/readline-${READLINE_VER} ) |
1768 |
+ nls? ( virtual/libintl )" |
1769 |
+RDEPEND="${DEPEND} |
1770 |
+ virtual/mpi |
1771 |
+ sys-cluster/libcircle |
1772 |
+ !<sys-apps/portage-2.1.6.7_p1 |
1773 |
+ !<sys-apps/paludis-0.26.0_alpha5" |
1774 |
+# we only need yacc when the .y files get patched (bash42-005) |
1775 |
+DEPEND+=" virtual/yacc" |
1776 |
+ |
1777 |
+S=${WORKDIR}/${MY_P} |
1778 |
+ |
1779 |
+pkg_setup() { |
1780 |
+ if is-flag -malign-double ; then #7332 |
1781 |
+ eerror "Detected bad CFLAGS '-malign-double'. Do not use this" |
1782 |
+ eerror "as it breaks LFS (struct stat64) on x86." |
1783 |
+ die "remove -malign-double from your CFLAGS mr ricer" |
1784 |
+ fi |
1785 |
+ if use bashlogger ; then |
1786 |
+ ewarn "The logging patch should ONLY be used in restricted (i.e. honeypot) envs." |
1787 |
+ ewarn "This will log ALL output you enter into the shell, you have been warned." |
1788 |
+ fi |
1789 |
+} |
1790 |
+ |
1791 |
+src_unpack() { |
1792 |
+ unpack ${MY_P}.tar.gz |
1793 |
+} |
1794 |
+ |
1795 |
+src_prepare() { |
1796 |
+ # Include official patches |
1797 |
+ [[ ${PLEVEL} -gt 0 ]] && epatch $(patches -s) |
1798 |
+ |
1799 |
+ # Clean out local libs so we know we use system ones w/releases. |
1800 |
+ if [[ ${PV} != *_rc* ]] ; then |
1801 |
+ rm -rf lib/{readline,termcap}/* |
1802 |
+ touch lib/{readline,termcap}/Makefile.in # for config.status |
1803 |
+ sed -ri -e 's:\$[(](RL|HIST)_LIBSRC[)]/[[:alpha:]]*.h::g' Makefile.in || die |
1804 |
+ fi |
1805 |
+ |
1806 |
+ # Avoid regenerating docs after patches #407985 |
1807 |
+ sed -i -r '/^(HS|RL)USER/s:=.*:=:' doc/Makefile.in || die |
1808 |
+ touch -r . doc/* |
1809 |
+ |
1810 |
+ epatch "${FILESDIR}"/${PN#mpi}-4.3-compat-lvl.patch |
1811 |
+ epatch "${FILESDIR}"/${PN#mpi}-4.3-parse-time-keyword.patch |
1812 |
+ epatch "${FILESDIR}"/${PN#mpi}-4.3-append-process-segfault.patch |
1813 |
+ epatch "${FILESDIR}"/${PN}-4.3.patch |
1814 |
+ |
1815 |
+ epatch_user |
1816 |
+ |
1817 |
+ eautoconf |
1818 |
+} |
1819 |
+ |
1820 |
+src_configure() { |
1821 |
+ local myconf=() |
1822 |
+ |
1823 |
+ # For descriptions of these, see config-top.h |
1824 |
+ # bashrc/#26952 bash_logout/#90488 ssh/#24762 |
1825 |
+ append-cppflags \ |
1826 |
+ -DDEFAULT_PATH_VALUE=\'\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\' \ |
1827 |
+ -DSTANDARD_UTILS_PATH=\'\"/bin:/usr/bin:/sbin:/usr/sbin\"\' \ |
1828 |
+ -DSYS_BASHRC=\'\"/etc/bash/bashrc\"\' \ |
1829 |
+ -DSYS_BASH_LOGOUT=\'\"/etc/bash/bash_logout\"\' \ |
1830 |
+ -DNON_INTERACTIVE_LOGIN_SHELLS \ |
1831 |
+ -DSSH_SOURCE_BASHRC \ |
1832 |
+ $($(tc-getPKG_CONFIG) --cflags libcircle) \ |
1833 |
+ $(use bashlogger && echo -DSYSLOG_HISTORY) |
1834 |
+ |
1835 |
+ # Don't even think about building this statically without |
1836 |
+ # reading Bug 7714 first. If you still build it statically, |
1837 |
+ # don't come crying to us with bugs ;). |
1838 |
+ #use static && export LDFLAGS="${LDFLAGS} -static" |
1839 |
+ use nls || myconf+=( --disable-nls ) |
1840 |
+ |
1841 |
+ # Historically, we always used the builtin readline, but since |
1842 |
+ # our handling of SONAME upgrades has gotten much more stable |
1843 |
+ # in the PM (and the readline ebuild itself preserves the old |
1844 |
+ # libs during upgrades), linking against the system copy should |
1845 |
+ # be safe. |
1846 |
+ # Exact cached version here doesn't really matter as long as it |
1847 |
+ # is at least what's in the DEPEND up above. |
1848 |
+ export ac_cv_rl_version=${READLINE_VER} |
1849 |
+ |
1850 |
+ # Force linking with system curses ... the bundled termcap lib |
1851 |
+ # sucks bad compared to ncurses. For the most part, ncurses |
1852 |
+ # is here because readline needs it. But bash itself calls |
1853 |
+ # ncurses in one or two small places :(. |
1854 |
+ |
1855 |
+ if [[ ${PV} != *_rc* ]] ; then |
1856 |
+ # Use system readline only with released versions. |
1857 |
+ myconf+=( --with-installed-readline=. ) |
1858 |
+ fi |
1859 |
+ |
1860 |
+ if use plugins; then |
1861 |
+ append-ldflags -Wl,-rpath,/usr/$(get_libdir)/bash |
1862 |
+ else |
1863 |
+ # Disable the plugins logic by hand since bash doesn't |
1864 |
+ # provide a way of doing it. |
1865 |
+ export ac_cv_func_dl{close,open,sym}=no \ |
1866 |
+ ac_cv_lib_dl_dlopen=no ac_cv_header_dlfcn_h=no |
1867 |
+ sed -i \ |
1868 |
+ -e '/LOCAL_LDFLAGS=/s:-rdynamic::' \ |
1869 |
+ configure || die |
1870 |
+ fi |
1871 |
+ tc-export AR #444070 |
1872 |
+ LIBS="-lcircle" CC=mpicc \ |
1873 |
+ econf \ |
1874 |
+ --docdir='$(datarootdir)'/doc/${PF} \ |
1875 |
+ --htmldir='$(docdir)/html' \ |
1876 |
+ --with-curses \ |
1877 |
+ $(use_with afs) \ |
1878 |
+ $(use_enable net net-redirections) \ |
1879 |
+ --disable-profiling \ |
1880 |
+ $(use_enable mem-scramble) \ |
1881 |
+ $(use_with mem-scramble bash-malloc) \ |
1882 |
+ $(use_enable readline) \ |
1883 |
+ $(use_enable readline history) \ |
1884 |
+ $(use_enable readline bang-history) \ |
1885 |
+ "${myconf[@]}" |
1886 |
+} |
1887 |
+ |
1888 |
+src_compile() { |
1889 |
+ emake |
1890 |
+ |
1891 |
+ if use plugins ; then |
1892 |
+ emake -C examples/loadables all others |
1893 |
+ fi |
1894 |
+} |
1895 |
+ |
1896 |
+src_install() { |
1897 |
+ local d f |
1898 |
+ |
1899 |
+ default |
1900 |
+ |
1901 |
+ find "${ED}" -name "bashbug*" -delete |
1902 |
+ mv "${ED}"/usr/share/man/man1/{,mpi}bash.1 || die |
1903 |
+ mv "${ED}"/usr/share/info/{,mpi}bash.info || die |
1904 |
+ return 0 |
1905 |
+ |
1906 |
+ dodir /bin |
1907 |
+ mv "${ED}"/usr/bin/bash "${ED}"/bin/ || die |
1908 |
+ dosym bash /bin/rbash |
1909 |
+ |
1910 |
+ insinto /etc/bash |
1911 |
+ doins "${FILESDIR}"/{bashrc,bash_logout} |
1912 |
+ insinto /etc/skel |
1913 |
+ for f in bash{_logout,_profile,rc} ; do |
1914 |
+ newins "${FILESDIR}"/dot-${f} .${f} |
1915 |
+ done |
1916 |
+ |
1917 |
+ local sed_args=( |
1918 |
+ -e "s:#${USERLAND}#@::" |
1919 |
+ -e '/#@/d' |
1920 |
+ ) |
1921 |
+ if ! use readline ; then |
1922 |
+ sed_args+=( #432338 |
1923 |
+ -e '/^shopt -s histappend/s:^:#:' |
1924 |
+ -e 's:use_color=true:use_color=false:' |
1925 |
+ ) |
1926 |
+ fi |
1927 |
+ sed -i \ |
1928 |
+ "${sed_args[@]}" \ |
1929 |
+ "${ED}"/etc/skel/.bashrc \ |
1930 |
+ "${ED}"/etc/bash/bashrc || die |
1931 |
+ |
1932 |
+ if use plugins ; then |
1933 |
+ exeinto /usr/$(get_libdir)/bash |
1934 |
+ doexe $(echo examples/loadables/*.o | sed 's:\.o::g') |
1935 |
+ insinto /usr/include/bash-plugins |
1936 |
+ doins *.h builtins/*.h include/*.h lib/{glob/glob.h,tilde/tilde.h} |
1937 |
+ fi |
1938 |
+ |
1939 |
+ if use examples ; then |
1940 |
+ for d in examples/{functions,misc,scripts,scripts.noah,scripts.v2} ; do |
1941 |
+ exeinto /usr/share/doc/${PF}/${d} |
1942 |
+ insinto /usr/share/doc/${PF}/${d} |
1943 |
+ for f in ${d}/* ; do |
1944 |
+ if [[ ${f##*/} != PERMISSION ]] && [[ ${f##*/} != *README ]] ; then |
1945 |
+ doexe ${f} |
1946 |
+ else |
1947 |
+ doins ${f} |
1948 |
+ fi |
1949 |
+ done |
1950 |
+ done |
1951 |
+ fi |
1952 |
+ |
1953 |
+ doman doc/*.1 |
1954 |
+ newdoc CWRU/changelog ChangeLog |
1955 |
+ dosym bash.info /usr/share/info/bashref.info |
1956 |
+} |
1957 |
+ |
1958 |
+pkg_preinst() { |
1959 |
+ return 0 |
1960 |
+ if [[ -e ${EROOT}/etc/bashrc ]] && [[ ! -d ${EROOT}/etc/bash ]] ; then |
1961 |
+ mkdir -p "${EROOT}"/etc/bash |
1962 |
+ mv -f "${EROOT}"/etc/bashrc "${EROOT}"/etc/bash/ |
1963 |
+ fi |
1964 |
+ |
1965 |
+ if [[ -L ${EROOT}/bin/sh ]] ; then |
1966 |
+ # rewrite the symlink to ensure that its mtime changes. having /bin/sh |
1967 |
+ # missing even temporarily causes a fatal error with paludis. |
1968 |
+ local target=$(readlink "${EROOT}"/bin/sh) |
1969 |
+ local tmp=$(emktemp "${EROOT}"/bin) |
1970 |
+ ln -sf "${target}" "${tmp}" |
1971 |
+ mv -f "${tmp}" "${EROOT}"/bin/sh |
1972 |
+ fi |
1973 |
+} |
1974 |
+ |
1975 |
+pkg_postinst() { |
1976 |
+ return 0 |
1977 |
+ # If /bin/sh does not exist, provide it |
1978 |
+ if [[ ! -e ${EROOT}/bin/sh ]] ; then |
1979 |
+ ln -sf bash "${EROOT}"/bin/sh |
1980 |
+ fi |
1981 |
+} |