libexplain  1.4.D001
libexplain/buffer/errno/shmctl.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 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 #include <libexplain/ac/string.h>
00021 
00022 #include <libexplain/buffer/dac.h>
00023 #include <libexplain/buffer/eacces.h>
00024 #include <libexplain/buffer/efault.h>
00025 #include <libexplain/buffer/einval.h>
00026 #include <libexplain/buffer/enomem.h>
00027 #include <libexplain/buffer/eoverflow.h>
00028 #include <libexplain/buffer/eperm.h>
00029 #include <libexplain/buffer/errno/generic.h>
00030 #include <libexplain/buffer/errno/shmctl.h>
00031 #include <libexplain/buffer/gettext.h>
00032 #include <libexplain/buffer/int.h>
00033 #include <libexplain/buffer/is_the_null_pointer.h>
00034 #include <libexplain/buffer/pointer.h>
00035 #include <libexplain/buffer/shmctl_command.h>
00036 #include <libexplain/buffer/shmid_ds.h>
00037 #include <libexplain/buffer/shm_info.h>
00038 #include <libexplain/buffer/shminfo.h>
00039 #include <libexplain/explanation.h>
00040 #include <libexplain/translate.h>
00041 
00042 
00043 static int
00044 wrap_shmctl(int shmid, int cmd, struct shmid_ds *data)
00045 {
00046     if (shmctl(shmid, cmd, data) >= 0)
00047         return 0;
00048     if (errno == EACCES || errno == EPERM)
00049     {
00050         /*
00051          * Note that shmctl(IPC_STAT) requires read permission, so if we
00052          * get EACCES that means we know we have no read permission, but
00053          * we don't know anything else.  Fake it.
00054          */
00055         memset(data, 0, sizeof(*data));
00056         return 0;
00057     }
00058     return -1;
00059 }
00060 
00061 
00062 static void
00063 explain_buffer_errno_shmctl_system_call(explain_string_buffer_t *sb, int errnum,
00064     int shmid, int command, struct shmid_ds *data)
00065 {
00066     (void)errnum;
00067     explain_string_buffer_puts(sb, "shmctl(shmid = ");
00068     explain_buffer_int(sb, shmid);
00069     explain_string_buffer_puts(sb, ", command = ");
00070     explain_buffer_shmctl_command(sb, command);
00071     explain_string_buffer_puts(sb, ", data = ");
00072     switch (command)
00073     {
00074 #ifdef IPC_SET
00075     case IPC_SET:
00076         explain_buffer_shmid_ds(sb, data, 0);
00077         break;
00078 #endif
00079 
00080 #ifdef IPC_INFO
00081     case IPC_INFO:
00082 #endif
00083 #ifdef IPC_RMID
00084     case IPC_RMID:
00085 #endif
00086 #ifdef IPC_STAT
00087     case IPC_STAT:
00088 #endif
00089 #ifdef SHM_INFO
00090     case SHM_INFO:
00091 #endif
00092 #ifdef SHM_LOCK
00093     case SHM_LOCK:
00094 #endif
00095 #ifdef SHM_STAT
00096     case SHM_STAT:
00097 #endif
00098 #ifdef SHM_UNLOCK
00099     case SHM_UNLOCK:
00100 #endif
00101     default:
00102         explain_buffer_pointer(sb, data);
00103         break;
00104     }
00105     explain_string_buffer_putc(sb, ')');
00106 }
00107 
00108 
00109 void
00110 explain_buffer_errno_shmctl_explanation(explain_string_buffer_t *sb, int errnum,
00111     const char *syscall_name, int shmid, int command, struct shmid_ds *data)
00112 {
00113     /*
00114      * http://www.opengroup.org/onlinepubs/009695399/functions/shmctl.html
00115      */
00116     switch (errnum)
00117     {
00118     case EFAULT:
00119         if (!data)
00120             explain_buffer_is_the_null_pointer(sb, "data");
00121         else
00122             explain_buffer_efault(sb, "data");
00123         break;
00124 
00125 #ifdef EIDRM
00126     case EIDRM:
00127         explain_buffer_gettext
00128         (
00129             sb,
00130             /*
00131              * xgettext: This erro rmessage is used to describe the cause of an
00132              * EIDRM error reported by the shmctl(2) system call, in the case
00133              * where the shmid refers to a removed identifier.
00134              */
00135             i18n("shmid refers to a removed identifier")
00136         );
00137         break;
00138 #endif
00139 
00140     case EINVAL:
00141         /*
00142          * 1. shmid is not a valid identifier; or
00143          * 2. command is not a valid command; or
00144          * 3. for a SHM_STAT operation, the index value specified in
00145          *    shmid referred to an array slot that is currently unused.
00146          */
00147         switch (command)
00148         {
00149 #ifdef IPC_STAT
00150         case IPC_STAT:
00151 #endif
00152 #ifdef IPC_SET
00153         case IPC_SET:
00154 #endif
00155 #ifdef IPC_RMID
00156         case IPC_RMID:
00157 #endif
00158 #ifdef IPC_INFO
00159         case IPC_INFO:
00160 #endif
00161 #ifdef SHM_INFO
00162         case SHM_INFO:
00163 #endif
00164 #ifdef SHM_STAT
00165         case SHM_STAT:
00166 #endif
00167 #ifdef SHM_LOCK
00168         case SHM_LOCK:
00169 #endif
00170 #ifdef SHM_UNLOCK
00171         case SHM_UNLOCK:
00172 #endif
00173             break;
00174 
00175         default:
00176             explain_buffer_einval_vague(sb, "command");
00177             break;
00178         }
00179         explain_buffer_einval_vague(sb, "data");
00180         break;
00181 
00182     case ENOMEM:
00183         explain_buffer_enomem_kernel(sb);
00184         break;
00185 
00186     case EOVERFLOW:
00187         explain_buffer_eoverflow(sb);
00188         break;
00189 
00190     case EACCES:
00191     case EPERM:
00192 #ifdef SHM_LOCK
00193         if (command == SHM_LOCK || command == SHM_UNLOCK)
00194         {
00195             /*
00196              * "In kernels before 2.6.9, SHM_LOCK or SHM_UNLOCK was specified,
00197              * but the process was not privileged (Linux did not have the
00198              * CAP_IPC_LOCK capability).  Since Linux 2.6.9, this error can
00199              * also occur if the RLIMIT_MEMLOCK is 0 and the caller is not
00200              * privileged."
00201              */
00202             explain_string_buffer_printf
00203             (
00204                 sb,
00205                 /* FIXME: i18n */
00206                 "the process does not have %s lock privileges",
00207                 explain_translate_shared_memory_segment()
00208             );
00209             explain_buffer_dac_ipc_lock(sb);
00210         }
00211 #endif
00212 
00213         {
00214             struct shmid_ds xyz;
00215 
00216             if (wrap_shmctl(shmid, IPC_STAT, &xyz) >= 0)
00217             {
00218                 explain_buffer_eacces_shmat(sb, &xyz.shm_perm, 1);
00219                 break;
00220             }
00221         }
00222         explain_buffer_eacces_shmat_vague(sb);
00223         break;
00224 
00225     default:
00226         explain_buffer_errno_generic(sb, errnum, syscall_name);
00227         break;
00228     }
00229 }
00230 
00231 
00232 void
00233 explain_buffer_errno_shmctl(explain_string_buffer_t *sb, int errnum, int shmid,
00234     int command, struct shmid_ds *data)
00235 {
00236     explain_explanation_t exp;
00237 
00238     explain_explanation_init(&exp, errnum);
00239     explain_buffer_errno_shmctl_system_call(&exp.system_call_sb, errnum, shmid,
00240         command, data);
00241     explain_buffer_errno_shmctl_explanation(&exp.explanation_sb, errnum,
00242         "shmctl", shmid, command, data);
00243     explain_explanation_assemble(&exp, sb);
00244 }
00245 
00246 
00247 /* vim: set ts=8 sw=4 et : */