+ arg2[0] = "device";
+ arg2[1] = argv[1];
+ arg2[2] = NULL;
+ rc = jt_device(2, arg2);
+
+ if (!rc) {
+ arg2[0] = "connect";
+ arg2[1] = NULL;
+ rc = jt_connect(1, arg2);
+ }
+
+ if (!rc)
+ rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
+
+ ret = do_disconnect(argv[0], 0);
+ if (!rc)
+ rc = ret;
+
+ return rc;
+}
+
+static int jt__threads(int argc, char **argv)
+{
+ int threads, next_thread;
+ int verbose;
+ int i, j;
+ int rc;
+
+ if (argc < 5) {
+ fprintf(stderr,
+ "usage: %s numthreads verbose devno <cmd [args ...]>\n",
+ argv[0]);
+ return -1;
+ }
+
+ threads = strtoul(argv[1], NULL, 0);
+
+ verbose = get_verbose(argv[2]);
+
+ printf("%s: starting %d threads on device %s running %s\n",
+ argv[0], threads, argv[3], argv[4]);
+
+ for (i = 1, next_thread = verbose; i <= threads; i++) {
+ rc = fork();
+ if (rc < 0) {
+ fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
+ strerror(rc = errno));
+ break;
+ } else if (rc == 0) {
+ thread = i;
+ argv[2] = "--device";
+ return jt__device(argc - 2, argv + 2);
+ } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
+ printf("%s: thread #%d (PID %d) started\n",
+ argv[0], i, rc);
+ rc = 0;
+ }
+
+ if (!thread) { /* parent process */
+ if (!verbose)
+ printf("%s: started %d threads\n\n", argv[0], i - 1);
+ else
+ printf("\n");
+
+ for (j = 1; j < i; j++) {
+ int status;
+ int ret = wait(&status);
+
+ if (ret < 0) {
+ fprintf(stderr, "error: %s: wait - %s\n",
+ argv[0], strerror(errno));
+ if (!rc)
+ rc = errno;
+ } else {
+ /*
+ * This is a hack. We _should_ be able to use
+ * WIFEXITED(status) to see if there was an
+ * error, but it appears to be broken and it
+ * always returns 1 (OK). See wait(2).
+ */
+ int err = WEXITSTATUS(status);
+ if (err)
+ fprintf(stderr,
+ "%s: PID %d had rc=%d\n",
+ argv[0], ret, err);
+ if (!rc)
+ rc = err;
+ }
+ }
+ }