117721Speter/* error.c -- error handler for noninteractive utilities 217721Speter Copyright (C) 1990-1992 Free Software Foundation, Inc. 317721Speter 417721Speter This program is free software; you can redistribute it and/or modify 517721Speter it under the terms of the GNU General Public License as published by 617721Speter the Free Software Foundation; either version 2, or (at your option) 717721Speter any later version. 817721Speter 917721Speter This program is distributed in the hope that it will be useful, 1017721Speter but WITHOUT ANY WARRANTY; without even the implied warranty of 1117721Speter MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1225839Speter GNU General Public License for more details. */ 1317721Speter 1417721Speter/* David MacKenzie */ 1517721Speter/* Brian Berliner added support for CVS */ 1617721Speter 1717721Speter#include "cvs.h" 1817721Speter 1917721Speter#include <stdio.h> 2017721Speter 2117721Speter/* If non-zero, error will use the CVS protocol to stdout to report error 2217721Speter messages. This will only be set in the CVS server parent process; 2317721Speter most other code is run via do_cvs_command, which forks off a child 2417721Speter process and packages up its stderr in the protocol. */ 2517721Speterint error_use_protocol; 2617721Speter 2717721Speter#ifdef HAVE_VPRINTF 2817721Speter 2925839Speter#ifdef __STDC__ 3017721Speter#include <stdarg.h> 3117721Speter#define VA_START(args, lastarg) va_start(args, lastarg) 3217721Speter#else /* ! __STDC__ */ 3317721Speter#include <varargs.h> 3417721Speter#define VA_START(args, lastarg) va_start(args) 3517721Speter#endif /* __STDC__ */ 3617721Speter 3717721Speter#else /* ! HAVE_VPRINTF */ 3817721Speter 3917721Speter#ifdef HAVE_DOPRNT 4017721Speter#define va_alist args 4117721Speter#define va_dcl int args; 4217721Speter#else /* ! HAVE_DOPRNT */ 4317721Speter#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 4417721Speter#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; 4517721Speter#endif /* HAVE_DOPRNT */ 4617721Speter 4717721Speter#endif /* HAVE_VPRINTF */ 4817721Speter 4917721Speter#if STDC_HEADERS 5017721Speter#include <stdlib.h> 5117721Speter#include <string.h> 5217721Speter#else /* ! STDC_HEADERS */ 5325839Speter#ifdef __STDC__ 5417721Spetervoid exit(int status); 5517721Speter#else /* ! __STDC__ */ 5617721Spetervoid exit (); 5717721Speter#endif /* __STDC__ */ 5817721Speter#endif /* STDC_HEADERS */ 5917721Speter 6025839Speter#ifndef strerror 6117721Speterextern char *strerror (); 6225839Speter#endif 6317721Speter 6425839Spetervoid 6525839Spetererror_exit PROTO ((void)) 6617721Speter{ 6766525Speter rcs_cleanup (); 6866525Speter Lock_Cleanup (); 6925839Speter#ifdef SERVER_SUPPORT 7025839Speter if (server_active) 7125839Speter server_cleanup (0); 7225839Speter#endif 7325839Speter#ifdef SYSTEM_CLEANUP 7425839Speter /* Hook for OS-specific behavior, for example socket subsystems on 7525839Speter NT and OS2 or dealing with windows and arguments on Mac. */ 7625839Speter SYSTEM_CLEANUP (); 7725839Speter#endif 7825839Speter exit (EXIT_FAILURE); 7917721Speter} 8017721Speter 8117721Speter/* Print the program name and error message MESSAGE, which is a printf-style 8254427Speter format string with optional args. This is a very limited printf subset: 8354427Speter %s, %d, %c, %x and %% only (without anything between the % and the s, 8454427Speter d, &c). Callers who want something fancier can use sprintf. 8554427Speter 8617721Speter If ERRNUM is nonzero, print its corresponding system error message. 8725839Speter Exit with status EXIT_FAILURE if STATUS is nonzero. If MESSAGE is "", 8832785Speter no need to print a message. 8932785Speter 9032785Speter I think this is largely cleaned up to the point where it does the right 9132785Speter thing for the server, whether the normal server_active (child process) 9232785Speter case or the error_use_protocol (parent process) case. The one exception 9332785Speter is that STATUS nonzero for error_use_protocol probably doesn't work yet; 9444852Speter in that case still need to use the pending_error machinery in server.c. 9544852Speter 9644852Speter error() does not molest errno; some code (e.g. Entries_Open) depends 9744852Speter on being able to say something like: 9844852Speter error (0, 0, "foo"); 9944852Speter error (0, errno, "bar"); 10044852Speter 10144852Speter */ 10244852Speter 10317721Speter/* VARARGS */ 10417721Spetervoid 10554427Speter#if defined (__STDC__) 10617721Spetererror (int status, int errnum, const char *message, ...) 10717721Speter#else 10817721Spetererror (status, errnum, message, va_alist) 10917721Speter int status; 11017721Speter int errnum; 11117721Speter const char *message; 11217721Speter va_dcl 11317721Speter#endif 11417721Speter{ 11544852Speter int save_errno = errno; 11644852Speter 11725839Speter if (message[0] != '\0') 11817721Speter { 11925839Speter va_list args; 12054427Speter const char *p; 12154427Speter char *q; 12254427Speter char *str; 12354427Speter int num; 12481404Speter long lnum; 12554427Speter unsigned int unum; 12681404Speter unsigned long ulnum; 12754427Speter int ch; 12866525Speter char buf[100]; 12917721Speter 13054427Speter cvs_outerr (program_name, 0); 131128266Speter if (cvs_cmd_name && *cvs_cmd_name) 13217721Speter { 13354427Speter cvs_outerr (" ", 1); 13454427Speter if (status != 0) 13554427Speter cvs_outerr ("[", 1); 136128266Speter cvs_outerr (cvs_cmd_name, 0); 13754427Speter if (status != 0) 13854427Speter cvs_outerr (" aborted]", 0); 13917721Speter } 14054427Speter cvs_outerr (": ", 2); 14154427Speter 14254427Speter VA_START (args, message); 14354427Speter p = message; 14454427Speter while ((q = strchr (p, '%')) != NULL) 14517721Speter { 14654427Speter static const char msg[] = 14754427Speter "\ninternal error: bad % in error()\n"; 14854427Speter if (q - p > 0) 14954427Speter cvs_outerr (p, q - p); 15054427Speter 15154427Speter switch (q[1]) 15217721Speter { 15354427Speter case 's': 15454427Speter str = va_arg (args, char *); 15554427Speter cvs_outerr (str, strlen (str)); 15654427Speter break; 15754427Speter case 'd': 15854427Speter num = va_arg (args, int); 15954427Speter sprintf (buf, "%d", num); 16054427Speter cvs_outerr (buf, strlen (buf)); 16154427Speter break; 16281404Speter case 'l': 16381404Speter if (q[2] == 'd') 16481404Speter { 16581404Speter lnum = va_arg (args, long); 16681404Speter sprintf (buf, "%ld", lnum); 16781404Speter } 16881404Speter else if (q[2] == 'u') 16981404Speter { 17081404Speter ulnum = va_arg (args, unsigned long); 17181404Speter sprintf (buf, "%lu", ulnum); 17281404Speter } 17381404Speter else goto bad; 17481404Speter cvs_outerr (buf, strlen (buf)); 17581404Speter q++; 17681404Speter break; 17754427Speter case 'x': 17854427Speter unum = va_arg (args, unsigned int); 17954427Speter sprintf (buf, "%x", unum); 18054427Speter cvs_outerr (buf, strlen (buf)); 18154427Speter break; 18254427Speter case 'c': 18354427Speter ch = va_arg (args, int); 18454427Speter buf[0] = ch; 18554427Speter cvs_outerr (buf, 1); 18654427Speter break; 18754427Speter case '%': 18854427Speter cvs_outerr ("%", 1); 18954427Speter break; 19054427Speter default: 19181404Speter bad: 19254427Speter cvs_outerr (msg, sizeof (msg) - 1); 19354427Speter /* Don't just keep going, because q + 1 might point to the 19454427Speter terminating '\0'. */ 19554427Speter goto out; 19617721Speter } 19754427Speter p = q + 2; 19817721Speter } 19954427Speter cvs_outerr (p, strlen (p)); 20054427Speter out: 20154427Speter va_end (args); 20217721Speter 20354427Speter if (errnum != 0) 20425839Speter { 20554427Speter cvs_outerr (": ", 2); 20654427Speter cvs_outerr (strerror (errnum), 0); 20725839Speter } 20854427Speter cvs_outerr ("\n", 1); 20925839Speter } 21025839Speter 21117721Speter if (status) 21225839Speter error_exit (); 21344852Speter errno = save_errno; 21417721Speter} 21517721Speter 21617721Speter/* Print the program name and error message MESSAGE, which is a printf-style 21717721Speter format string with optional args to the file specified by FP. 21817721Speter If ERRNUM is nonzero, print its corresponding system error message. 21917721Speter Exit with status EXIT_FAILURE if STATUS is nonzero. */ 22017721Speter/* VARARGS */ 22117721Spetervoid 22225839Speter#if defined (HAVE_VPRINTF) && defined (__STDC__) 22366525Speterfperrmsg (FILE *fp, int status, int errnum, char *message, ...) 22417721Speter#else 22566525Speterfperrmsg (fp, status, errnum, message, va_alist) 22617721Speter FILE *fp; 22717721Speter int status; 22817721Speter int errnum; 22917721Speter char *message; 23017721Speter va_dcl 23117721Speter#endif 23217721Speter{ 23317721Speter#ifdef HAVE_VPRINTF 23417721Speter va_list args; 23517721Speter#endif 23617721Speter 23717721Speter fprintf (fp, "%s: ", program_name); 23817721Speter#ifdef HAVE_VPRINTF 23917721Speter VA_START (args, message); 24017721Speter vfprintf (fp, message, args); 24117721Speter va_end (args); 24217721Speter#else 24317721Speter#ifdef HAVE_DOPRNT 24417721Speter _doprnt (message, &args, fp); 24517721Speter#else 24617721Speter fprintf (fp, message, a1, a2, a3, a4, a5, a6, a7, a8); 24717721Speter#endif 24817721Speter#endif 24917721Speter if (errnum) 25017721Speter fprintf (fp, ": %s", strerror (errnum)); 25117721Speter putc ('\n', fp); 25217721Speter fflush (fp); 25317721Speter if (status) 25425839Speter error_exit (); 25517721Speter} 256