libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2010, 2011, 2013 Peter Miller 00004 * 00005 * This program is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 3 of the License, or (at 00008 * your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 00013 * General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include <libexplain/ac/errno.h> 00020 00021 #include <libexplain/buffer/ebadf.h> 00022 #include <libexplain/buffer/efault.h> 00023 #include <libexplain/buffer/einval.h> 00024 #include <libexplain/buffer/errno/fputs.h> 00025 #include <libexplain/buffer/errno/vfprintf.h> 00026 #include <libexplain/buffer/is_the_null_pointer.h> 00027 #include <libexplain/buffer/pathname.h> 00028 #include <libexplain/buffer/pointer.h> 00029 #include <libexplain/buffer/software_error.h> 00030 #include <libexplain/buffer/stream.h> 00031 #include <libexplain/buffer/va_list.h> 00032 #include <libexplain/explanation.h> 00033 #include <libexplain/is_efault.h> 00034 #include <libexplain/libio.h> 00035 #include <libexplain/printf_format.h> 00036 00037 00038 static void 00039 explain_buffer_errno_vfprintf_system_call(explain_string_buffer_t *sb, 00040 int errnum, FILE *fp, const char *format, va_list ap) 00041 { 00042 (void)errnum; 00043 explain_string_buffer_puts(sb, "vfprintf(fp = "); 00044 explain_buffer_stream(sb, fp); 00045 explain_string_buffer_puts(sb, ", format = "); 00046 explain_buffer_pathname(sb, format); 00047 explain_string_buffer_puts(sb, ", ap = "); 00048 explain_buffer_va_list(sb, ap); 00049 explain_string_buffer_putc(sb, ')'); 00050 } 00051 00052 00053 void 00054 explain_buffer_errno_vfprintf_explanation(explain_string_buffer_t *sb, 00055 int errnum, const char *syscall_name, FILE *fp, const char *format, 00056 va_list ap) 00057 { 00058 if (!fp) 00059 { 00060 explain_buffer_is_the_null_pointer(sb, "fp"); 00061 return; 00062 } 00063 if (explain_is_efault_pointer(fp, sizeof(*fp))) 00064 { 00065 explain_buffer_efault(sb, "fp"); 00066 return; 00067 } 00068 00069 if (errnum == EBADF) 00070 { 00071 /* 00072 * The underlying fildes could be open read/write but the FILE 00073 * may not be open for writing. 00074 */ 00075 if (explain_libio_no_writes(fp)) 00076 { 00077 explain_buffer_ebadf_not_open_for_writing(sb, "fp", -1); 00078 explain_buffer_software_error(sb); 00079 return; 00080 } 00081 } 00082 00083 if (!format) 00084 { 00085 explain_buffer_is_the_null_pointer(sb, "format"); 00086 return; 00087 } 00088 if (explain_is_efault_string(format)) 00089 { 00090 explain_buffer_efault(sb, "format"); 00091 return; 00092 } 00093 00094 /* 00095 * http://www.opengroup.org/onlinepubs/009695399/functions/vfprintf.html 00096 */ 00097 (void)ap; 00098 switch (errnum) 00099 { 00100 case EBADF: 00101 /* let "fputs" explain it */ 00102 goto generic; 00103 00104 case EINVAL: 00105 /* fp could be NULL, but we already checked for that */ 00106 00107 /* 00108 * Check the format string. 00109 * All the fugly stuff is hidden in explain_printf_format(). 00110 */ 00111 { 00112 int cur_idx; 00113 size_t j; 00114 explain_printf_format_list_t specs; 00115 size_t errpos; 00116 00117 explain_printf_format_list_constructor(&specs); 00118 errpos = explain_printf_format(format, &specs); 00119 if (errpos > 0) 00120 { 00121 explain_buffer_einval_format_string 00122 ( 00123 sb, 00124 "format", 00125 format, 00126 errpos 00127 ); 00128 explain_printf_format_list_destructor(&specs); 00129 return; 00130 } 00131 explain_printf_format_list_sort(&specs); 00132 /* duplicates are OK, holes are not */ 00133 cur_idx = 0; 00134 for (j = 0; j < specs.length; ++j) 00135 { 00136 int idx; 00137 00138 idx = specs.list[j].index; 00139 if (idx > cur_idx) 00140 { 00141 /* we found a hole */ 00142 explain_buffer_einval_format_string_hole 00143 ( 00144 sb, 00145 "format", 00146 cur_idx + 1 00147 ); 00148 explain_printf_format_list_destructor(&specs); 00149 return; 00150 } 00151 if (idx == cur_idx) 00152 ++cur_idx; 00153 } 00154 explain_printf_format_list_destructor(&specs); 00155 } 00156 00157 #if 0 00158 #ifdef HAVE_FWIDE 00159 /* 00160 * FIXME: [e]glibc returns EOF (without setting errno) if the stream 00161 * is wide (this is a narrow char printf). 00162 * 00163 * Our recommended usage is to set errno = EINVAL before the call. 00164 */ 00165 if (fwide(fp, 0) > 0) 00166 { 00167 "The stream is for wide characters, and this is a narrow character " 00168 "operation. We need to do this check for all narrow character " 00169 "functions. " 00170 return; 00171 } 00172 #endif 00173 #endif 00174 goto generic; 00175 00176 default: 00177 generic: 00178 explain_buffer_errno_fputs_explanation 00179 ( 00180 sb, 00181 errnum, 00182 syscall_name, 00183 format, 00184 fp 00185 ); 00186 break; 00187 } 00188 } 00189 00190 00191 void 00192 explain_buffer_errno_vfprintf(explain_string_buffer_t *sb, int errnum, FILE *fp, 00193 const char *format, va_list ap) 00194 { 00195 explain_explanation_t exp; 00196 00197 explain_explanation_init(&exp, errnum); 00198 explain_buffer_errno_vfprintf_system_call(&exp.system_call_sb, errnum, fp, 00199 format, ap); 00200 explain_buffer_errno_vfprintf_explanation(&exp.explanation_sb, errnum, 00201 "vfprintf", fp, format, ap); 00202 explain_explanation_assemble(&exp, sb); 00203 } 00204 00205 00206 /* vim: set ts=8 sw=4 et : */