libexplain  1.4.D001
libexplain/buffer/errno/setpgid.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/assert.h>
00020 #include <libexplain/ac/errno.h>
00021 
00022 #include <libexplain/buffer/einval.h>
00023 #include <libexplain/buffer/errno/generic.h>
00024 #include <libexplain/buffer/errno/setpgid.h>
00025 #include <libexplain/buffer/esrch.h>
00026 #include <libexplain/buffer/gettext.h>
00027 #include <libexplain/buffer/pid_t_star.h>
00028 #include <libexplain/explanation.h>
00029 #include <libexplain/process_exists.h>
00030 
00031 
00032 static void
00033 explain_buffer_errno_setpgid_system_call(explain_string_buffer_t *sb,
00034     int errnum, pid_t pid, pid_t pgid)
00035 {
00036     (void)errnum;
00037     explain_string_buffer_puts(sb, "setpgid(pid = ");
00038     explain_buffer_pid_t(sb, pid);
00039     explain_string_buffer_puts(sb, ", pgid = ");
00040     explain_buffer_pid_t(sb, pgid);
00041     explain_string_buffer_putc(sb, ')');
00042 }
00043 
00044 
00045 void
00046 explain_buffer_errno_setpgid_explanation(explain_string_buffer_t *sb,
00047     int errnum, const char *syscall_name, pid_t pid, pid_t pgid)
00048 {
00049     pid_t           me;
00050 
00051     me = getpid();
00052     assert(me >= 1);
00053     if (!pid)
00054         pid = me;
00055     if (!pgid)
00056         pgid = pid;
00057 
00058     /*
00059      * http://www.opengroup.org/onlinepubs/009695399/functions/setpgid.html
00060      */
00061     switch (errnum)
00062     {
00063     case EACCES:
00064         explain_buffer_gettext
00065         (
00066             sb,
00067             /*
00068              * xgettext:  This error message is used to explain an EACCES
00069              * error reported by the setpgid(2) system call, in the case where
00070              * an attempt was made to change the process group ID of one of
00071              * the children of the calling process and the child had already
00072              * performed an execve(2).
00073              */
00074             i18n("an attempt was made to change the process group ID of "
00075                 "one of the children of the calling process and the "
00076                 "child had already performed an execve(2)")
00077         );
00078         break;
00079 
00080     case EINVAL:
00081         if (pid < 0)
00082         {
00083             pid_too_small:
00084             explain_buffer_einval_too_small(sb, "pid", pid);
00085             break;
00086         }
00087         if (!explain_process_exists(pid))
00088         {
00089             no_such_pid:
00090             explain_buffer_esrch(sb, "pid", pid);
00091             break;
00092         }
00093         if (pgid < 0)
00094         {
00095             pgid_too_small:
00096             explain_buffer_einval_too_small(sb, "pgid", pgid);
00097             break;
00098         }
00099         if (!explain_process_exists(pgid))
00100         {
00101             no_such_pgid:
00102             explain_buffer_esrch(sb, "pgid", pgid);
00103             break;
00104         }
00105         goto generic;
00106 
00107     case EPERM:
00108         {
00109             pid_t           sid_of_me;
00110             pid_t           sid_of_pid;
00111             pid_t           sid_of_pgid;
00112 
00113             /*
00114              * NOTE: while pgid values are usually process IDs, they
00115              * don't have to be.  They can be zero, as is the case for
00116              * many processes spawned by the kernel itself.
00117              */
00118 
00119             sid_of_me = getsid(me);
00120             if (sid_of_me < 0)
00121                 goto barf;
00122 
00123             if (pid < 0)
00124                 goto pid_too_small;
00125             sid_of_pid = getsid(pid);
00126             if (sid_of_pid < 0)
00127             {
00128                 if (errno == ESRCH)
00129                     goto no_such_pid;
00130                 goto barf;
00131             }
00132 
00133             if (pgid < 0)
00134                 goto pgid_too_small;
00135             sid_of_pgid = getsid(pgid);
00136             if (sid_of_pgid < 0)
00137             {
00138                 if (errno == ESRCH)
00139                     goto no_such_pgid;
00140                 goto barf;
00141             }
00142 
00143             /*
00144              * You are not allowed to move a process into a process group in a
00145              * different session.
00146              */
00147             if (sid_of_pid != sid_of_pgid)
00148             {
00149                 explain_buffer_gettext
00150                 (
00151                     sb,
00152                     /*
00153                      * xgettext: This error message is used to explain an
00154                      * ESRCH error reported by a setpgid system call, in the
00155                      * case where an attempt was made to move a process into a
00156                      * process group in a different session.
00157                      */
00158                     i18n("an attempt was made to move a process into a process "
00159                         "group in a different session")
00160                 );
00161                 break;
00162             }
00163 
00164             /*
00165              * You are not allowed to change the process group ID of a
00166              * session leader.
00167              *
00168              * You can tell a process is a session group leader, because
00169              * the sid and the pid are the same.
00170              */
00171             if (pid == sid_of_pid && pgid != pid)
00172             {
00173                 explain_buffer_gettext
00174                 (
00175                     sb,
00176                     /*
00177                      * xgettext: This error message is used to explain an ESRCH
00178                      * error reported by a setpgid system call, in the case
00179                      * where an attempt was made to change the process group ID
00180                      * of a session leader
00181                      */
00182                     i18n("an attempt was made to change the process group ID "
00183                         "of a session leader")
00184                 );
00185                 break;
00186             }
00187 
00188             /* we have no way to tell */
00189             barf:
00190             explain_buffer_gettext
00191             (
00192                 sb,
00193                 /*
00194                  * xgettext: This error message is used to explain an ESRCH
00195                  * error reported by a setpgid system call, in the case where an
00196                  * attempt was made to move a process into a process group in a
00197                  * different session, or to change the process group ID of one
00198                  * of the children of the calling process and the child was in
00199                  * a different session, or to change the process group ID of a
00200                  * session leader
00201                  */
00202                 i18n("an attempt was made to move a process into a process "
00203                     "group in a different session, or to change the process "
00204                     "group ID of one of the children of the calling process "
00205                     "and the child was in a different session, or to change "
00206                     "the process group ID of a session leader")
00207             );
00208         }
00209         break;
00210 
00211     case ESRCH:
00212         if (pid < 0)
00213             goto pid_too_small;
00214         if (!explain_process_exists(pid))
00215             goto no_such_pid;
00216         if (pgid < 0)
00217             goto pgid_too_small;
00218         if (!explain_process_exists(pgid))
00219             goto no_such_pgid;
00220 
00221         if (pid != me)
00222         {
00223             explain_buffer_gettext
00224             (
00225                 sb,
00226                 /*
00227                  * xgettext: This error message is used to explain an ESRCH
00228                  * error reported by the setpgid system call, in the case where
00229                  * pid is not the calling process and not a child of the calling
00230                  * process.
00231                  */
00232                 i18n("pid is not the calling process and not a child of "
00233                     "the calling process")
00234             );
00235             break;
00236         }
00237         goto generic;
00238 
00239     default:
00240         generic:
00241         explain_buffer_errno_generic(sb, errnum, syscall_name);
00242         break;
00243     }
00244 }
00245 
00246 
00247 void
00248 explain_buffer_errno_setpgid(explain_string_buffer_t *sb, int errnum, pid_t pid,
00249     pid_t pgid)
00250 {
00251     explain_explanation_t exp;
00252 
00253     explain_explanation_init(&exp, errnum);
00254     explain_buffer_errno_setpgid_system_call(&exp.system_call_sb, errnum, pid,
00255         pgid);
00256     explain_buffer_errno_setpgid_explanation(&exp.explanation_sb, errnum,
00257         "setpgid", pid, pgid);
00258     explain_explanation_assemble(&exp, sb);
00259 }
00260 
00261 
00262 /* vim: set ts=8 sw=4 et : */