Long slumber — apologies. TL;DR — you may close this bug report. The original report was against Mac OS X El Capitan 10.11. Later versions of OS X 10.11 (definitively from 10.11.4, possibly earlier) have the problem fixed.
Gory details: On 10.11.5, I ran the t.c file you provided and it worked cleanly. It exited with status 4, but there was no problem with the directory cleanup. I still have a gruesome directory which 'Finder' (the OS X GUI tool) cannot clean up when it is in Trash. I've placed it into a directory $HOME/tmp/top-level and renamed 'confdir-14B---' to names such as ' confdir-000000' .. 'confdir-000335' (using the rename-it.sh script attached) I run into problems with 'confdir-000335'; although its mode field is 40700 (a directory with 700 permissions), I get errno 2 'no such file or directory' when I execute 'chdir("confdir-000335")' from directory "top-level/…/confdir-000334". I created a program do_cd.c (attached, along with the error reporting code I use, stderr.[ch]), loosely related to t.c that runs into a hard wall at level 335, whether run from top-level or from top-level/…/confdir-000129. The shell (Bash 3.2.57(1)) gives up (cannot do cd) after around top-level/…/confdir-000129, even trying 'cd top-level/…/confdir-000061' (successful) followed by 'cd confdir-000062/…/confdir-000129' (that succeeds, but 131 fails with 'path name too long'). I finally used 'cd top-level/…/confdir-000061; mv * ~/tmp/top-level' to move the hierarchy up the file system — so I had, briefly, top-level/confdir-000001 with a path down to confdir-000061, and top-level/confdir-000062 with a path down to confdir-000335. Running 'rm -fr confdir-000001' was able to clean that section up. Using do_cd, there were still problems with 'chdir("confdir-000335")' , but 'rm -fr confdir-000062' (from the ~/tmp/top-level directory) worked, so I finally don't have the wreckage of the attempted build cluttering up my file system. I agree that what I found was a bug in OSX, and so apparently does Apple since the failure no longer occurs. JFTR: the versions of Mac OS X 10.11.x El Capitan so far were announced in email on these dates: 10.11 — 2015-09-30 10.11.1 — 2015-10-21 10.11.2 — 2015-12-15 10.11.3 — 2016-01-19 10.11.4 — 2016-04-21 10.11.5 — 2016-05-16 Since I reported the problem on 2015-10-12, I must have been using 10.11 at the time, as I reported. On Tue, Oct 13, 2015 at 11:39 AM, Paul Eggert <egg...@cs.ucla.edu> wrote: > On 10/12/2015 02:00 PM, Jonathan Leffler wrote: > >> 1. Has anyone else seen anything similar on El Capitan? >> 2. Does anyone have an idea how to get rid of the trashed directories? >> 3. How can we modify the test so it doesn't fail catastrophically like >> this on El Capitan? >> 4. Do I need to report a bug to Apple separately from this report to GNU >> Tar? >> > > For (4), OS X is clearly busted here. A user-mode application shouldn't be > able to create a directory that 'rm -fr' can't remove. Please feel free to > report the bug to Apple. The problem will occur with many GNU tools' > installation procedure, as they're all using Gnulib and Gnulib tries to > check for getcwd bugs like this one. > > For (2) I suggest using coreutils; 'rm -fr directory should do the trick > if you're using GNU rm. > > For (3) we need to figure out why the test doesn't clean up after itself > on El Capitan. It's supposed to. Please compile and run the attached test > program in a place where you don't mind having long directory chains. On > my GNU/Linux host, I can do something like this: > > gcc t.c > strace ./a.out > > and the 'strace' output contains the following, showing that the test > program cleans up after itself. Please find out why it's not doing so under > El Capitan. OS X lacks strace, but you can use a debugger or dtruss or > whatever your favorite tool is. Thanks. > > mkdir("confdir-14B---", 0700) = 0 > chdir("confdir-14B---") = 0 > mkdir("confdir-14B---", 0700) = 0 > chdir("confdir-14B---") = 0 > ... > mkdir("confdir-14B---", 0700) = 0 > chdir("confdir-14B---") = 0 > getcwd(0x1736010, 4096) = -1 ENAMETOOLONG (File name too > long) > [a whole bunch of other stuff, which eventually succeeds. Now comes > cleanup time....] > rmdir("confdir-14B---") = -1 ENOENT (No such file or > directory) > chdir("..") = 0 > rmdir("confdir-14B---") = 0 > chdir("..") = 0 > ... > chdir("..") = 0 > rmdir("confdir-14B---") = 0 > exit_group(0) = ? > > -- Jonathan Leffler <jonathan.leff...@gmail.com> #include <disclaimer.h> Guardian of DBD::Informix - v2015.1101 - http://dbi.perl.org "Blessed are we who can laugh at ourselves, for we shall never cease to be amused."
#include "stderr.h" #include <assert.h> #include <dirent.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> int main(int argc, char **argv) { err_setarg0(argv[0]); if (argc != 2) err_usage("directory"); struct stat sb; char *name = argv[1]; if (stat(name, &sb) != 0) err_syserr("Unable to stat directory '%s': ", name); if (!S_ISDIR(sb.st_mode)) err_error("File '%s' is not a directory (mode = %o)\n", name, sb.st_mode); size_t bufmax = 4096; char *buffer = malloc(bufmax); if (buffer == 0) err_syserr("Failed to malloc %zu bytes: ", bufmax); strcpy(buffer, name); size_t buflen = strlen(buffer); assert(buflen < bufmax); size_t levels = 0; while (buflen < bufmax) { if (chdir(name) != 0) { err_sysrem("Failed to chdir into '%s'\n", name); err_remark("%3zu (%4zu): %s\n", ++levels, buflen, buffer); err_error("Mode = %o\n", sb.st_mode); } printf("%3zu (%4zu): %s\n", ++levels, buflen, buffer); DIR *dp = opendir("."); struct dirent *nm; while ((nm = readdir(dp)) != 0) { if (strcmp(nm->d_name, ".") == 0 || strcmp(nm->d_name, "..") == 0) continue; if (stat(nm->d_name, &sb) != 0) err_syserr("Unable to stat name '%s': ", nm->d_name); if (!S_ISDIR(sb.st_mode)) { err_sysrem("Name '%s' is not a directory (mode = %o)\n", nm->d_name, sb.st_mode); if (unlink(nm->d_name) != 0) err_syserr("Failed to remove non-directory '%s': ", nm->d_name); err_remark("Removed '%s' from '%s'\n", nm->d_name, buffer); continue; } size_t namlen = strlen(nm->d_name); if (buflen + namlen + 1 >= bufmax) { err_remark("Allocate space - name is too long: additional name '%s' - (%zu levels) %zu '%s'\n", nm->d_name, levels, buflen, buffer); size_t newmax = 2 * bufmax; char *newbuf = realloc(buffer, newmax); if (newbuf == 0) err_syserr("Failed to reallocate %zu bytes memory: ", newmax); bufmax = newmax; buffer = newbuf; } buffer[buflen++] = '/'; strcpy(&buffer[buflen], nm->d_name); name = &buffer[buflen]; buflen += namlen; break; } closedir(dp); } return 0; }
/* @(#)File: $RCSfile: stderr.c,v $ @(#)Version: $Revision: 10.14 $ @(#)Last changed: $Date: 2015/06/02 03:04:32 $ @(#)Purpose: Error reporting routines @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1988-91,1996-99,2001,2003,2005-11,2013,2015 @(#)Product: :PRODUCT: */ /*TABSTOP=4*/ /* ** Configuration: ** USE_STDERR_SYSLOG - include syslog functionality ** USE_STDERR_FILEDESC - include file descriptor functionality ** JLSS_STDERR - force support for syslog and file descriptors */ #include "posixver.h" #include "stderr.h" /* Includes config.h if available */ #include <assert.h> #include <ctype.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> #include <time.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #else extern int getpid(void); #endif /* HAVE_UNISTD_H */ enum { MAX_MSGLEN = 2048 }; /* Find sub-second timing mechanism */ #if defined(HAVE_CLOCK_GETTIME) /* Uses <time.h> */ #elif defined(HAVE_GETTIMEOFDAY) /* Mac OS X 10.10.3 does not have clock_gettime() yet */ #include <sys/time.h> #else /* No sub-second timing */ #endif #if defined(HAVE_SYSLOG_H) && defined(HAVE_SYSLOG) && defined(USE_STDERR_SYSLOG) #include <syslog.h> extern const char jlss_id_stderr_c_with_syslog[]; const char jlss_id_stderr_c_with_syslog[] = "@(#)" __FILE__ " configured with USE_STDERR_SYSLOG"; #else #undef USE_STDERR_SYSLOG #undef HAVE_SYSLOG_H #undef HAVE_SYSLOG #endif /* syslog configuration */ #if defined(USE_STDERR_FILEDESC) extern const char jlss_id_stderr_c_with_filedesc[]; const char jlss_id_stderr_c_with_filedesc[] = "@(#)" __FILE__ " configured with USE_STDERR_FILEDESC"; #endif /* USE_STDERR_FILEDESC */ static const char def_format[] = "%Y-%m-%d %H:%M:%S"; static const char *tm_format = def_format; static char arg0[ERR_MAXLEN_ARGV0+1] = "**undefined**"; /* Permitted default error flags */ enum { ERR_LOGTIME = ERR_STAMP | ERR_MILLI | ERR_MICRO | ERR_NANO }; enum { ERR_LOGOPTS = ERR_NOFLUSH | ERR_EXIT | ERR_ABORT | ERR_LOGTIME | ERR_NOARG0 | ERR_PID | ERR_ERRNO }; static int err_flags = 0; /* Default error flags (ERR_STAMP, ERR_PID, etc) */ /* Where do messages go? ** if (defined USE_STDERR_SYSLOG && errlog != 0) ==> syslog ** elif (err_fd >= 0) ==> file descriptor ** else ==> file pointer */ #ifdef USE_STDERR_SYSLOG static int errlog = 0; #endif /* USE_STDERR_SYSLOG */ static FILE *errout = 0; #ifdef USE_STDERR_FILEDESC static int err_fd = -1; #endif /* USE_STDERR_FILEDESC */ /* ** err_???_print() functions are named systematically, and are all static. ** ** err_[ev][crx][fn]_print(): ** -- e takes ellipsis argument ** -- v takes va_list argument ** -- c conditionally exits ** -- r returns (no exit) ** -- x exits (no return) ** -- f takes file pointer ** -- n no file pointer (use errout) ** ** NB: no-return and printf-like can only be attached to declarations, not definitions. */ static NORETURN void err_vxf_print(FILE *fp, int flags, int estat, const char *format, va_list args); static NORETURN void err_vxn_print(int flags, int estat, const char *format, va_list args); static NORETURN void err_exn_print(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4); static NORETURN void err_terminate(int flags, int estat); #ifndef lint /* Prevent over-aggressive optimizers from eliminating ID string */ extern const char jlss_id_stderr_c[]; const char jlss_id_stderr_c[] = "@(#)$Id: stderr.c,v 10.14 2015/06/02 03:04:32 jleffler Exp $"; #endif /* lint */ /* ** Set default log options, returning old value. ** Setting ERR_EXIT and ERR_ABORT is permitted but not recommended. */ int err_setlogopts(int new_opts) { int old_opts = err_flags; err_flags = new_opts & ERR_LOGOPTS; return(old_opts); } /* Return default log options */ int err_getlogopts(void) { return(err_flags); } /* Change the definition of 'stderr', reporting on the old one too */ /* NB: using err_stderr((FILE *)0) simply reports the current 'stderr' */ FILE *(err_stderr)(FILE *newerr) { FILE *old; if (errout == 0) errout = stderr; old = errout; if (newerr != 0) errout = newerr; return(old); } #if defined(USE_STDERR_FILEDESC) /* Change the definition of 'stderr', reporting on the old one too */ /* NB: using err_use_fd() with a negative value turns off 'errors to file descriptor' */ int (err_use_fd)(int new_fd) { int old_fd = err_fd; if (new_fd < 0) new_fd = -1; err_fd = new_fd; return(old_fd); } #endif /* USE_STDERR_FILEDESC */ #if defined(USE_STDERR_SYSLOG) /* ** Configure the use of syslog ** If not configured to use syslog(), this is a no-op. ** If configured to use syslog(), the facility argument should be one of ** the standard facilities (POSIX defines LOG_USER and LOG_LOCAL0 to ** LOG_LOCAL7) to turn on syslog(), or a negative value to turn it off. ** The logopts should be the bitwise combination of 0 and the options ** LOG_PID, LOG_CONS, LOG_NDELAY, LOG_ODELAY, LOG_NOWAIT. However, the ** STDERR package sets LOG_PID regardless. ** The ident used in openlog() corresponds to the value in arg0. ** Note that when formatting the message for syslog(), the time, the PID ** and arg0 are not needed (and hence not provided). The downside is ** you are stuck with the date formatted by syslog(). */ int (err_use_syslog)(int logopts, int facility) { if (facility < 0) { /* Turn off syslog() */ closelog(); errlog = 0; } else { openlog(arg0, LOG_PID|logopts, facility); errlog = 1; } return(errlog); } #endif /* USE_STDERR_SYSLOG */ /* Return stored basename of command */ const char *(err_getarg0)(void) { return(arg0); } /* Store basename of command, excluding trailing slashes */ void (err_setarg0)(const char *argv0) { /* Ignore three pathological program names -- NULL, "/" and "" */ if (argv0 != 0 && *argv0 != '\0' && (*argv0 != '/' || *(argv0 + 1) != '\0')) { const char *cp; size_t nbytes = sizeof(arg0) - 1; if ((cp = strrchr(argv0, '/')) == 0) { /* Basename of file only */ cp = argv0; } else if (*(cp + 1) != '\0') { /* Regular pathname containing slashes but not trailing slashes */ cp++; } else { /* Skip backwards over trailing slashes */ const char *ep = cp; while (ep > argv0 && *ep == '/') ep--; /* Skip backwards over non-slashes */ cp = ep; while (cp > argv0 && *cp != '/') cp--; assert(ep >= cp); cp++; nbytes = (size_t)(ep - cp) + 1; if (nbytes > sizeof(arg0) - 1) nbytes = sizeof(arg0) - 1; } strncpy(arg0, cp, nbytes); arg0[nbytes] = '\0'; } } const char *(err_rcs_string)(const char *s2, char *buffer, size_t buflen) { const char *src = s2; char *dst = buffer; char *end = buffer + buflen - 1; /* ** Bother RCS! We've probably been given something like: ** "$Revision: 10.14 $ ($Date: 2015/06/02 03:04:32 $)" ** We only want to emit "7.5 (2001/08/11 06:25:48)". ** Skip the components between '$' and ': ', copy up to ' $', ** repeating as necessary. And we have to test for overflow! ** Also work with the unexpanded forms of keywords ($Keyword$). ** Never needed this with SCCS! */ while (*src != '\0' && dst < end) { while (*src != '\0' && *src != '$') { *dst++ = *src++; if (dst >= end) break; } if (*src == '$') src++; while (*src != '\0' && *src != ':' && *src != '$') src++; if (*src == '\0') break; if (*src == '$') { /* Unexpanded keyword '$Keyword$' notation */ src++; continue; } if (*src == ':') src++; if (*src == ' ') src++; while (*src != '\0' && *src != '$') { /* Map / in 2009/02/15 to dash */ /* Heuristic - maps slashes surrounded by digits to dashes */ char c = *src++; if (c == '/' && isdigit(*src) && isdigit(*(src-2))) c = '-'; *dst++ = c; if (dst >= end) break; } if (*src == '$') { if (*(dst-1) == ' ') dst--; src++; } } *dst = '\0'; return(buffer); } /* Similar to, but different from, Time in timer.h */ typedef struct Time { time_t tv_sec; long tv_nsec; } Time; static Time now(void) { Time clk; #if defined(HAVE_CLOCK_GETTIME) struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); clk.tv_sec = ts.tv_sec; clk.tv_nsec = ts.tv_nsec; #elif defined(HAVE_GETTIMEOFDAY) struct timeval tv; gettimeofday(&tv, 0); clk.tv_sec = tv.tv_sec; clk.tv_nsec = 1000 * tv.tv_usec; #else clk.tv_sec = time(0); clk.tv_nsec = 0; #endif return clk; } /* Format a time string for now (using ISO8601 format) */ /* Allow for future settable time format with tm_format */ static char *err_time(int flags, char *buffer, size_t buflen) { Time clk = now(); struct tm *tp = localtime(&clk.tv_sec); size_t nb = strftime(buffer, buflen, tm_format, tp); if (flags & (ERR_NANO | ERR_MICRO | ERR_MILLI)) { char subsec[12]; size_t ss_len; if (flags & ERR_NANO) ss_len = snprintf(subsec, sizeof(subsec), ".%.9ld", clk.tv_nsec); else if (flags & ERR_MICRO) ss_len = snprintf(subsec, sizeof(subsec), ".%.6ld", clk.tv_nsec / 1000); else /* (flags & ERR_MILLI) */ ss_len = snprintf(subsec, sizeof(subsec), ".%.3ld", clk.tv_nsec / (1000 * 1000)); if (ss_len + nb + 1 < buflen) strcpy(buffer + nb, subsec); } return(buffer); } /* err_stdio - report error via stdio */ static void (err_stdio)(FILE *fp, int flags, int errnum, const char *format, va_list args) { if ((flags & ERR_NOARG0) == 0) fprintf(fp, "%s: ", arg0); if (flags & ERR_LOGTIME) { char timbuf[48]; fprintf(fp, "%s - ", err_time(flags, timbuf, sizeof(timbuf))); } if (flags & ERR_PID) fprintf(fp, "pid=%d: ", (int)getpid()); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" vfprintf(fp, format, args); #pragma GCC diagnostic pop if (flags & ERR_ERRNO) fprintf(fp, "error (%d) %s\n", errnum, strerror(errnum)); } #if defined(USE_STDERR_FILEDESC) || defined(USE_STDERR_SYSLOG) static char *fmt_string(char *curr, const char *end, const char *format, va_list args) { char *new_end = curr; if (curr < end - 1) { size_t size = (size_t)(end - curr); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" int more = vsnprintf(curr, size, format, args); #pragma GCC diagnostic pop if (more >= 0) new_end += ((size_t)more >= size) ? size : (size_t)more; } return(new_end); } static char *fmt_strdots(char *curr, const char *end, const char *format, ...) { va_list args; char *new_end; va_start(args, format); new_end = fmt_string(curr, end, format, args); va_end(args); return new_end; } #endif /* USE_STDERR_FILEDESC || USE_STDERR_SYSLOG */ #if defined(USE_STDERR_SYSLOG) /* err_syslog() - report error via syslog ** ** syslog() automatically adds PID and program name (configured in openlog()) and time stamp. */ static void (err_syslog)(int flags, int errnum, const char *format, va_list args) { char buffer[MAX_MSGLEN]; char *curpos = buffer; char *bufend = buffer + sizeof(buffer); int priority; curpos = fmt_string(curpos, bufend, format, args); if (flags & ERR_ERRNO) curpos = fmt_strdots(curpos, bufend, "error (%d) %s\n", errnum, strerror(errnum)); if (flags & ERR_ABORT) priority = LOG_CRIT; else if (flags & ERR_EXIT) priority = LOG_ERR; else priority = LOG_WARNING; syslog(priority, "%s", buffer); } #endif /* USE_STDERR_SYSLOG */ #if defined(USE_STDERR_FILEDESC) /* err_filedes() - report error via file descriptor */ static void (err_filedes)(int fd, int flags, int errnum, const char *format, va_list args) { char buffer[MAX_MSGLEN]; char *curpos = buffer; char *bufend = buffer + sizeof(buffer); ssize_t nbytes; buffer[0] = '\0'; /* Not strictly necessary */ if ((flags & ERR_NOARG0) == 0) curpos = fmt_strdots(curpos, bufend, "%s: ", arg0); if (flags & ERR_LOGTIME) { char timbuf[32]; curpos = fmt_strdots(curpos, bufend, "%s - ", err_time(flags, timbuf, sizeof(timbuf))); } if (flags & ERR_PID) curpos = fmt_strdots(curpos, bufend, "pid=%d: ", (int)getpid()); curpos = fmt_string(curpos, bufend, format, args); if (flags & ERR_ERRNO) curpos = fmt_strdots(curpos, bufend, "error (%d) %s\n", errnum, strerror(errnum)); /* There's no sensible way to handle short writes! */ nbytes = write(fd, buffer, (size_t)(curpos - buffer)); assert(nbytes == curpos - buffer); } #endif /* USE_STDERR_FILEDESC */ /* Most fundamental (and flexible) error message printing routine - always returns */ static void (err_vrf_print)(FILE *fp, int flags, const char *format, va_list args) { int errnum = errno; /* Capture errno before it is damaged! */ if ((flags & ERR_NOFLUSH) == 0) fflush(0); #if defined(USE_STDERR_SYSLOG) if (errlog) err_syslog(flags, errnum, format, args); else #endif /* USE_STDERR_SYSLOG */ #if defined(USE_STDERR_FILEDESC) if (err_fd >= 0) err_filedes(err_fd, flags, errnum, format, args); else #endif /* USE_STDERR_FILEDESC */ err_stdio(fp, flags, errnum, format, args); fflush(fp); } /* Terminate program - abort or exit */ static void err_terminate(int flags, int estat) { assert(flags & (ERR_ABORT|ERR_EXIT)); if (flags & ERR_ABORT) abort(); exit(estat); } /* Most fundamental (and flexible) error message printing routine - may return */ static void (err_vcf_print)(FILE *fp, int flags, int estat, const char *format, va_list args) { err_vrf_print(fp, flags, format, args); if (flags & (ERR_ABORT|ERR_EXIT)) err_terminate(flags, estat); } /* Analog of err_vcf_print() which guarantees 'no return' */ static void (err_vxf_print)(FILE *fp, int flags, int estat, const char *format, va_list args) { err_vrf_print(fp, flags, format, args); err_terminate(flags, estat); } /* External interface to err_vcf_print() - may return */ void (err_logmsg)(FILE *fp, int flags, int estat, const char *format, ...) { va_list args; va_start(args, format); err_vcf_print(fp, flags, estat, format, args); va_end(args); } /* Print error message to current error output - no return */ static void (err_vxn_print)(int flags, int estat, const char *format, va_list args) { if (errout == 0) errout = stderr; err_vxf_print(errout, flags, estat, format, args); } /* Print error message to current error output - no return */ static void err_exn_print(int flags, int estat, const char *format, ...) { va_list args; va_start(args, format); err_vxn_print(flags, estat, format, args); va_end(args); } /* Print error message to nominated output - always returns */ static void err_erf_print(FILE *fp, int flags, const char *format, ...) { va_list args; va_start(args, format); err_vrf_print(fp, flags, format, args); va_end(args); } /* Print message using current error file */ void (err_print)(int flags, int estat, const char *format, va_list args) { if (errout == 0) errout = stderr; err_vcf_print(errout, flags, estat, format, args); } static void err_vrn_print(int flags, const char *format, va_list args) { if (errout == 0) errout = stderr; err_vrf_print(errout, flags, format, args); } /* Report warning including message from errno */ void (err_sysrem)(const char *format, ...) { va_list args; va_start(args, format); err_vrn_print(ERR_SYSREM | err_getlogopts(), format, args); va_end(args); } /* Report warning including message from errno */ void (err_sysremark)(int errnum, const char *format, ...) { va_list args; int old_errno = errno; errno = errnum; va_start(args, format); err_vrn_print(ERR_SYSREM | err_getlogopts(), format, args); va_end(args); errno = old_errno; } /* Report error including message from errno */ void (err_syserr)(const char *format, ...) { va_list args; va_start(args, format); err_vxn_print(ERR_SYSERR | err_getlogopts(), ERR_STAT, format, args); va_end(args); } /* Report error including message from errno */ void (err_syserror)(int errnum, const char *format, ...) { va_list args; int old_errno = errno; errno = errnum; va_start(args, format); err_vxn_print(ERR_SYSERR | err_getlogopts(), ERR_STAT, format, args); va_end(args); errno = old_errno; } /* Report warning */ void (err_remark)(const char *format, ...) { va_list args; va_start(args, format); err_vrn_print(ERR_REM | err_getlogopts(), format, args); va_end(args); } /* Report error */ void (err_error)(const char *format, ...) { va_list args; va_start(args, format); err_vxn_print(ERR_ERR | err_getlogopts(), ERR_STAT, format, args); va_end(args); } /* Report message - sometimes exiting too */ void (err_report)(int flags, int estat, const char *format, ...) { va_list args; va_start(args, format); err_print(flags, estat, format, args); va_end(args); } /* Print usage message and exit with failure status */ void (err_usage)(const char *s1) { err_exn_print(ERR_NOARG0|ERR_EXIT, EXIT_FAILURE, "Usage: %s %s\n", err_getarg0(), s1); } /* Report failure and generate core dump */ void (err_abort)(const char *format, ...) { va_list args; va_start(args, format); err_vxn_print(ERR_ABORT | err_getlogopts(), EXIT_FAILURE, format, args); va_end(args); } /* Report version information (no exit), removing embedded RCS keyword strings (but not values) */ void (err_printversion)(const char *program, const char *verinfo) { char buffer[64]; if (strchr(verinfo, '$')) verinfo = err_rcs_string(verinfo, buffer, sizeof(buffer)); err_erf_print(stdout, ERR_DEFAULT, "%s Version %s\n", program, verinfo); } /* Report version information and exit, removing embedded RCS keyword strings (but not values) */ void (err_version)(const char *program, const char *verinfo) { err_printversion(program, verinfo); exit(EXIT_SUCCESS); } /* Report an internal error and exit */ /* Abort if JLSS_INTERNAL_ERROR_ABORT set in environment */ void (err_internal)(const char *function, const char *format, ...) { va_list args; int flags = ERR_EXIT; const char *ev = getenv("JLSS_INTERNAL_ERROR_ABORT"); va_start(args, format); if (ev != 0 && *ev != '\0') flags = ERR_ABORT; /* Generate core dump */ err_remark("unrecoverable internal error in function %s():\n", function); err_vxn_print(flags | err_getlogopts(), EXIT_FAILURE, format, args); va_end(args); } #ifdef TEST #error Use separate test program test.stderr.c #endif /* TEST */
/* @(#)File: $RCSfile: stderr.h,v $ @(#)Version: $Revision: 10.10 $ @(#)Last changed: $Date: 2015/10/14 23:12:19 $ @(#)Purpose: Header file for standard error functions @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1989-93,1996-99,2003,2005-11,2015 @(#)Product: :PRODUCT: */ #if !defined(STDERR_H) #define STDERR_H #if defined(MAIN_PROGRAM) #if !defined(lint) /* Prevent over-aggressive optimizers from eliminating ID string */ extern const char jlss_id_stderr_h[]; const char jlss_id_stderr_h[] = "@(#)$Id: stderr.h,v 10.10 2015/10/14 23:12:19 jleffler Exp $"; #endif /* lint */ #endif #if defined(HAVE_CONFIG_H) #include "config.h" #endif /* HAVE_CONFIG_H */ #if defined(JLSS_STDERR) #undef USE_STDERR_FILEDESC #define USE_STDERR_FILEDESC #if defined(HAVE_SYSLOG) && defined(HAVE_SYSLOG_H) #undef USE_STDERR_SYSLOG #define USE_STDERR_SYSLOG #endif /* HAVE_SYSLOG && HAVE_SYSLOG_H */ #endif /* JLSS_STDERR */ #include <stdio.h> #include <stdarg.h> #if !defined(NORETURN) #if __STDC_VERSION__ >= 201112L #define NORETURN _Noreturn #elif defined(__GNUC__) #define NORETURN __attribute__((noreturn)) #else #define NORETURN /* If only */ #endif /* __STDC_VERSION__ || __GNUC__ */ #endif /* NORETURN */ #if !defined(PRINTFLIKE) #if defined(__GNUC__) #define PRINTFLIKE(n,m) __attribute__((format(printf,n,m))) #else #define PRINTFLIKE(n,m) /* If only */ #endif /* __GNUC__ */ #endif /* PRINTFLIKE */ /* -- Definitions for error handling */ enum { ERR_STAT = 1 }; /* Default exit status */ enum { ERR_DEFAULT = 0x0000 }; /* Default flag */ enum { ERR_NOFLUSH = 0x0001 }; /* Do not flush open files */ enum { ERR_EXIT = 0x0004 }; /* Exit -- do not return */ enum { ERR_ABORT = 0x0008 }; /* Abort -- do not return */ enum { ERR_STAMP = 0x0020 }; /* Timestamp messages (whole second) */ enum { ERR_NOARG0 = 0x0040 }; /* Do not print arg0 prefix */ enum { ERR_PID = 0x0080 }; /* Include pid=nnnnn info */ enum { ERR_ERRNO = 0x0100 }; /* Include system error */ enum { ERR_MILLI = 0x0200 }; /* Timestamp messages (millisecond) */ enum { ERR_MICRO = 0x0400 }; /* Timestamp messages (microsecond) */ enum { ERR_NANO = 0x0800 }; /* Timestamp messages (nanosecond) */ #if defined(USE_STDERR_SYSLOG) /* Definitions related to using syslog */ enum { ERR_LOG_EMERG = 0x01000 }; /* system is unusable */ enum { ERR_LOG_ALERT = 0x02000 }; /* action must be taken immediately */ enum { ERR_LOG_CRIT = 0x04000 }; /* critical conditions */ enum { ERR_LOG_ERR = 0x08000 }; /* error conditions */ enum { ERR_LOG_WARNING = 0x10000 }; /* warning conditions */ enum { ERR_LOG_NOTICE = 0x20000 }; /* normal but significant condition */ enum { ERR_LOG_INFO = 0x40000 }; /* informational */ enum { ERR_LOG_DEBUG = 0x80000 }; /* debug-level messages */ enum { ERR_LOG_LEVEL_HI = ERR_LOG_EMERG|ERR_LOG_ALERT|ERR_LOG_CRIT|ERR_LOG_ERR }; enum { ERR_LOG_LEVEL_LO = ERR_LOG_WARNING|ERR_LOG_NOTICE|ERR_LOG_INFO|ERR_LOG_DEBUG }; enum { ERR_LOG_LEVEL = ERR_LOG_LEVEL_HI|ERR_LOG_LEVEL_LO }; #endif /* USE_STDERR_SYSLOG */ /* -- Standard combinations of flags */ enum { ERR_REM = ERR_DEFAULT }; enum { ERR_ERR = ERR_EXIT }; enum { ERR_ABT = ERR_ABORT }; enum { ERR_LOG = ERR_STAMP|ERR_PID }; enum { ERR_SYSREM = ERR_REM|ERR_ERRNO }; enum { ERR_SYSERR = ERR_ERR|ERR_ERRNO }; /* -- Maximum recorded length of argv[0]; extra is truncated */ enum { ERR_MAXLEN_ARGV0 = 63 }; /* -- Global definitions */ extern const char *err_getarg0(void); extern void err_setarg0(const char *argv0); extern FILE *err_stderr(FILE *fp); extern const char *err_rcs_string(const char *s, char *buffer, size_t buflen); extern NORETURN void err_abort(const char *format, ...) PRINTFLIKE(1,2); extern NORETURN void err_error(const char *format, ...) PRINTFLIKE(1,2); extern NORETURN void err_error1(const char *s1); extern NORETURN void err_error2(const char *s1, const char *s2); extern NORETURN void err_help(const char *use_str, const char *hlp_str); extern NORETURN void err_helplist(const char *use_str, const char * const *help_list); extern NORETURN void err_internal(const char *function, const char *format, ...) PRINTFLIKE(2,3); extern NORETURN void err_syserr(const char *format, ...) PRINTFLIKE(1,2); extern NORETURN void err_syserr1(const char *s1); extern NORETURN void err_syserr2(const char *s1, const char *s2); extern NORETURN void err_syserror(int errnum, const char *format, ...) PRINTFLIKE(2,3); extern NORETURN void err_usage(const char *usestr); extern NORETURN void err_version(const char *program, const char *verinfo); extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5); extern void err_print(int flags, int estat, const char *format, va_list args); extern void err_printversion(const char *program, const char *verinfo); extern void err_remark(const char *format, ...) PRINTFLIKE(1,2); extern void err_remark1(const char *s1); extern void err_remark2(const char *s1, const char *s2); extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4); extern void err_sysrem(const char *format, ...) PRINTFLIKE(1,2); extern void err_sysrem1(const char *s1); extern void err_sysrem2(const char *s1, const char *s2); extern void err_sysremark(int errnum, const char *format, ...) PRINTFLIKE(2,3); extern int err_getlogopts(void); /* Get default log options */ extern int err_setlogopts(int new_opts); /* Set default log options */ #if defined(USE_STDERR_FILEDESC) extern int err_use_fd(int fd); /* Use file descriptor */ #endif /* USE_STDERR_FILEDESC */ #if defined(USE_STDERR_SYSLOG) /* In case of doubt, use zero for both logopts and facility */ extern int err_use_syslog(int logopts, int facility); /* Configure/use syslog() */ #endif /* USE_STDERR_SYSLOG */ /* ** JL 2003-07-31: Security Note. ** Question: given that err_remark("abc\n") and err_remark1("abc") ** produce the same output, when should you use err_remark1() ** instead of err_remark()? ** Answer 1: trivia - when you can't put the newline in the string. ** Answer 2: security - when the argument contains user input and could, ** therefore, contain conversion specifiers, etc. The code in ** err_remark() does not (and cannot) verify that you have ** passed correct arguments for the conversion specifiers in ** the format string. ** Answer 3: inertia - when migrating code that uses remark(). ** ** Generalizing: when you use a function that has 'const char *format' ** in the prototype above, make sure your code is fully in charge of the ** format string to avoid security lapses. Do not allow the user to ** provide that string unless you stringently check it beforehand. */ #endif /* STDERR_H */
rename-it.sh
Description: Bourne shell script