libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2010, 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, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser 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 #include <libexplain/ac/net/if.h> 00021 #include <libexplain/ac/sys/socket.h> 00022 #include <libexplain/ac/sys/stat.h> 00023 #include <libexplain/ac/sys/un.h> 00024 00025 #include <libexplain/buffer/dac.h> 00026 #include <libexplain/buffer/eacces.h> 00027 #include <libexplain/buffer/eaddrinuse.h> 00028 #include <libexplain/buffer/eafnosupport.h> 00029 #include <libexplain/buffer/ebadf.h> 00030 #include <libexplain/buffer/efault.h> 00031 #include <libexplain/buffer/einval.h> 00032 #include <libexplain/buffer/eloop.h> 00033 #include <libexplain/buffer/enametoolong.h> 00034 #include <libexplain/buffer/enoent.h> 00035 #include <libexplain/buffer/enomem.h> 00036 #include <libexplain/buffer/enotdir.h> 00037 #include <libexplain/buffer/enotsock.h> 00038 #include <libexplain/buffer/erofs.h> 00039 #include <libexplain/buffer/errno/bind.h> 00040 #include <libexplain/buffer/errno/generic.h> 00041 #include <libexplain/buffer/errno/path_resolution.h> 00042 #include <libexplain/buffer/fildes_to_pathname.h> 00043 #include <libexplain/buffer/gettext.h> 00044 #include <libexplain/buffer/pointer.h> 00045 #include <libexplain/buffer/sockaddr.h> 00046 #include <libexplain/explanation.h> 00047 #include <libexplain/fildes_to_address_family.h> 00048 00049 00050 static void 00051 explain_buffer_errno_bind_system_call(explain_string_buffer_t *sb, 00052 int errnum, int fildes, const struct sockaddr *sock_addr, 00053 int sock_addr_size) 00054 { 00055 (void)errnum; 00056 explain_string_buffer_printf(sb, "bind(fildes = %d", fildes); 00057 explain_buffer_fildes_to_pathname(sb, fildes); 00058 explain_string_buffer_puts(sb, ", sock_addr = "); 00059 explain_buffer_sockaddr(sb, sock_addr, sock_addr_size); 00060 explain_string_buffer_printf 00061 ( 00062 sb, 00063 ", sock_addr_size = %d", 00064 sock_addr_size 00065 ); 00066 explain_string_buffer_putc(sb, ')'); 00067 } 00068 00069 00070 static void 00071 explain_final_sock_init(explain_final_t *fp) 00072 { 00073 explain_final_init(fp); 00074 fp->want_to_create = 1; 00075 fp->want_to_read = 1; 00076 fp->must_be_a_st_mode = 1; 00077 fp->st_mode = S_IFSOCK; 00078 } 00079 00080 00081 static void 00082 the_socket_is_already_bound(explain_string_buffer_t *sb, int fildes) 00083 { 00084 struct sockaddr_storage sas; 00085 struct sockaddr *sas_p; 00086 socklen_t sa_len; 00087 00088 sas_p = (struct sockaddr *)&sas; 00089 sa_len = sizeof(sas); 00090 if (getsockname(fildes, sas_p, &sa_len) >= 0) 00091 { 00092 char addr[500]; 00093 explain_string_buffer_t addr_sb; 00094 00095 explain_string_buffer_init(&addr_sb, addr, sizeof(addr)); 00096 explain_buffer_sockaddr(&addr_sb, sas_p, sa_len); 00097 explain_string_buffer_printf_gettext 00098 ( 00099 sb, 00100 /* 00101 * xgettext: This message is used to explain an EINVAL error 00102 * returned by the bind(2) system call, in the case where 00103 * the socket is already bound to an address. 00104 * 00105 * %1$s => a representation of the struct sockaddr that the 00106 * socket is already bound to. 00107 */ 00108 i18n("the socket is already bound to %s"), 00109 addr 00110 ); 00111 } 00112 else 00113 { 00114 explain_buffer_gettext 00115 ( 00116 sb, 00117 /* 00118 * xgettext: This message is used to explain an EINVAL 00119 * error returned by the bind(2) system call, in the case 00120 * where the socket is already bound to an address, but the 00121 * address cannot be determined. 00122 */ 00123 i18n("the socket is already bound to an address") 00124 ); 00125 } 00126 } 00127 00128 00129 static void 00130 explain_buffer_errno_bind_explanation(explain_string_buffer_t *sb, 00131 int errnum, int fildes, const struct sockaddr *sock_addr, 00132 int sock_addr_size) 00133 { 00134 /* 00135 * http://www.opengroup.org/onlinepubs/009695399/functions/bind.html 00136 */ 00137 (void)sock_addr_size; 00138 switch (errnum) 00139 { 00140 case EACCES: 00141 if (sock_addr->sa_family == AF_UNIX) 00142 { 00143 explain_final_t final_component; 00144 const struct sockaddr_un *saddr; 00145 00146 saddr = (const struct sockaddr_un *)sock_addr; 00147 explain_final_sock_init(&final_component); 00148 final_component.want_to_write = 1; 00149 final_component.want_to_create = 1; 00150 final_component.must_be_a_st_mode = 1; 00151 final_component.st_mode = S_IFSOCK; 00152 final_component.path_max = sizeof(saddr->sun_path) - 1; 00153 explain_buffer_eacces 00154 ( 00155 sb, 00156 saddr->sun_path, 00157 "sock_addr->sun_path", 00158 &final_component 00159 ); 00160 } 00161 else 00162 { 00163 explain_buffer_gettext 00164 ( 00165 sb, 00166 /* 00167 * xgettext: This message is used to explain an EACCES 00168 * error reported by a bind(2) system call, in the case 00169 * where a privileged port is specific, and the process 00170 * does not have permission. 00171 */ 00172 i18n("the network port address is protected") 00173 ); 00174 explain_buffer_dac_net_bind_service(sb); 00175 } 00176 break; 00177 00178 case EADDRINUSE: 00179 if (sock_addr->sa_family == AF_UNIX) 00180 { 00181 explain_buffer_gettext 00182 ( 00183 sb, 00184 /* 00185 * xgettext: This message is used when an AF_UNIX socket 00186 * file already exists when it should not. While the 00187 * bind(2) call will create the entry in the file 00188 * system, the correponding close(2) will not remove it 00189 * again, the programmer must explicitly unlink(2) it. 00190 */ 00191 i18n("the socket file already exists, and it should " 00192 "not; when you are done with AF_UNIX sockets you must " 00193 "deliberately unlink(2) the socket file, it does not " 00194 "happen automatically") 00195 ); 00196 break; 00197 } 00198 explain_buffer_eaddrinuse(sb, fildes); 00199 break; 00200 00201 case EBADF: 00202 explain_buffer_ebadf(sb, fildes, "fildes"); 00203 break; 00204 00205 case EAFNOSUPPORT: 00206 explain_buffer_eafnosupport 00207 ( 00208 sb, 00209 fildes, 00210 "fildes", 00211 sock_addr, 00212 "sock_addr" 00213 ); 00214 break; 00215 00216 case EINVAL: 00217 if (sock_addr->sa_family == AF_UNIX) 00218 { 00219 if (explain_fildes_to_address_family(fildes) == AF_UNIX) 00220 { 00221 explain_buffer_einval_too_small 00222 ( 00223 sb, 00224 "sock_addr_size", 00225 sock_addr_size 00226 ); 00227 } 00228 else 00229 { 00230 explain_buffer_eafnosupport 00231 ( 00232 sb, 00233 fildes, 00234 "fildes", 00235 sock_addr, 00236 "sock_addr" 00237 ); 00238 } 00239 } 00240 else 00241 { 00242 the_socket_is_already_bound(sb, fildes); 00243 } 00244 break; 00245 00246 case ENOTSOCK: 00247 explain_buffer_enotsock(sb, fildes, "fildes"); 00248 break; 00249 00250 case EADDRNOTAVAIL: 00251 /* FIXME: which is it? differentiate between these two cases */ 00252 explain_string_buffer_puts 00253 ( 00254 sb, 00255 /* 00256 * xgettext: This message is used to explain an EADDRNOTAVAIL 00257 * error reported by a bind(2) system call, in the case where 00258 * the requested network address was not local or a nonexistent 00259 * interface was requested. 00260 */ 00261 i18n("the requested network address was not local or a " 00262 "nonexistent interface was requested") 00263 ); 00264 00265 #ifdef SO_BINDTODEVICE 00266 { 00267 char name[IFNAMSIZ + 1]; 00268 socklen_t namsiz; 00269 00270 /* 00271 * This is only useful for AF_INET and AF_INET6, 00272 * AF_PACKET is different. 00273 */ 00274 namsiz = sizeof(name); 00275 if 00276 ( 00277 !getsockopt(fildes, SOL_SOCKET, SO_BINDTODEVICE, name, &namsiz) 00278 && 00279 namsiz 00280 && 00281 name[0] 00282 ) 00283 { 00284 explain_string_buffer_puts(sb, " ("); 00285 explain_string_buffer_puts_quoted(sb, name); 00286 explain_string_buffer_putc(sb, ')'); 00287 } 00288 } 00289 #endif 00290 break; 00291 00292 case EFAULT: 00293 explain_buffer_efault(sb, "sock_addr"); 00294 break; 00295 00296 case ELOOP: 00297 if (sock_addr->sa_family == AF_UNIX) 00298 { 00299 struct sockaddr_un *saddr; 00300 explain_final_t final_component; 00301 00302 explain_final_sock_init(&final_component); 00303 saddr = (struct sockaddr_un *)sock_addr; 00304 00305 explain_buffer_eloop 00306 ( 00307 sb, 00308 saddr->sun_path, 00309 "sock_addr->sun_path", 00310 &final_component 00311 ); 00312 } 00313 break; 00314 00315 case ENAMETOOLONG: 00316 if (sock_addr->sa_family == AF_UNIX) 00317 { 00318 struct sockaddr_un *saddr; 00319 explain_final_t final_component; 00320 00321 explain_final_sock_init(&final_component); 00322 saddr = (struct sockaddr_un *)sock_addr; 00323 00324 explain_buffer_enametoolong 00325 ( 00326 sb, 00327 saddr->sun_path, 00328 "sock_addr->sun_path", 00329 &final_component 00330 ); 00331 } 00332 break; 00333 00334 case ENOENT: 00335 if (sock_addr->sa_family == AF_UNIX) 00336 { 00337 struct sockaddr_un *saddr; 00338 explain_final_t final_component; 00339 00340 explain_final_sock_init(&final_component); 00341 saddr = (struct sockaddr_un *)sock_addr; 00342 00343 explain_buffer_enoent 00344 ( 00345 sb, 00346 saddr->sun_path, 00347 "sock_addr->sun_path", 00348 &final_component 00349 ); 00350 } 00351 break; 00352 00353 case ENOMEM: 00354 explain_buffer_enomem_kernel(sb); 00355 break; 00356 00357 case ENOTDIR: 00358 if (sock_addr->sa_family == AF_UNIX) 00359 { 00360 struct sockaddr_un *saddr; 00361 explain_final_t final_component; 00362 00363 explain_final_sock_init(&final_component); 00364 saddr = (struct sockaddr_un *)sock_addr; 00365 00366 explain_buffer_enotdir 00367 ( 00368 sb, 00369 saddr->sun_path, 00370 "sock_addr->sun_path", 00371 &final_component 00372 ); 00373 } 00374 break; 00375 00376 case EROFS: 00377 if (sock_addr->sa_family == AF_UNIX) 00378 { 00379 struct sockaddr_un *saddr; 00380 00381 saddr = (struct sockaddr_un *)sock_addr; 00382 explain_buffer_erofs(sb, saddr->sun_path, "sock_addr->sun_path"); 00383 } 00384 break; 00385 00386 default: 00387 explain_buffer_errno_generic(sb, errnum, "bind"); 00388 break; 00389 } 00390 } 00391 00392 00393 void 00394 explain_buffer_errno_bind(explain_string_buffer_t *sb, int errnum, 00395 int fildes, const struct sockaddr *sock_addr, int sock_addr_size) 00396 { 00397 explain_explanation_t exp; 00398 00399 explain_explanation_init(&exp, errnum); 00400 explain_buffer_errno_bind_system_call 00401 ( 00402 &exp.system_call_sb, 00403 errnum, 00404 fildes, 00405 sock_addr, 00406 sock_addr_size 00407 ); 00408 explain_buffer_errno_bind_explanation 00409 ( 00410 &exp.explanation_sb, 00411 errnum, 00412 fildes, 00413 sock_addr, 00414 sock_addr_size 00415 ); 00416 explain_explanation_assemble(&exp, sb); 00417 } 00418 00419 00420 /* vim: set ts=8 sw=4 et : */