1169695Skan/* Pexecute test program, 2169695Skan Copyright (C) 2005 Free Software Foundation, Inc. 3169695Skan Written by Ian Lance Taylor <ian@airs.com>. 4169695Skan 5169695Skan This file is part of GNU libiberty. 6169695Skan 7169695Skan This program is free software; you can redistribute it and/or modify 8169695Skan it under the terms of the GNU General Public License as published by 9169695Skan the Free Software Foundation; either version 2 of the License, or 10169695Skan (at your option) any later version. 11169695Skan 12169695Skan This program is distributed in the hope that it will be useful, 13169695Skan but WITHOUT ANY WARRANTY; without even the implied warranty of 14169695Skan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15169695Skan GNU General Public License for more details. 16169695Skan 17169695Skan You should have received a copy of the GNU General Public License 18169695Skan along with this program; if not, write to the Free Software 19169695Skan Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20169695Skan*/ 21169695Skan 22169695Skan#ifdef HAVE_CONFIG_H 23169695Skan#include "config.h" 24169695Skan#endif 25169695Skan#include "ansidecl.h" 26169695Skan#include "libiberty.h" 27169695Skan#include <stdio.h> 28169695Skan#include <signal.h> 29169695Skan#include <errno.h> 30169695Skan#ifdef HAVE_STRING_H 31169695Skan#include <string.h> 32169695Skan#endif 33169695Skan#include <sys/types.h> 34169695Skan#ifdef HAVE_STDLIB_H 35169695Skan#include <stdlib.h> 36169695Skan#endif 37169695Skan#ifdef HAVE_UNISTD_H 38169695Skan#include <unistd.h> 39169695Skan#endif 40169695Skan#ifdef HAVE_SYS_WAIT_H 41169695Skan#include <sys/wait.h> 42169695Skan#endif 43169695Skan#ifdef HAVE_SYS_TIME_H 44169695Skan#include <sys/time.h> 45169695Skan#endif 46169695Skan#ifdef HAVE_SYS_RESOURCE_H 47169695Skan#include <sys/resource.h> 48169695Skan#endif 49169695Skan 50169695Skan#ifndef WIFSIGNALED 51169695Skan#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f) 52169695Skan#endif 53169695Skan#ifndef WTERMSIG 54169695Skan#define WTERMSIG(S) ((S) & 0x7f) 55169695Skan#endif 56169695Skan#ifndef WIFEXITED 57169695Skan#define WIFEXITED(S) (((S) & 0xff) == 0) 58169695Skan#endif 59169695Skan#ifndef WEXITSTATUS 60169695Skan#define WEXITSTATUS(S) (((S) & 0xff00) >> 8) 61169695Skan#endif 62169695Skan#ifndef WSTOPSIG 63169695Skan#define WSTOPSIG WEXITSTATUS 64169695Skan#endif 65169695Skan#ifndef WCOREDUMP 66169695Skan#define WCOREDUMP(S) ((S) & WCOREFLG) 67169695Skan#endif 68169695Skan#ifndef WCOREFLG 69169695Skan#define WCOREFLG 0200 70169695Skan#endif 71169695Skan 72169695Skan#ifndef EXIT_SUCCESS 73169695Skan#define EXIT_SUCCESS 0 74169695Skan#endif 75169695Skan 76169695Skan#ifndef EXIT_FAILURE 77169695Skan#define EXIT_FAILURE 1 78169695Skan#endif 79169695Skan 80169695Skan/* When this program is run with no arguments, it runs some tests of 81169695Skan the libiberty pexecute functions. As a test program, it simply 82169695Skan invokes itself with various arguments. 83169695Skan 84169695Skan argv[1]: 85169695Skan *empty string* Run tests, exit with success status 86169695Skan exit Exit success 87169695Skan error Exit error 88169695Skan abort Abort 89169695Skan echo Echo remaining arguments, exit success 90169695Skan echoerr Echo next arg to stdout, next to stderr, repeat 91169695Skan copy Copy stdin to stdout 92169695Skan write Write stdin to file named in next argument 93169695Skan*/ 94169695Skan 95169695Skanstatic void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN; 96169695Skanstatic void error (int, const char *); 97169695Skanstatic void check_line (int, FILE *, const char *); 98169695Skanstatic void do_cmd (int, char **) ATTRIBUTE_NORETURN; 99169695Skan 100169695Skan/* The number of errors we have seen. */ 101169695Skan 102169695Skanstatic int error_count; 103169695Skan 104169695Skan/* Print a fatal error and exit. LINE is the line number where we 105169695Skan detected the error, ERRMSG is the error message to print, and ERR 106169695Skan is 0 or an errno value to print. */ 107169695Skan 108169695Skanstatic void 109169695Skanfatal_error (int line, const char *errmsg, int err) 110169695Skan{ 111169695Skan fprintf (stderr, "test-pexecute:%d: %s", line, errmsg); 112169695Skan if (errno != 0) 113169695Skan fprintf (stderr, ": %s", xstrerror (err)); 114169695Skan fprintf (stderr, "\n"); 115169695Skan exit (EXIT_FAILURE); 116169695Skan} 117169695Skan 118169695Skan#define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR) 119169695Skan 120169695Skan/* Print an error message and bump the error count. LINE is the line 121169695Skan number where we detected the error, ERRMSG is the error to 122169695Skan print. */ 123169695Skan 124169695Skanstatic void 125169695Skanerror (int line, const char *errmsg) 126169695Skan{ 127169695Skan fprintf (stderr, "test-pexecute:%d: %s\n", line, errmsg); 128169695Skan ++error_count; 129169695Skan} 130169695Skan 131169695Skan#define ERROR(ERRMSG) error (__LINE__, ERRMSG) 132169695Skan 133169695Skan/* Check a line in a file. */ 134169695Skan 135169695Skanstatic void 136169695Skancheck_line (int line, FILE *e, const char *str) 137169695Skan{ 138169695Skan const char *p; 139169695Skan int c; 140169695Skan char buf[1000]; 141169695Skan 142169695Skan p = str; 143169695Skan while (1) 144169695Skan { 145169695Skan c = getc (e); 146169695Skan 147169695Skan if (*p == '\0') 148169695Skan { 149169695Skan if (c != '\n') 150169695Skan { 151169695Skan snprintf (buf, sizeof buf, "got '%c' when expecting newline", c); 152169695Skan fatal_error (line, buf, 0); 153169695Skan } 154169695Skan c = getc (e); 155169695Skan if (c != EOF) 156169695Skan { 157169695Skan snprintf (buf, sizeof buf, "got '%c' when expecting EOF", c); 158169695Skan fatal_error (line, buf, 0); 159169695Skan } 160169695Skan return; 161169695Skan } 162169695Skan 163169695Skan if (c != *p) 164169695Skan { 165169695Skan snprintf (buf, sizeof buf, "expected '%c', got '%c'", *p, c); 166169695Skan fatal_error (line, buf, 0); 167169695Skan } 168169695Skan 169169695Skan ++p; 170169695Skan } 171169695Skan} 172169695Skan 173169695Skan#define CHECK_LINE(E, STR) check_line (__LINE__, E, STR) 174169695Skan 175169695Skan/* Main function for the pexecute tester. Run the tests. */ 176169695Skan 177169695Skanint 178169695Skanmain (int argc, char **argv) 179169695Skan{ 180169695Skan int trace; 181169695Skan struct pex_obj *test_pex_tmp; 182169695Skan int test_pex_status; 183169695Skan FILE *test_pex_file; 184169695Skan struct pex_obj *pex1; 185169695Skan char *subargv[10]; 186169695Skan int status; 187169695Skan FILE *e; 188169695Skan int statuses[10]; 189169695Skan 190169695Skan trace = 0; 191169695Skan if (argc > 1 && strcmp (argv[1], "-t") == 0) 192169695Skan { 193169695Skan trace = 1; 194169695Skan --argc; 195169695Skan ++argv; 196169695Skan } 197169695Skan 198169695Skan if (argc > 1) 199169695Skan do_cmd (argc, argv); 200169695Skan 201169695Skan#define TEST_PEX_INIT(FLAGS, TEMPBASE) \ 202169695Skan (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE)) \ 203169695Skan != NULL) \ 204169695Skan ? test_pex_tmp \ 205169695Skan : (FATAL_ERROR ("pex_init failed", 0), NULL)) 206169695Skan 207169695Skan#define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME) \ 208169695Skan do \ 209169695Skan { \ 210169695Skan int err; \ 211169695Skan const char *pex_run_err; \ 212169695Skan if (trace) \ 213169695Skan fprintf (stderr, "Line %d: running %s %s\n", \ 214169695Skan __LINE__, EXECUTABLE, ARGV[0]); \ 215169695Skan pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, \ 216169695Skan ERRNAME, &err); \ 217169695Skan if (pex_run_err != NULL) \ 218169695Skan FATAL_ERROR (pex_run_err, err); \ 219169695Skan } \ 220169695Skan while (0) 221169695Skan 222169695Skan#define TEST_PEX_GET_STATUS_1(PEXOBJ) \ 223169695Skan (pex_get_status (PEXOBJ, 1, &test_pex_status) \ 224169695Skan ? test_pex_status \ 225169695Skan : (FATAL_ERROR ("pex_get_status failed", errno), 1)) 226169695Skan 227169695Skan#define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR) \ 228169695Skan do \ 229169695Skan { \ 230169695Skan if (!pex_get_status (PEXOBJ, COUNT, VECTOR)) \ 231169695Skan FATAL_ERROR ("pex_get_status failed", errno); \ 232169695Skan } \ 233169695Skan while (0) 234169695Skan 235169695Skan#define TEST_PEX_READ_OUTPUT(PEXOBJ) \ 236169695Skan ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL \ 237169695Skan ? test_pex_file \ 238169695Skan : (FATAL_ERROR ("pex_read_output failed", errno), NULL)) 239169695Skan 240169695Skan remove ("temp.x"); 241169695Skan remove ("temp.y"); 242169695Skan 243169695Skan memset (subargv, 0, sizeof subargv); 244169695Skan 245169695Skan subargv[0] = "./test-pexecute"; 246169695Skan 247169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 248169695Skan subargv[1] = "exit"; 249169695Skan subargv[2] = NULL; 250169695Skan TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL); 251169695Skan status = TEST_PEX_GET_STATUS_1 (pex1); 252169695Skan if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 253169695Skan ERROR ("exit failed"); 254169695Skan pex_free (pex1); 255169695Skan 256169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 257169695Skan subargv[1] = "error"; 258169695Skan subargv[2] = NULL; 259169695Skan TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL); 260169695Skan status = TEST_PEX_GET_STATUS_1 (pex1); 261169695Skan if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE) 262169695Skan ERROR ("error test failed"); 263169695Skan pex_free (pex1); 264169695Skan 265169695Skan /* We redirect stderr to a file to avoid an error message which is 266169695Skan printed on mingw32 when the child calls abort. */ 267169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL); 268169695Skan subargv[1] = "abort"; 269169695Skan subargv[2] = NULL; 270169695Skan TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z"); 271169695Skan status = TEST_PEX_GET_STATUS_1 (pex1); 272169695Skan if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT) 273169695Skan ERROR ("abort failed"); 274169695Skan pex_free (pex1); 275169695Skan remove ("temp.z"); 276169695Skan 277169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 278169695Skan subargv[1] = "echo"; 279169695Skan subargv[2] = "foo"; 280169695Skan subargv[3] = NULL; 281169695Skan TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL); 282169695Skan e = TEST_PEX_READ_OUTPUT (pex1); 283169695Skan CHECK_LINE (e, "foo"); 284169695Skan if (TEST_PEX_GET_STATUS_1 (pex1) != 0) 285169695Skan ERROR ("echo exit status failed"); 286169695Skan pex_free (pex1); 287169695Skan 288169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 289169695Skan subargv[1] = "echo"; 290169695Skan subargv[2] = "bar"; 291169695Skan subargv[3] = NULL; 292169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 293169695Skan subargv[1] = "copy"; 294169695Skan subargv[2] = NULL; 295169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 296169695Skan e = TEST_PEX_READ_OUTPUT (pex1); 297169695Skan CHECK_LINE (e, "bar"); 298169695Skan TEST_PEX_GET_STATUS (pex1, 2, statuses); 299169695Skan if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 300169695Skan || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 301169695Skan ERROR ("copy exit status failed"); 302169695Skan pex_free (pex1); 303169695Skan if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 304169695Skan ERROR ("temporary files exist"); 305169695Skan 306169695Skan pex1 = TEST_PEX_INIT (0, "temp"); 307169695Skan subargv[1] = "echo"; 308169695Skan subargv[2] = "bar"; 309169695Skan subargv[3] = NULL; 310169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 311169695Skan subargv[1] = "copy"; 312169695Skan subargv[2] = NULL; 313169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 314169695Skan e = TEST_PEX_READ_OUTPUT (pex1); 315169695Skan CHECK_LINE (e, "bar"); 316169695Skan TEST_PEX_GET_STATUS (pex1, 2, statuses); 317169695Skan if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 318169695Skan || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 319169695Skan ERROR ("copy exit status failed"); 320169695Skan pex_free (pex1); 321169695Skan if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 322169695Skan ERROR ("temporary files exist"); 323169695Skan 324169695Skan pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp"); 325169695Skan subargv[1] = "echo"; 326169695Skan subargv[2] = "quux"; 327169695Skan subargv[3] = NULL; 328169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL); 329169695Skan subargv[1] = "copy"; 330169695Skan subargv[2] = NULL; 331169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 332169695Skan e = TEST_PEX_READ_OUTPUT (pex1); 333169695Skan CHECK_LINE (e, "quux"); 334169695Skan TEST_PEX_GET_STATUS (pex1, 2, statuses); 335169695Skan if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 336169695Skan || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 337169695Skan ERROR ("copy temp exit status failed"); 338169695Skan e = fopen ("temp.x", "r"); 339169695Skan if (e == NULL) 340169695Skan FATAL_ERROR ("fopen temp.x failed in copy temp", errno); 341169695Skan CHECK_LINE (e, "quux"); 342169695Skan fclose (e); 343169695Skan e = fopen ("temp.y", "r"); 344169695Skan if (e == NULL) 345169695Skan FATAL_ERROR ("fopen temp.y failed in copy temp", errno); 346169695Skan CHECK_LINE (e, "quux"); 347169695Skan fclose (e); 348169695Skan pex_free (pex1); 349169695Skan remove ("temp.x"); 350169695Skan remove ("temp.y"); 351169695Skan 352169695Skan pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp"); 353169695Skan subargv[1] = "echoerr"; 354169695Skan subargv[2] = "one"; 355169695Skan subargv[3] = "two"; 356169695Skan subargv[4] = NULL; 357169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x"); 358169695Skan subargv[1] = "write"; 359169695Skan subargv[2] = "temp2.y"; 360169695Skan subargv[3] = NULL; 361169695Skan TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL); 362169695Skan TEST_PEX_GET_STATUS (pex1, 2, statuses); 363169695Skan if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS 364169695Skan || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS) 365169695Skan ERROR ("echoerr exit status failed"); 366169695Skan pex_free (pex1); 367169695Skan if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL) 368169695Skan ERROR ("temporary files exist"); 369169695Skan e = fopen ("temp2.x", "r"); 370169695Skan if (e == NULL) 371169695Skan FATAL_ERROR ("fopen temp2.x failed in echoerr", errno); 372169695Skan CHECK_LINE (e, "two"); 373169695Skan fclose (e); 374169695Skan e = fopen ("temp2.y", "r"); 375169695Skan if (e == NULL) 376169695Skan FATAL_ERROR ("fopen temp2.y failed in echoerr", errno); 377169695Skan CHECK_LINE (e, "one"); 378169695Skan fclose (e); 379169695Skan remove ("temp2.x"); 380169695Skan remove ("temp2.y"); 381169695Skan 382169695Skan /* Test the old pexecute interface. */ 383169695Skan { 384169695Skan int pid1, pid2; 385169695Skan char *errmsg_fmt; 386169695Skan char *errmsg_arg; 387169695Skan char errbuf1[1000]; 388169695Skan char errbuf2[1000]; 389169695Skan 390169695Skan subargv[1] = "echo"; 391169695Skan subargv[2] = "oldpexecute"; 392169695Skan subargv[3] = NULL; 393169695Skan pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp", 394169695Skan &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST); 395169695Skan if (pid1 < 0) 396169695Skan { 397169695Skan snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg); 398169695Skan snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1); 399169695Skan FATAL_ERROR (errbuf2, 0); 400169695Skan } 401169695Skan 402169695Skan subargv[1] = "write"; 403169695Skan subargv[2] = "temp.y"; 404169695Skan subargv[3] = NULL; 405169695Skan pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp", 406169695Skan &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST); 407169695Skan if (pid2 < 0) 408169695Skan { 409169695Skan snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg); 410169695Skan snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1); 411169695Skan FATAL_ERROR (errbuf2, 0); 412169695Skan } 413169695Skan 414169695Skan if (pwait (pid1, &status, 0) < 0) 415169695Skan FATAL_ERROR ("write pwait 1 failed", errno); 416169695Skan if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 417169695Skan ERROR ("write exit status 1 failed"); 418169695Skan 419169695Skan if (pwait (pid2, &status, 0) < 0) 420169695Skan FATAL_ERROR ("write pwait 1 failed", errno); 421169695Skan if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) 422169695Skan ERROR ("write exit status 2 failed"); 423169695Skan 424169695Skan e = fopen ("temp.y", "r"); 425169695Skan if (e == NULL) 426169695Skan FATAL_ERROR ("fopen temp.y failed in copy temp", errno); 427169695Skan CHECK_LINE (e, "oldpexecute"); 428169695Skan fclose (e); 429169695Skan 430169695Skan remove ("temp.y"); 431169695Skan } 432169695Skan 433169695Skan if (trace) 434169695Skan fprintf (stderr, "Exiting with status %d\n", error_count); 435169695Skan 436169695Skan return error_count; 437169695Skan} 438169695Skan 439169695Skan/* Execute one of the special testing commands. */ 440169695Skan 441169695Skanstatic void 442169695Skando_cmd (int argc, char **argv) 443169695Skan{ 444169695Skan const char *s; 445169695Skan 446169695Skan /* Try to prevent generating a core dump. */ 447169695Skan#ifdef RLIMIT_CORE 448169695Skan { 449169695Skan struct rlimit r; 450169695Skan 451169695Skan r.rlim_cur = 0; 452169695Skan r.rlim_max = 0; 453169695Skan setrlimit (RLIMIT_CORE, &r); 454169695Skan } 455169695Skan#endif 456169695Skan 457169695Skan s = argv[1]; 458169695Skan if (strcmp (s, "exit") == 0) 459169695Skan exit (EXIT_SUCCESS); 460169695Skan else if (strcmp (s, "echo") == 0) 461169695Skan { 462169695Skan int i; 463169695Skan 464169695Skan for (i = 2; i < argc; ++i) 465169695Skan { 466169695Skan if (i > 2) 467169695Skan putchar (' '); 468169695Skan fputs (argv[i], stdout); 469169695Skan } 470169695Skan putchar ('\n'); 471169695Skan exit (EXIT_SUCCESS); 472169695Skan } 473169695Skan else if (strcmp (s, "echoerr") == 0) 474169695Skan { 475169695Skan int i; 476169695Skan 477169695Skan for (i = 2; i < argc; ++i) 478169695Skan { 479169695Skan if (i > 3) 480169695Skan putc (' ', (i & 1) == 0 ? stdout : stderr); 481169695Skan fputs (argv[i], (i & 1) == 0 ? stdout : stderr); 482169695Skan } 483169695Skan putc ('\n', stdout); 484169695Skan putc ('\n', stderr); 485169695Skan exit (EXIT_SUCCESS); 486169695Skan } 487169695Skan else if (strcmp (s, "error") == 0) 488169695Skan exit (EXIT_FAILURE); 489169695Skan else if (strcmp (s, "abort") == 0) 490169695Skan abort (); 491169695Skan else if (strcmp (s, "copy") == 0) 492169695Skan { 493169695Skan int c; 494169695Skan 495169695Skan while ((c = getchar ()) != EOF) 496169695Skan putchar (c); 497169695Skan exit (EXIT_SUCCESS); 498169695Skan } 499169695Skan else if (strcmp (s, "write") == 0) 500169695Skan { 501169695Skan FILE *e; 502169695Skan int c; 503169695Skan 504169695Skan e = fopen (argv[2], "w"); 505169695Skan if (e == NULL) 506169695Skan FATAL_ERROR ("fopen for write failed", errno); 507169695Skan while ((c = getchar ()) != EOF) 508169695Skan putc (c, e); 509169695Skan if (fclose (e) != 0) 510169695Skan FATAL_ERROR ("fclose for write failed", errno); 511169695Skan exit (EXIT_SUCCESS); 512169695Skan } 513169695Skan else 514169695Skan { 515169695Skan char buf[1000]; 516169695Skan 517169695Skan snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]); 518169695Skan FATAL_ERROR (buf, 0); 519169695Skan } 520169695Skan 521169695Skan exit (EXIT_FAILURE); 522169695Skan} 523