libexplain  1.4.D001
libexplain/exit.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2009, 2010, 2012, 2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/stdlib.h>
00021 
00022 #include <libexplain/exit.h>
00023 #include <libexplain/option.h>
00024 #include <libexplain/program_name.h>
00025 #include <libexplain/string_buffer.h>
00026 #include <libexplain/wrap_and_print.h>
00027 
00028 
00029 /*
00030  * All ANSI C compliant system provide atexit,
00031  * but on_exit is a GNU glibc invention,
00032  * and a very useful one.
00033  */
00034 #ifdef HAVE_ON_EXIT
00035 
00036 enum action_t
00037 {
00038     action_never,
00039     action_error,
00040     action_always,
00041 };
00042 
00043 static int      registered;
00044 static enum action_t action = action_never;
00045 
00046 
00047 static void
00048 grim_reaper(int es, void *aux)
00049 {
00050     es &= 255;
00051     (void)aux;
00052     switch (action)
00053     {
00054     default:
00055     case action_never:
00056         break;
00057 
00058     case action_error:
00059         if (es == EXIT_SUCCESS)
00060             break;
00061         /* fall through... */
00062 
00063     case action_always:
00064         {
00065             explain_string_buffer_t sb;
00066             char            text[1000];
00067 
00068             explain_string_buffer_init(&sb, text, sizeof(text));
00069 
00070             if (explain_option_assemble_program_name())
00071             {
00072                 const char      *prog;
00073 
00074                 prog = explain_program_name_get();
00075                 if (prog && *prog)
00076                 {
00077                     explain_string_buffer_puts(&sb, prog);
00078                     explain_string_buffer_puts(&sb, ": ");
00079                 }
00080             }
00081 
00082             explain_string_buffer_puts(&sb, "exit status ");
00083             switch (es)
00084             {
00085             case EXIT_SUCCESS:
00086                 explain_string_buffer_puts(&sb, "EXIT_SUCCESS");
00087                 break;
00088 
00089             case EXIT_FAILURE:
00090                 explain_string_buffer_puts(&sb, "EXIT_FAILURE");
00091                 break;
00092 
00093             default:
00094                 explain_string_buffer_printf(&sb, "EXIT_FAILURE (%d)", es);
00095                 break;
00096             }
00097 
00098             explain_wrap_and_print(stderr, text);
00099         }
00100         break;
00101     }
00102 }
00103 
00104 
00105 static void
00106 install_grim_reaper(void)
00107 {
00108     if (!registered)
00109     {
00110         registered = 1;
00111         on_exit(grim_reaper, 0);
00112     }
00113 }
00114 
00115 #endif
00116 
00117 void
00118 explain_exit_on_exit(void)
00119 {
00120 #ifdef HAVE_ON_EXIT
00121     action = action_always;
00122     install_grim_reaper();
00123 #endif
00124 }
00125 
00126 
00127 void
00128 explain_exit_on_error(void)
00129 {
00130 #ifdef HAVE_ON_EXIT
00131     action = action_error;
00132     install_grim_reaper();
00133 #endif
00134 }
00135 
00136 
00137 void
00138 explain_exit_cancel(void)
00139 {
00140 #ifdef HAVE_ON_EXIT
00141     /*
00142      * If grim reaper is not already installed, there is no need to do
00143      * it now, because the result of installing it would be the same as
00144      * not installing it.
00145      */
00146     action = action_never;
00147 #endif
00148 }
00149 
00150 
00151 /* vim: set ts=8 sw=4 et : */