Marcus Meissner
9b729e2acc
New package per "Factory first" policy. Please list me as bug owner and maintainer, if possible. OBS-URL: https://build.opensuse.org/request/show/459343 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=1
527 lines
16 KiB
Diff
527 lines
16 KiB
Diff
--- s390-tools-1.34.0/dasdfmt/dasdfmt.8 2016-04-14 16:43:51.000000000 -0400
|
|
+++ s390-tools-1.34.0/dasdfmt/dasdfmt.8 2016-04-14 16:35:01.000000000 -0400
|
|
@@ -3,11 +3,11 @@
|
|
dasdfmt \- formatting of DASD (ECKD) disk drives.
|
|
|
|
.SH SYNOPSIS
|
|
-\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-P] [-m \fIstep\fR]
|
|
+\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-Q] [-m \fIstep\fR]
|
|
.br
|
|
- [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR]
|
|
+ [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR] [-P maxpar]
|
|
.br
|
|
- [-L] [-V] [-F] [-k] [-C] \fIdevice\fR
|
|
+ [-L] [-V] [-F] [-k] [-C] \fIdevice\fR ...
|
|
|
|
.SH DESCRIPTION
|
|
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
|
|
@@ -91,7 +91,7 @@
|
|
running in background or redirecting the output to a file.
|
|
|
|
.TP
|
|
-\fB-P\fR or \fB--percentage\fR
|
|
+\fB-Q\fR or \fB--percentage\fR
|
|
Print one line for each formatted cylinder showing the number of the
|
|
cylinder and percentage of formatting process.
|
|
Intended to be used by higher level interfaces.
|
|
@@ -123,6 +123,20 @@
|
|
and always be a power of two. The recommended blocksize is 4096 bytes.
|
|
|
|
.TP
|
|
+\fB-P\fR \fInumdisks\fR or \fB--max_parallel\fR=\fInumdisks\fR
|
|
+Specify the number of disks to be formatted in
|
|
+parallel. \FInumdisks\fR specifies the number of formatting processes
|
|
+which is independent of the overall number of disks to be formatted as
|
|
+specified on the commandline. The maximum value for \fInumdisks\fR is
|
|
+1024. Default is 1.
|
|
+.br
|
|
+Using this option can
|
|
+decrease overall processing time when formatting several disks.
|
|
+Please note that the I/O throughput will dramatically increase when
|
|
+using this option. Use with care.
|
|
+.br
|
|
+
|
|
+.TP
|
|
\fB-l\fR \fIvolser\fR or \fB--label\fR=\fIvolser\fR
|
|
Specify the volume serial number or volume identifier to be written
|
|
to disk after formatting. If no label is specified, a sensible default
|
|
--- s390-tools-1.34.0/dasdfmt/dasdfmt.h 2016-04-14 16:43:51.000000000 -0400
|
|
+++ s390-tools-1.34.0/dasdfmt/dasdfmt.h 2016-04-14 16:35:01.000000000 -0400
|
|
@@ -195,6 +195,7 @@
|
|
#define LABEL_LENGTH 14
|
|
#define VLABEL_CHARS 84
|
|
#define LINE_LENGTH 80
|
|
+#define MAX_DEVICES 1024
|
|
#define ERR_LENGTH 90
|
|
|
|
#define DEFAULT_BLOCKSIZE 4096
|
|
@@ -214,7 +215,7 @@
|
|
if (*endptr) ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
|
|
"is in invalid format\n",prog_name);}
|
|
|
|
-#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpPLtyvVFkC"
|
|
+#define dasdfmt_getopt_string "b:n:l:f:d:m:r:hpQLtyvVFkCYP:"
|
|
|
|
static struct option dasdfmt_getopt_long_options[]=
|
|
{
|
|
@@ -225,12 +226,14 @@
|
|
{ "force", 0, 0, 'F'},
|
|
{ "progressbar", 0, 0, 'p'},
|
|
{ "hashmarks", 1, 0, 'm'},
|
|
- { "percentage", 0, 0, 'P'},
|
|
+ { "percentage", 0, 0, 'Q'},
|
|
{ "label", 1, 0, 'l'},
|
|
{ "device", 1, 0, 'f'},
|
|
{ "blocksize", 1, 0, 'b'},
|
|
{ "requestsize", 1, 0, 'r'},
|
|
{ "help", 0, 0, 'h'},
|
|
+ { "max_parallel",1, 0, 'P'},
|
|
+ { "yast_mode", 0, 0, 'Y'},
|
|
{ "keep_volser", 0, 0, 'k'},
|
|
{ "norecordzero", 0, 0, 'z'},
|
|
{ "check_host_count", 0, 0, 'C'},
|
|
@@ -267,6 +270,8 @@
|
|
int device_id;
|
|
int keep_volser;
|
|
int force_host;
|
|
+ int yast_mode;
|
|
+ int procnum;
|
|
} dasdfmt_info_t;
|
|
|
|
|
|
--- s390-tools-1.34.0/dasdfmt/dasdfmt.c 2016-04-14 16:43:51.000000000 -0400
|
|
+++ s390-tools-1.34.0/dasdfmt/dasdfmt.c 2016-04-14 16:35:01.000000000 -0400
|
|
@@ -17,6 +17,7 @@
|
|
#include "vtoc.h"
|
|
#include "util_proc.h"
|
|
#include "dasd_sys.h"
|
|
+#include <sys/wait.h>
|
|
|
|
#define BUSIDSIZE 8
|
|
|
|
@@ -48,7 +49,7 @@
|
|
*/
|
|
static void exit_usage(int exitcode)
|
|
{
|
|
- printf("Usage: %s [-htvypPLVFkC]\n"
|
|
+ printf("Usage: %s [-htvypQLVFkC]\n"
|
|
" [-l <volser> | --label=<volser>]\n"
|
|
" [-b <blocksize> | --blocksize=<blocksize>]\n"
|
|
" [-d <disk layout> | --disk_layout=<disk layout>]\n"
|
|
@@ -59,7 +60,7 @@
|
|
" -V or --version means print version\n"
|
|
" -L or --no_label means don't write disk label\n"
|
|
" -p or --progressbar means show a progress bar\n"
|
|
- " -P or --percentage means show a progress in percent\n"
|
|
+ " -Q or --percentage means show a progress in percent\n"
|
|
" -m x or --hashmarks=x means show a hashmark every x "
|
|
"cylinders\n"
|
|
" -r x or --requestsize=x means use x cylinders in one "
|
|
@@ -143,22 +144,33 @@
|
|
/*
|
|
* check given device name for blanks and some special characters
|
|
*/
|
|
-static void get_device_name(dasdfmt_info_t *info, char *name, int argc, char * argv[])
|
|
+static char* getdev(char* sysfs_path)
|
|
{
|
|
- struct util_proc_dev_entry dev_entry;
|
|
- struct stat dev_stat;
|
|
-
|
|
- if (info->node_specified && (info->device_id < argc))
|
|
- ERRMSG_EXIT(EXIT_MISUSE,"%s: Device can only specified once!\n",
|
|
- prog_name);
|
|
+ DIR* d;
|
|
+ struct dirent* de;
|
|
+
|
|
+ d = opendir(sysfs_path);
|
|
+ if(!d) ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not open directory %s.\n",prog_name,sysfs_path);
|
|
+ while((de = readdir(d)))
|
|
+ {
|
|
+ if(strncmp(de->d_name,"block:",6) == 0)
|
|
+ {
|
|
+ closedir(d);
|
|
+ return de->d_name+6;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
|
|
- if (!info->node_specified && (info->device_id >= argc))
|
|
- ERRMSG_EXIT(EXIT_MISUSE,"%s: No device specified!\n",
|
|
- prog_name);
|
|
+static void get_device_name(dasdfmt_info_t *info, char *name)
|
|
+{
|
|
+ struct util_proc_dev_entry dev_entry;
|
|
+ struct stat dev_stat;
|
|
+ char buf[PATH_MAX];
|
|
+ char devno[9];
|
|
+ char* device;
|
|
+ int i;
|
|
|
|
- if (info->device_id < argc) {
|
|
- strcpy(info->devname, argv[info->device_id]);
|
|
- } else {
|
|
if ((strchr(name, ' ') != NULL)||(strchr(name, '#') != NULL)||
|
|
(strchr(name, '[') != NULL)||(strchr(name, ']') != NULL)||
|
|
(strchr(name, '!') != NULL)||(strchr(name, '>') != NULL)||
|
|
@@ -169,9 +181,38 @@
|
|
"blanks or special characters!\n",
|
|
prog_name);
|
|
|
|
- strncpy(info->devname, name, PATH_MAX - 1);
|
|
+ if (isxdigit(name[0]) && name[1] == '.' && isxdigit(name[2]) && name[3] == '.' && strlen(name) == 8)
|
|
+ { /* x.x.xxxx format */
|
|
+ for(i=0; i<8; i++)
|
|
+ devno[i] = tolower(name[i]);
|
|
+ devno[8] = 0;
|
|
+ sprintf(buf,"/sys/bus/ccw/devices/%s",devno);
|
|
+ device = getdev(buf);
|
|
+ if(device)
|
|
+ {
|
|
+ strcpy(info->devname,"/dev/");
|
|
+ strcat(info->devname,device);
|
|
+ }
|
|
+ else ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not find device file for device no. %s\n",prog_name,name);
|
|
+ }
|
|
+ else if (isxdigit(name[0]) && isxdigit(name[1]) && isxdigit(name[2]) && isxdigit(name[3]))
|
|
+ { /* xxxx format */
|
|
+ for(i=0; i<4; i++)
|
|
+ devno[i] = tolower(name[i]);
|
|
+ devno[4] = 0;
|
|
+ sprintf(buf,"/sys/bus/ccw/devices/0.0.%s",devno);
|
|
+ device = getdev(buf);
|
|
+ if(device)
|
|
+ {
|
|
+ strcpy(info->devname,"/dev/");
|
|
+ strcat(info->devname,device);
|
|
+ }
|
|
+ else ERRMSG_EXIT(EXIT_FAILURE,"%s: Could not find device file for device no. %s\n",prog_name,name);
|
|
+ }
|
|
+ else
|
|
+ strncpy(info->devname, name, PATH_MAX - 1);
|
|
+
|
|
info->devname[PATH_MAX - 1] = '\0';
|
|
- }
|
|
|
|
if (stat(info->devname, &dev_stat) != 0)
|
|
ERRMSG_EXIT(EXIT_MISUSE,
|
|
@@ -217,8 +258,9 @@
|
|
info->reqsize_specified = 0;
|
|
info->node_specified = 0;
|
|
info->device_id = 0;
|
|
- info->keep_volser = 0;
|
|
+ info->keep_volser = 0;
|
|
info->force_host = 0;
|
|
+ info->yast_mode = 0;
|
|
}
|
|
|
|
|
|
@@ -271,7 +313,6 @@
|
|
}
|
|
|
|
|
|
-
|
|
/*
|
|
* check the volume serial for special
|
|
* characters and move blanks to the end
|
|
@@ -640,7 +681,7 @@
|
|
info->hashstep = 10;
|
|
}
|
|
|
|
- printf("Printing hashmark every %d cylinders.\n",
|
|
+ if(!info->yast_mode) printf("Printing hashmark every %d cylinders.\n",
|
|
info->hashstep);
|
|
}
|
|
|
|
@@ -649,7 +690,7 @@
|
|
|
|
k = 0;
|
|
cyl = 1;
|
|
- if (info->print_progressbar || info->print_hashmarks)
|
|
+ if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode)
|
|
printf("\n");
|
|
|
|
while (1) {
|
|
@@ -688,7 +729,7 @@
|
|
|
|
if (info->print_hashmarks)
|
|
if ((cyl / info->hashstep - hashcount) != 0) {
|
|
- printf("#");
|
|
+ printf("%d|",info->procnum);
|
|
fflush(stdout);
|
|
hashcount++;
|
|
}
|
|
@@ -709,7 +750,7 @@
|
|
break;
|
|
}
|
|
|
|
- if (info->print_progressbar || info->print_hashmarks)
|
|
+ if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode)
|
|
printf("\n\n");
|
|
}
|
|
|
|
@@ -884,17 +925,21 @@
|
|
|
|
dasdfmt_prepare_and_format(info, cylinders, heads, p);
|
|
|
|
- printf("Finished formatting the device.\n");
|
|
+ if (!info->yast_mode)
|
|
+ printf("Finished formatting the device.\n");
|
|
|
|
if (!info->writenolabel)
|
|
dasdfmt_write_labels(info, vlabel, cylinders, heads);
|
|
|
|
- printf("Rereading the partition table... ");
|
|
+ if (!info->yast_mode)
|
|
+ printf("Rereading the partition table... ");
|
|
if (reread_partition_table()) {
|
|
ERRMSG("%s: error during rereading the partition "
|
|
"table: %s.\n", prog_name, strerror(errno));
|
|
- } else
|
|
- printf("ok\n");
|
|
+ } else {
|
|
+ if (!info->yast_mode)
|
|
+ printf("ok\n");
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -905,7 +950,8 @@
|
|
volume_label_t vlabel;
|
|
char old_volser[7];
|
|
|
|
- char dev_filename[PATH_MAX];
|
|
+ char* dev_filename[MAX_DEVICES];
|
|
+ int dev_count=0;
|
|
char str[ERR_LENGTH];
|
|
char buf[7];
|
|
|
|
@@ -913,7 +959,10 @@
|
|
char *reqsize_param_str = NULL;
|
|
char *hashstep_str = NULL;
|
|
|
|
- int rc, index;
|
|
+ int rc, index, i;
|
|
+
|
|
+ int max_parallel=1;
|
|
+ int running=0;
|
|
|
|
/* Establish a handler for interrupt signals. */
|
|
signal (SIGTERM, program_interrupt_signal);
|
|
@@ -990,7 +1039,7 @@
|
|
}
|
|
break;
|
|
|
|
- case 'P':
|
|
+ case 'Q':
|
|
if (!(info.print_hashmarks || info.print_progressbar))
|
|
info.print_percentage = 1;
|
|
break;
|
|
@@ -1034,9 +1083,18 @@
|
|
info.reqsize_specified = 1;
|
|
break;
|
|
case 'f' :
|
|
- strncpy(dev_filename, optarg, PATH_MAX);
|
|
+ if(dev_count>=MAX_DEVICES)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: too many devices specified.\n",
|
|
+ prog_name);
|
|
+ dev_filename[dev_count++]=strdup(optarg);
|
|
info.node_specified=1;
|
|
break;
|
|
+ case 'Y' : /* YaST mode */
|
|
+ info.yast_mode=1;
|
|
+ break;
|
|
+ case 'P' : /* max parallel formatting processes */
|
|
+ max_parallel=atoi(optarg);
|
|
+ break;
|
|
case 'k' :
|
|
info.keep_volser=1;
|
|
break;
|
|
@@ -1059,58 +1117,147 @@
|
|
CHECK_SPEC_MAX_ONCE(info.labelspec, "label");
|
|
CHECK_SPEC_MAX_ONCE(info.writenolabel, "omit-label-writing flag");
|
|
|
|
- if (info.blksize_specified)
|
|
- PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
|
|
- "blocksize");
|
|
- if (info.reqsize_specified) {
|
|
- PARSE_PARAM_INTO(reqsize, reqsize_param_str, 10, "requestsize");
|
|
- if (reqsize < 1 || reqsize > 255)
|
|
- ERRMSG_EXIT(EXIT_FAILURE,
|
|
- "invalid requestsize %d specified\n",
|
|
- reqsize);
|
|
- } else
|
|
- reqsize = DEFAULT_REQUESTSIZE;
|
|
- if (info.print_hashmarks)
|
|
- PARSE_PARAM_INTO(info.hashstep, hashstep_str,10,"hashstep");
|
|
-
|
|
- get_device_name(&info, dev_filename, argc, argv);
|
|
+ while(info.device_id < argc) { /* devices specified at the end of cmdline */
|
|
+ if(dev_count>=MAX_DEVICES)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: too many devices specified.\n",
|
|
+ prog_name);
|
|
+ dev_filename[dev_count++]=strdup(argv[info.device_id]);
|
|
+ info.node_specified=1;
|
|
+ info.device_id++;
|
|
+ }
|
|
|
|
- if (!info.blksize_specified)
|
|
- format_params = ask_user_for_blksize(format_params);
|
|
+ if (info.node_specified == 0)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: No device specified!\n",
|
|
+ prog_name);
|
|
|
|
if (info.keep_volser) {
|
|
if(info.labelspec) {
|
|
ERRMSG_EXIT(EXIT_MISUSE,"%s: The -k and -l options are mutually exclusive\n",
|
|
prog_name);
|
|
}
|
|
- if(!(format_params.intensity & DASD_FMT_INT_COMPAT)) {
|
|
- printf("WARNING: VOLSER cannot be kept " \
|
|
- "when using the ldl format!\n");
|
|
- exit(1);
|
|
+ }
|
|
+
|
|
+ if (info.labelspec && max_parallel > 1) {
|
|
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: The -l option cannot be used with parallel formatting\n",
|
|
+ prog_name);
|
|
+ }
|
|
+
|
|
+ if(info.yast_mode) {
|
|
+ for(i=0;i<dev_count;i++) {
|
|
+ dasd_information_t dasd_info;
|
|
+ struct dasd_eckd_characteristics *characteristics;
|
|
+ unsigned int cylinders;
|
|
+
|
|
+ get_device_name(&info, dev_filename[i]);
|
|
+ if ((filedes = open(info.devname, O_RDWR)) == -1) {
|
|
+ ERRMSG("%s: Unable to open device %s: %s\n",
|
|
+ prog_name, info.devname, strerror(errno));
|
|
+ free(dev_filename[i]);
|
|
+ dev_filename[i]=(char*)-1; /* ignore device */
|
|
+ continue;
|
|
+ }
|
|
+ if (ioctl(filedes, BIODASDINFO, &dasd_info) != 0) {
|
|
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: (retrieving disk information) "
|
|
+ "IOCTL BIODASDINFO failed (%s).\n",
|
|
+ prog_name, strerror(errno));
|
|
+ free(dev_filename[i]);
|
|
+ dev_filename[i]=(char*)-1; /* ignore device */
|
|
+ close(filedes);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ characteristics =
|
|
+ (struct dasd_eckd_characteristics *) &dasd_info.characteristics;
|
|
+ if (characteristics->no_cyl == LV_COMPAT_CYL &&
|
|
+ characteristics->long_no_cyl)
|
|
+ cylinders = characteristics->long_no_cyl;
|
|
+ else
|
|
+ cylinders = characteristics->no_cyl;
|
|
+
|
|
+ printf("%d\n", cylinders);
|
|
+ close(filedes);
|
|
}
|
|
-
|
|
- if(dasdfmt_get_volser(info.devname, old_volser) == 0)
|
|
- vtoc_volume_label_set_volser(&vlabel, old_volser);
|
|
- else
|
|
- ERRMSG_EXIT(EXIT_FAILURE,"%s: VOLSER not found on device %s\n",
|
|
- prog_name, info.devname);
|
|
-
|
|
+ fflush(stdout);
|
|
}
|
|
|
|
- if ((filedes = open(info.devname, O_RDWR)) == -1)
|
|
- ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n",
|
|
- prog_name, info.devname, strerror(errno));
|
|
+ /* fork one formatting process for each device */
|
|
+ rc = 0;
|
|
+ for(i=0;i<dev_count;i++) {
|
|
+ int chpid; /* child process ID */
|
|
+ int tmp;
|
|
|
|
- check_disk(&info);
|
|
+ if(dev_filename[i]==(char*)-1) continue; /* ignore device */
|
|
|
|
- if (check_param(str, ERR_LENGTH, &format_params) < 0)
|
|
- ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
|
|
+ chpid=fork();
|
|
+ if(chpid==-1)
|
|
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to create child process: %s\n",
|
|
+ prog_name, strerror(errno));
|
|
|
|
- do_format_dasd(&info, &format_params, &vlabel);
|
|
+ if(!chpid) {
|
|
+ info.procnum=i;
|
|
+ if (info.blksize_specified)
|
|
+ PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
|
|
+ "blocksize");
|
|
+ if (info.reqsize_specified) {
|
|
+ PARSE_PARAM_INTO(reqsize, reqsize_param_str, 10, "requestsize");
|
|
+ if (reqsize < 1 || reqsize > 255)
|
|
+ ERRMSG_EXIT(EXIT_FAILURE,
|
|
+ "invalid requestsize %d specified\n",
|
|
+ reqsize);
|
|
+ } else
|
|
+ reqsize = DEFAULT_REQUESTSIZE;
|
|
+ if (info.print_hashmarks)
|
|
+ PARSE_PARAM_INTO(info.hashstep, hashstep_str,10,"hashstep");
|
|
+
|
|
+ get_device_name(&info, dev_filename[i]);
|
|
+
|
|
+ if (!info.blksize_specified)
|
|
+ format_params = ask_user_for_blksize(format_params);
|
|
+
|
|
+ if (info.keep_volser) {
|
|
+ if(format_params.intensity == 0x00) {
|
|
+ printf("WARNING: VOLSER cannot be kept " \
|
|
+ "when using the ldl format!\n");
|
|
+ exit(1);
|
|
+ }
|
|
|
|
- if (close(filedes) != 0)
|
|
- ERRMSG("%s: error during close: %s\ncontinuing...\n",
|
|
- prog_name, strerror(errno));
|
|
+ if(dasdfmt_get_volser(info.devname, old_volser) == 0)
|
|
+ vtoc_volume_label_set_volser(&vlabel, old_volser);
|
|
+ else
|
|
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: VOLSER not found on device %s\n",
|
|
+ prog_name, info.devname);
|
|
|
|
- return 0;
|
|
+ }
|
|
+
|
|
+ if ((filedes = open(info.devname, O_RDWR)) == -1)
|
|
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: Unable to open device %s: %s\n",
|
|
+ prog_name, info.devname, strerror(errno));
|
|
+
|
|
+ check_disk(&info);
|
|
+
|
|
+ if (check_param(str, ERR_LENGTH, &format_params) < 0)
|
|
+ ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
|
|
+
|
|
+ do_format_dasd(&info, &format_params, &vlabel);
|
|
+
|
|
+ if (close(filedes) != 0)
|
|
+ ERRMSG("%s: error during close: %s\ncontinuing...\n",
|
|
+ prog_name, strerror(errno));
|
|
+
|
|
+ exit(0);
|
|
+ } else {
|
|
+ running++;
|
|
+ if(running>=max_parallel) {
|
|
+ if(wait(&tmp) > 0 && WEXITSTATUS(tmp))
|
|
+ rc = WEXITSTATUS(tmp);
|
|
+ running--;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* wait until all formatting children have finished */
|
|
+ while(wait(&i) > 0)
|
|
+ if (WEXITSTATUS(i)) rc = WEXITSTATUS(i);
|
|
+
|
|
+ return rc;
|
|
}
|