libexplain  1.4.D001
libexplain/buffer/errno/path_resolution.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 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 published by
00008  * the Free Software Foundation; either version 3 of the License, or (at
00009  * 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/assert.h>
00021 #include <libexplain/ac/ctype.h>
00022 #include <libexplain/ac/dirent.h>
00023 #include <libexplain/ac/errno.h>
00024 #include <libexplain/ac/fcntl.h>
00025 #include <libexplain/ac/limits.h> /* for PATH_MAX on Solaris */
00026 #include <libexplain/ac/stdlib.h>
00027 #include <libexplain/ac/string.h>
00028 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */
00029 #include <libexplain/ac/sys/stat.h>
00030 #include <libexplain/ac/unistd.h>
00031 
00032 #include <libexplain/buffer/caption_name_type.h>
00033 #include <libexplain/buffer/dac.h>
00034 #include <libexplain/buffer/does_not_have_inode_modify_permission.h>
00035 #include <libexplain/buffer/eexist.h>
00036 #include <libexplain/buffer/errno/path_resolution.h>
00037 #include <libexplain/buffer/file_type.h>
00038 #include <libexplain/buffer/gettext.h>
00039 #include <libexplain/buffer/mount_point.h>
00040 #include <libexplain/buffer/uid.h>
00041 #include <libexplain/buffer/wrong_file_type.h>
00042 #include <libexplain/capability.h>
00043 #include <libexplain/fstrcmp.h>
00044 #include <libexplain/getppcwd.h>
00045 #include <libexplain/have_permission.h>
00046 #include <libexplain/name_max.h>
00047 #include <libexplain/option.h>
00048 #include <libexplain/symloopmax.h>
00049 
00050 
00051 static int
00052 all_slash(const char *s)
00053 {
00054     while (*s == '/')
00055         ++s;
00056     return !*s;
00057 }
00058 
00059 
00060 static void
00061 look_for_similar(explain_string_buffer_t *sb, const char *lookup_directory,
00062     const char *component)
00063 {
00064     DIR             *dp;
00065     char            best_name[NAME_MAX + 1];
00066     double          best_weight;
00067     char            subject[NAME_MAX * 4 + 3];
00068     explain_string_buffer_t subject_sb;
00069     struct stat     st;
00070 
00071     dp = opendir(lookup_directory);
00072     if (!dp)
00073         return;
00074 
00075     best_name[0] = '\0';
00076     best_weight = 0.6;
00077     for (;;)
00078     {
00079         struct dirent   *dep;
00080         double          weight;
00081 
00082         dep = readdir(dp);
00083         if (!dep)
00084             break;
00085         if (0 == strcmp(dep->d_name, "."))
00086             continue;
00087         if (0 == strcmp(dep->d_name, ".."))
00088             continue;
00089         weight = explain_fstrcasecmp(component, dep->d_name);
00090         if (best_weight < weight)
00091         {
00092             best_weight = weight;
00093             explain_strendcpy
00094             (
00095                 best_name,
00096                 dep->d_name,
00097                 best_name + sizeof(best_name)
00098             );
00099         }
00100     }
00101     closedir(dp);
00102 
00103     if (best_name[0] == '\0')
00104         return;
00105 
00106     memset(&st, 0, sizeof(st));
00107     {
00108         /*
00109          * see if we can say what kind of file it is
00110          */
00111         char            ipath[PATH_MAX + 1];
00112         char            *ipath_end;
00113         char            *ip;
00114 
00115         ipath_end = ipath + sizeof(ipath);
00116         ip = ipath;
00117         ip = explain_strendcpy(ip, lookup_directory, ipath_end);
00118         ip = explain_strendcpy(ip, "/", ipath_end);
00119         ip = explain_strendcpy(ip, best_name, ipath_end);
00120         lstat(ipath, &st);
00121     }
00122 
00123     explain_string_buffer_init(&subject_sb, subject, sizeof(subject));
00124     if (st.st_dev)
00125         explain_buffer_caption_name_type_st(&subject_sb, 0, best_name, &st);
00126     else
00127         explain_buffer_caption_name_type(&subject_sb, 0, best_name, -1);
00128 
00129     explain_string_buffer_puts(sb->footnotes, "; ");
00130     explain_string_buffer_printf_gettext
00131     (
00132         sb->footnotes,
00133         /*
00134          * xgettext: This message is issued when a file (or directory
00135          * component) could not be found, but a sufficiently similar
00136          * name has been found in the same directory.  This often helps
00137          * with typographical errors.
00138          *
00139          * %1$s => the name (already quoted) and file type (already
00140          *         translated) of the alternate file found.
00141          */
00142         i18n("did you mean the %s instead?"),
00143         subject
00144     );
00145 }
00146 
00147 
00148 static int
00149 command_interpreter_broken(explain_string_buffer_t *sb, const char *pathname)
00150 {
00151     char            block[512];
00152     int             fd;
00153     ssize_t         n;
00154     char            *end;
00155     char            *interpreter_pathname;
00156     explain_final_t final_component;
00157     char            *bp;
00158 
00159     fd = open(pathname, O_RDONLY);
00160     if (fd < 0)
00161         return -1;
00162     n = read(fd, block, sizeof(block) - 1);
00163     close(fd);
00164     if (n < 4)
00165         return -1;
00166     end = block + n;
00167     if (block[0] != '#')
00168         return -1;
00169     if (block[1] != '!')
00170         return -1;
00171     bp = block + 2;
00172     while (bp < end && (*bp == ' ' || *bp == '\t'))
00173         ++bp;
00174     if (bp >= end)
00175         return -1;
00176     interpreter_pathname = bp;
00177     ++bp;
00178     while (bp < end && !isspace(*bp))
00179         ++bp;
00180     *bp = '\0';
00181 
00182     explain_final_init(&final_component);
00183     final_component.want_to_execute = 1;
00184     final_component.follow_interpreter = 0; /* avoid infinite loops */
00185     return
00186         explain_buffer_errno_path_resolution
00187         (
00188             sb,
00189             EACCES,
00190             interpreter_pathname,
00191             "#!",
00192             &final_component
00193         );
00194 }
00195 
00196 
00197 static int
00198 hash_bang(explain_string_buffer_t *sb, const char *pathname)
00199 {
00200     int             fd;
00201     ssize_t         n;
00202     char            *end;
00203     char            *interpreter_pathname;
00204     char            *bp;
00205     char            block[512];
00206     char            qintname[PATH_MAX + 1];
00207     explain_string_buffer_t qintname_sb;
00208 
00209     fd = open(pathname, O_RDONLY);
00210     if (fd < 0)
00211         return -1;
00212     n = read(fd, block, sizeof(block) - 1);
00213     close(fd);
00214     if (n < 4)
00215         return -1;
00216     end = block + n;
00217     if (block[0] != '#')
00218         return -1;
00219     if (block[1] != '!')
00220         return -1;
00221     bp = block + 2;
00222     while (bp < end && (*bp == ' ' || *bp == '\t'))
00223         ++bp;
00224     if (bp >= end)
00225         return -1;
00226     interpreter_pathname = bp;
00227     ++bp;
00228     while (bp < end && !isspace(*bp))
00229         ++bp;
00230     *bp = '\0';
00231 
00232     explain_string_buffer_init(&qintname_sb, qintname, sizeof(qintname));
00233     explain_string_buffer_puts_quoted(&qintname_sb, interpreter_pathname);
00234 
00235     explain_string_buffer_printf_gettext
00236     (
00237         sb,
00238         /*
00239          * xgettext: This message is used to explain an EACCES error,
00240          * where nested #! interpreter files are attempted.
00241          *
00242          * %1$s => The quoted pathname of the first file that contains an
00243          *         interpreter (#!) line, that points at yet another
00244          *         interpreted file.
00245          */
00246         i18n("too many levels of interpreters (%s)"),
00247         qintname
00248     );
00249     return 0;
00250 }
00251 
00252 
00253 static void
00254 directory_does_not_exist(explain_string_buffer_t *sb, const char *caption,
00255     const char *dirname)
00256 {
00257     char            subject[PATH_MAX + 50];
00258     explain_string_buffer_t subject_sb;
00259 
00260     explain_string_buffer_init(&subject_sb, subject, sizeof(subject));
00261     explain_buffer_caption_name_type(&subject_sb, caption, dirname, S_IFDIR);
00262     explain_string_buffer_printf_gettext
00263     (
00264         sb,
00265         /*
00266          * xgettext: This message is used when a path is being used as a
00267          * directory, when does not exist.
00268          *
00269          * %1$s => the name of the system call argument, the quoted path
00270          *         and the expected file type ("directory", already translated).
00271          */
00272         i18n("%s does not exist"),
00273         subject
00274     );
00275 }
00276 
00277 
00278 static void
00279 not_a_directory(explain_string_buffer_t *sb, const char *caption,
00280     const char *dir, const struct stat *st)
00281 {
00282     char            subject[PATH_MAX + 50];
00283     explain_string_buffer_t subject_sb;
00284 
00285     explain_string_buffer_init(&subject_sb, subject, sizeof(subject));
00286     explain_buffer_caption_name_type(&subject_sb, caption, dir, -1);
00287     explain_buffer_wrong_file_type_st(sb, st, subject, S_IFDIR);
00288 }
00289 
00290 
00291 static void
00292 no_such_directory_entry(explain_string_buffer_t *sb, const char *comp,
00293     int comp_st_mode, const char *dir_caption, const char *dir, int dir_st_mode)
00294 {
00295     char part1[NAME_MAX * 4 + 100];
00296     explain_string_buffer_t part1_sb;
00297     char part2[PATH_MAX * 4 + 100];
00298     explain_string_buffer_t part2_sb;
00299 
00300     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00301     explain_buffer_caption_name_type(&part1_sb, 0, comp, comp_st_mode);
00302     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00303     explain_buffer_caption_name_type
00304     (
00305         &part2_sb,
00306         dir_caption,
00307         dir,
00308         dir_st_mode
00309     );
00310 
00311     explain_string_buffer_printf_gettext
00312     (
00313         sb,
00314         /*
00315          * xgettext: This message is used when directory does not have a
00316          * directory entry for the named component.
00317          *
00318          * Different language grammars may need to rearrange the parts.
00319          *
00320          * %1$s => The name of the offending path component (will never have
00321          *         slashes).  It will be quoted.
00322          * %2$s => The name of the directory that contains the problematic
00323          *         component; it may have zero, one or more slashes in it.  Will
00324          *         include the name of the function call argument, the name of
00325          *         the directory, and the file type "directory".
00326          */
00327         i18n("there is no %s in the %s"),
00328         part1,
00329         part2
00330     );
00331 }
00332 
00333 
00334 static void
00335 not_possible_to_execute(explain_string_buffer_t *sb, const char *caption,
00336     const char *name, int st_mode)
00337 {
00338     char            ftype[NAME_MAX * 4 + 50];
00339     explain_string_buffer_t ftype_sb;
00340 
00341     explain_string_buffer_init(&ftype_sb, ftype, sizeof(ftype));
00342     explain_buffer_caption_name_type(&ftype_sb, caption, name, st_mode);
00343 
00344     explain_string_buffer_printf_gettext
00345     (
00346         sb,
00347         /*
00348          * xgettext: This message is issued when a user attempts to
00349          * execute something that is not a file, such as a block special
00350          * device.
00351          *
00352          * %1$s => the name of the system call argument, the name of the
00353          *         final path component and the type of the file.
00354          */
00355         i18n("it is not possible to execute the %s, "
00356             "only regular files can be executed"),
00357         ftype
00358     );
00359 }
00360 
00361 
00362 static void
00363 does_not_have_search_permission(explain_string_buffer_t *sb,
00364     const char *comp, const struct stat *comp_st, const char *caption,
00365     const char *dir, const struct stat *dir_st,
00366     const explain_have_identity_t *hip)
00367 {
00368     char part1[NAME_MAX * 4 + 100];
00369     explain_string_buffer_t part1_sb;
00370     char part2[PATH_MAX * 4 + 100];
00371     explain_string_buffer_t part2_sb;
00372 
00373     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00374     explain_buffer_caption_name_type_st(&part1_sb, 0, comp, comp_st);
00375     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00376     explain_buffer_caption_name_type_st
00377     (
00378         &part2_sb,
00379         caption,
00380         dir,
00381         dir_st
00382     );
00383 
00384     explain_string_buffer_printf_gettext
00385     (
00386         sb,
00387         /*
00388          * xgettext: This message is used when a process does not have
00389          * search permission to a directory it attempts to traverse.
00390          * Different language grammars may need to rearrange the parts.
00391          *
00392          * %1$s => The name of the component of the path, the subdirectory in
00393          *         question (will never have slashes).  It will in clude the
00394          *         name of the file, and the file type "directory".
00395          * %2$s => The name of the directory that contains the subdirectory in
00396          *         question; it may have zero, one or more slashes in it.  Will
00397          *         include the name of the function call argument, the name of
00398          *         the directory, and the file type "directory".
00399          */
00400         i18n("the process does not have search permission to the %s in "
00401             "the %s"),
00402         part1,
00403         part2
00404     );
00405     explain_explain_search_permission(sb, comp_st, hip);
00406 }
00407 
00408 
00409 static void
00410 does_not_have_search_permission1(explain_string_buffer_t *sb,
00411     const char *caption, const char *dir, const struct stat *dir_st,
00412     const explain_have_identity_t *hip)
00413 {
00414     char            dir_part[PATH_MAX + 100];
00415     explain_string_buffer_t dir_part_sb;
00416 
00417     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00418     explain_buffer_caption_name_type_st
00419     (
00420         &dir_part_sb,
00421         caption,
00422         dir,
00423         dir_st
00424     );
00425 
00426     explain_string_buffer_printf_gettext
00427     (
00428         sb,
00429         /*
00430          * xgettext: This message is used when a process does not have
00431          * search permission to a directory it attempts to traverse.
00432          * (Only used for problems with "." and "/".)
00433          * Different language grammars may need to rearrange the parts.
00434          *
00435          * %1$s => The pathname, the directory in question.  It will
00436          *         include the name of the function call argument, the
00437          *         name of the directory, file type "directory".
00438          */
00439         i18n("the process does not have search permission to the %s"),
00440         dir_part
00441     );
00442     explain_explain_search_permission(sb, dir_st, hip);
00443 }
00444 
00445 
00446 static void
00447 does_not_have_execute_permission(explain_string_buffer_t *sb,
00448     const char *comp, const struct stat *comp_st, const char *caption,
00449     const char *dir, const struct stat *dir_st,
00450     const explain_have_identity_t *hip)
00451 {
00452     char            final_part[NAME_MAX * 4 + 100];
00453     explain_string_buffer_t final_part_sb;
00454     char            dir_part[PATH_MAX * 4 + 100];
00455     explain_string_buffer_t dir_part_sb;
00456 
00457     explain_string_buffer_init
00458     (
00459         &final_part_sb,
00460         final_part,
00461         sizeof(final_part)
00462     );
00463     explain_buffer_caption_name_type_st(&final_part_sb, 0, comp, comp_st);
00464     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00465     explain_buffer_caption_name_type_st(&dir_part_sb, caption, dir, dir_st);
00466 
00467     explain_string_buffer_printf_gettext
00468     (
00469         sb,
00470         /*
00471          * xgettext: This message is used when a process does not have
00472          * execute permission to something it attempts to execute; for
00473          * example, one of the execve calls, or similar.
00474          * Different language grammars may need to rearrange the parts.
00475          *
00476          * %1$s => the name of the final component of the path, the
00477          *         regular file in question (will never have slashes).
00478          *         It will in clude the name of the file, and the file
00479          *         type "regular file".
00480          * %2$s => the name of the directory that contains the regular
00481          *         file to be executed; it may have zero, one or more
00482          *         slashes in it.  Will include the name of the function
00483          *         call argument, the name of the directory, and the
00484          *         file type "directory".
00485          */
00486         i18n("the process does not have execute permission to the %s in "
00487             "the %s"),
00488         final_part,
00489         dir_part
00490     );
00491     explain_explain_execute_permission(sb, comp_st, hip);
00492 }
00493 
00494 
00495 static void
00496 does_not_have_read_permission(explain_string_buffer_t *sb, const char *comp,
00497     const struct stat *comp_st, const char *caption, const char *dir,
00498     const struct stat *dir_st, const explain_have_identity_t *hip)
00499 {
00500     char            final_part[NAME_MAX * 4 + 100];
00501     explain_string_buffer_t final_part_sb;
00502     char            dir_part[PATH_MAX * 4 + 100];
00503     explain_string_buffer_t dir_part_sb;
00504 
00505     explain_string_buffer_init
00506     (
00507         &final_part_sb,
00508         final_part,
00509         sizeof(final_part)
00510     );
00511     explain_buffer_caption_name_type_st(&final_part_sb, 0, comp, comp_st);
00512     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00513     explain_buffer_caption_name_type_st(&dir_part_sb, caption, dir, dir_st);
00514 
00515     explain_string_buffer_printf_gettext
00516     (
00517         sb,
00518         /*
00519          * xgettext: This message is used when a process does not have
00520          * read permission to something it attempts to
00521          * open for reading; for example, open() or fopen().
00522          * Different language grammars may need to rearrange the parts.
00523          *
00524          * %1$s => the name of the final component of the path, the
00525          *         regular file in question (will never have slashes).
00526          *         It will include the name of the file, and the file
00527          *         type "regular file".
00528          * %2$s => the name of the directory that contains the regular
00529          *         file to be executed; it may have zero, one or more
00530          *         slashes in it.  Will include the name of the function
00531          *         call argument, the name of the directory, and the
00532          *         file type "directory".
00533          */
00534         i18n("the process does not have read permission to the %s in the %s"),
00535         final_part,
00536         dir_part
00537     );
00538     explain_explain_read_permission(sb, comp_st, hip);
00539 }
00540 
00541 
00542 static void
00543 does_not_have_write_permission(explain_string_buffer_t *sb, const char *comp,
00544     const struct stat *comp_st, const char *caption, const char *dir,
00545     const struct stat *dir_st, const explain_have_identity_t *hip)
00546 {
00547     char            final_part[NAME_MAX * 4 + 100];
00548     explain_string_buffer_t final_part_sb;
00549     char            dir_part[PATH_MAX * 4 + 100];
00550     explain_string_buffer_t dir_part_sb;
00551 
00552     explain_string_buffer_init
00553     (
00554         &final_part_sb,
00555         final_part,
00556         sizeof(final_part)
00557     );
00558     explain_buffer_caption_name_type_st(&final_part_sb, 0, comp, comp_st);
00559     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00560     explain_buffer_caption_name_type_st(&dir_part_sb, caption, dir, dir_st);
00561 
00562     explain_string_buffer_printf_gettext
00563     (
00564         sb,
00565         /*
00566          * xgettext: This message is used when a process does not have
00567          * write permission to something it attempts to
00568          * open for writing; for example, open() or fopen().
00569          * Different language grammars may need to rearrange the parts.
00570          *
00571          * %1$s => the name of the final component of the path, the
00572          *         regular file in question (will never have slashes).
00573          *         It will include the name of the file, and the file
00574          *         type "regular file".
00575          * %2$s => the name of the directory that contains the regular
00576          *         file to be executed; it may have zero, one or more
00577          *         slashes in it.  Will include the name of the function
00578          *         call argument, the name of the directory, and the
00579          *         file type "directory".
00580          */
00581         i18n("the process does not have write permission to the %s in the %s"),
00582         final_part,
00583         dir_part
00584     );
00585     explain_explain_write_permission(sb, comp_st, hip);
00586 }
00587 
00588 
00589 static void
00590 does_not_have_new_directory_entry_permission(explain_string_buffer_t *sb,
00591     const char *caption, const char *dir, const struct stat *dir_st,
00592     const char *comp, int comp_st_mode, const explain_have_identity_t *hip)
00593 {
00594     char            dir_part[PATH_MAX * 4 + 100];
00595     explain_string_buffer_t dir_part_sb;
00596     char            final_part[NAME_MAX * 4 + 100];
00597     explain_string_buffer_t final_part_sb;
00598 
00599     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00600     explain_buffer_caption_name_type_st(&dir_part_sb, caption, dir, dir_st);
00601     explain_string_buffer_init
00602     (
00603         &final_part_sb,
00604         final_part,
00605         sizeof(final_part)
00606     );
00607     explain_buffer_caption_name_type(&final_part_sb, 0, comp, comp_st_mode);
00608 
00609     explain_string_buffer_printf_gettext
00610     (
00611         sb,
00612         /*
00613          * xgettext: This message is used when a process does not have write
00614          * permission to a directoryin order to create a new directory entry;
00615          * for example creat(), mkdir(), symlink(), etc.
00616          * Different language grammars may need to rearrange the parts.
00617          *
00618          * %1$s => The name of the directory that is to receive the new
00619          *         directory entry; it may have zero, one or more slashes in it.
00620          *         Will include the name of the function call argument, the name
00621          *         of the directory, and the file type "directory".
00622          * %2$s => The name of the final component of the path, the
00623          *         new directory entry in question (will never have slashes).
00624          *         It will include the name of the new file, and the file type.
00625          */
00626         i18n("the process does not have write permission to the %s, this is "
00627             "needed to create the directory entry for the %s"),
00628         dir_part,
00629         final_part
00630     );
00631     explain_explain_write_permission(sb, dir_st, hip);
00632 }
00633 
00634 
00635 static void
00636 dangling_symbolic_link(explain_string_buffer_t *sb, const char *comp,
00637     int comp_st_mode, const char *caption, const char *dir, int dir_st_mode,
00638     const char *garbage)
00639 {
00640     char            final_part[NAME_MAX * 2 + 100];
00641     explain_string_buffer_t final_part_sb;
00642     char            dir_part[PATH_MAX * 2 + 100];
00643     explain_string_buffer_t dir_part_sb;
00644     char            dangling_part[PATH_MAX * 2 + 100];
00645     explain_string_buffer_t dangling_part_sb;
00646 
00647     explain_string_buffer_init
00648     (
00649         &final_part_sb,
00650         final_part,
00651         sizeof(final_part)
00652     );
00653     explain_buffer_caption_name_type(&final_part_sb, 0, comp, comp_st_mode);
00654     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00655     explain_buffer_caption_name_type
00656     (
00657         &dir_part_sb,
00658         caption,
00659         dir,
00660         dir_st_mode
00661     );
00662     explain_string_buffer_init
00663     (
00664         &dangling_part_sb,
00665         dangling_part,
00666         sizeof(dangling_part)
00667     );
00668     explain_string_buffer_puts_quoted(&dangling_part_sb, garbage);
00669 
00670     explain_string_buffer_printf_gettext
00671     (
00672         sb,
00673         /*
00674          * xgettext: This message is used when there is a dangling
00675          * symbolic link.
00676          *
00677          * Different language grammars may need to rearrange the parts.
00678          *
00679          * %1$s => The name of the final component of the path, the name of
00680          *         symbolic link in question, will include the file type
00681          *         "symbolic link", but will never have slashes.
00682          * %2$s => The name of the directory that contains the symbolic link;
00683          *         it may have zero, one or more slashes in it.  Will include
00684          *         the name of the function call argument, the name of the
00685          *         directory, and the file type "directory".
00686          * %3$s => the non-existent thing the symbolic link point to
00687          */
00688         i18n("the %s in the %s refers to %s that does not exist"),
00689         final_part,
00690         dir_part,
00691         dangling_part
00692     );
00693 }
00694 
00695 
00696 static void
00697 name_too_long(explain_string_buffer_t *sb, const char *caption,
00698     const char *component, long comp_length, long name_max)
00699 {
00700     char            part1[PATH_MAX * 2];
00701     explain_string_buffer_t part1_sb;
00702 
00703     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00704     explain_string_buffer_puts(&part1_sb, caption);
00705     explain_string_buffer_putc(&part1_sb, ' ');
00706     explain_string_buffer_puts_quoted(&part1_sb, component);
00707 
00708     explain_string_buffer_printf_gettext
00709     (
00710         sb,
00711         /*
00712          * xgettext: This message is used when a path name component is
00713          * longer than the system limit (NAME_MAX, not PATH_MAX).
00714          *
00715          * %1$s => the name of the function call argument and the quoted
00716          *         text of the offending path component.
00717          */
00718         i18n("%s component is longer than the system limit"),
00719         part1
00720     );
00721     explain_string_buffer_printf(sb, " (%ld > %ld)", comp_length, name_max);
00722 }
00723 
00724 
00725 static void
00726 not_a_subdirectory(explain_string_buffer_t *sb, const char *comp,
00727     int comp_st_mode, const char *caption, const char *dir, int dir_st_mode)
00728 {
00729     char part1[NAME_MAX * 4 + 100];
00730     explain_string_buffer_t part1_sb;
00731     char part2[PATH_MAX * 4 + 100];
00732     explain_string_buffer_t part2_sb;
00733 
00734     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00735     explain_buffer_caption_name_type(&part1_sb, 0, comp, comp_st_mode);
00736     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00737     explain_buffer_caption_name_type(&part2_sb, caption, dir, dir_st_mode);
00738 
00739     explain_string_buffer_printf_gettext
00740     (
00741         sb,
00742         /*
00743          * xgettext: This message is used when directory has a directory
00744          * entry for the named component, but a directory was expected
00745          * and something else was there instead.
00746          *
00747          * Different language grammars may need to rearrange the parts.
00748          *
00749          * %1$s => The name of the offending path component (will never have
00750          *         slashes).  It is already quoted.
00751          * %2$s => The name of the directory that contains the problematic
00752          *         component; it may have zero, one or more slashes in it.  Will
00753          *         include the name of the function call argument, the name of
00754          *         the directory, and the file type "directory".
00755          */
00756         i18n("the %s in the %s is being used as a directory when it is not"),
00757         part1,
00758         part2
00759     );
00760 }
00761 
00762 
00763 static void
00764 wrong_file_type(explain_string_buffer_t *sb, const char *caption,
00765     const char *dir, int dir_st_mode, const char *comp, int comp_st_mode,
00766     int wanted_st_mode)
00767 {
00768     char part1[PATH_MAX * 4 + 100];
00769     explain_string_buffer_t part1_sb;
00770     char part2[NAME_MAX * 4 + 100];
00771     explain_string_buffer_t part2_sb;
00772     char part3[100];
00773     explain_string_buffer_t part3_sb;
00774 
00775     explain_string_buffer_init(&part2_sb, part2, sizeof(part2));
00776     explain_buffer_caption_name_type(&part2_sb, 0, comp, comp_st_mode);
00777     explain_string_buffer_init(&part1_sb, part1, sizeof(part1));
00778     explain_buffer_caption_name_type(&part1_sb, caption, dir, dir_st_mode);
00779     explain_string_buffer_init(&part3_sb, part3, sizeof(part3));
00780     explain_buffer_file_type(&part3_sb, wanted_st_mode);
00781 
00782     explain_string_buffer_printf_gettext
00783     (
00784         sb,
00785         /*
00786          * xgettext: This message is used when directory has a directory
00787          * entry for the named component, but a directory was expected
00788          * and something else was there instead.
00789          *
00790          * Different language grammars may need to rearrange the parts.
00791          *
00792          * %1$s => The name of the directory that contains the problematic
00793          *         component; it may have zero, one or more slashes in
00794          *         it.  It will include the name of the function call
00795          *         argument, the name of the directory, and the file
00796          *         type "directory".
00797          * %2$s => The name of the offending path component and file
00798          *         type (will never have slashes).  It will be quoted.
00799          * %3$s => the desired file type
00800          */
00801         i18n("in the %s there is a %s, but it should be a %s"),
00802         part1,
00803         part2,
00804         part3
00805     );
00806 }
00807 
00808 
00809 static void
00810 need_dir_write_for_remove_dir_entry(explain_string_buffer_t *sb,
00811     const char *dir_caption, const char *dir_name, int dir_type,
00812     const char *comp_name, int comp_type)
00813 {
00814     explain_string_buffer_t dir_part_sb;
00815     explain_string_buffer_t comp_part_sb;
00816     char dir_part[PATH_MAX * 4 + 100];
00817     char comp_part[PATH_MAX * 4 + 100];
00818 
00819     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00820     explain_buffer_caption_name_type
00821     (
00822         &dir_part_sb,
00823         dir_caption,
00824         dir_name,
00825         dir_type
00826     );
00827     explain_string_buffer_init(&comp_part_sb, comp_part, sizeof(comp_part));
00828     explain_buffer_caption_name_type(&comp_part_sb, 0, comp_name, comp_type);
00829 
00830     explain_string_buffer_printf_gettext
00831     (
00832         sb,
00833         /*
00834          * xgettext: This message is used when the process has
00835          * insufficient permissions to a directory to remove a directory
00836          * entry from it.
00837          *
00838          * %1$s => The name of the offending system call argument, the
00839          *         quoted name of the corresponding directory, and its
00840          *         file type already translated.
00841          * %2$s => The quoted name of the directory component, and its
00842          *         file type already translated.
00843          */
00844         i18n("the process does not have write permission to the %s, this "
00845              "is needed to remove the directory entry for the %s"),
00846         dir_part,
00847         comp_part
00848     );
00849 }
00850 
00851 
00852 static void
00853 explain_sticky_bit_vs_unlink(explain_string_buffer_t *sb,
00854     const explain_have_identity_t *hip, const struct stat *dir_st,
00855     const struct stat *file_st)
00856 {
00857     explain_string_buffer_t proc_part_sb;
00858     explain_string_buffer_t dir_part_sb;
00859     explain_string_buffer_t file_part_sb;
00860     explain_string_buffer_t ftype_sb;
00861     char            proc_part[100];
00862     char            dir_part[100];
00863     char            file_part[100];
00864     char            ftype[100];
00865 
00866     explain_string_buffer_init(&proc_part_sb, proc_part, sizeof(proc_part));
00867     explain_string_buffer_init(&dir_part_sb, dir_part, sizeof(dir_part));
00868     explain_string_buffer_init(&file_part_sb, file_part, sizeof(file_part));
00869     explain_string_buffer_init(&ftype_sb, ftype, sizeof(ftype));
00870 
00871     explain_buffer_uid(&proc_part_sb, hip->uid);
00872     explain_buffer_uid(&dir_part_sb, dir_st->st_uid);
00873     explain_buffer_uid(&file_part_sb, file_st->st_uid);
00874     explain_buffer_file_type_st(&ftype_sb, file_st);
00875 
00876     explain_string_buffer_puts(sb, ", ");
00877     explain_string_buffer_printf_gettext
00878     (
00879         sb,
00880         /*
00881          * %1$s => the kind of UID, either "effective UID" or "real
00882          *         UID", already translated
00883          * %2$s => the process's UID and the corresponding login name,
00884          *         already quoted
00885          * %3$s => the file's UID and the corresponding login name,
00886          *         already quoted
00887          * %4$s => the type of file to be removed (e.g. "regular file"),
00888          *         already translated
00889          * %5$s => the directory's UID and the corresponding login name,
00890          *         already quoted
00891          */
00892         i18n("the directory has the sticky bit (S_ISVTX) set and the "
00893             "process's %s %s is neither the owner UID %s of the %s "
00894             "to be removed, nor the owner UID %s of the directory "
00895             "containing it"),
00896         explain_have_identity_kind_of_uid(hip),
00897         proc_part,
00898         file_part,
00899         ftype,
00900         dir_part
00901     );
00902     explain_buffer_dac_fowner(sb);
00903 }
00904 
00905 
00906 static int
00907 current_directory_confusing(void)
00908 {
00909     char parent_dir[PATH_MAX + 1];
00910     char child_dir[PATH_MAX + 1];
00911 
00912     /*
00913      * If this process' current directory differs from that of the
00914      * parent process' current directory, it means that the user may
00915      * well have a different idea of "the current directory" than this
00916      * process does.
00917      */
00918     if (!explain_getppcwd(parent_dir, sizeof(parent_dir)))
00919         return 1;
00920     if (!getcwd(child_dir, sizeof(child_dir)))
00921         return 1;
00922     return (0 != strcmp(parent_dir, child_dir));
00923 }
00924 
00925 
00926 static int
00927 is_ok_pathname_caption(const char *caption)
00928 {
00929     /* most of them */
00930     if (0 == strcmp(caption, "pathname"))
00931         return 1;
00932     /* rename */
00933     if  (0 == strcmp(caption, "oldpath"))
00934         return 1;
00935     /* rename */
00936     if (0 == strcmp(caption, "newpath"))
00937         return 1;
00938 
00939     /* mount */
00940     if (0 == strcmp(caption, "source"))
00941         return 1;
00942     /* mount */
00943     if (0 == strcmp(caption, "target"))
00944         return 1;
00945 
00946     /* heuristic */
00947     return !strchr(caption, '/');
00948 }
00949 
00950 
00951 int
00952 explain_buffer_errno_path_resolution(explain_string_buffer_t *sb,
00953     int expected_errno, const char *initial_pathname, const char *caption,
00954     const explain_final_t *final_component)
00955 {
00956     char            pathname[PATH_MAX * 2 + 1];
00957     explain_string_buffer_t pathname_buf;
00958     int             number_of_symlinks_followed;
00959     const char      *pp;
00960     char            lookup_directory[PATH_MAX + 1];
00961     explain_string_buffer_t lookup_directory_buf;
00962     char            **symlinks_so_far;
00963     int             symloop_max;
00964     long            path_max;
00965 
00966     /*
00967      * It's easy to pass pathname twice, rather than pathname and
00968      * "pathname", so we do a little checking.  Add to this list if
00969      * something else turns up, but I don't expect any more.
00970      *
00971      * RESIST the temptation to add more, because it actually makes the
00972      * libexplain API inconsistent (at the expense of avoiding lame
00973      * POSIX argument name inconsistencies).
00974      */
00975     assert(is_ok_pathname_caption(caption));
00976 
00977     if (expected_errno == EMLINK)
00978         expected_errno = ELOOP;
00979     symlinks_so_far = 0;
00980     number_of_symlinks_followed = 0;
00981 
00982     /*
00983      * Empty pathname:
00984      * In the original Unix, the empty pathname referred to the current
00985      * directory.  Nowadays POSIX decrees that an empty pathname must
00986      * not be resolved successfully.  Linux returns ENOENT in this case.
00987      *
00988      * FIXME: is there a way pathconf can tell us which semanrics apply?
00989      *        or maybe sysconf?
00990      */
00991     if (!initial_pathname || !*initial_pathname)
00992     {
00993 #ifdef __sun__
00994         initial_pathname = ".";
00995 #else
00996         explain_string_buffer_printf
00997         (
00998             sb,
00999             /*
01000              * xgettext: this explanation is given for paths that are
01001              * the empty string.
01002              *
01003              * %1$s => the name of the relevant system call argument.
01004              */
01005             i18n("POSIX decrees that an empty %s must not be resolved "
01006                 "successfully"),
01007             caption
01008         );
01009         return 0;
01010 #endif
01011     }
01012 
01013     /*
01014      * Deal with some boundary conditions.
01015      * What we want is to always have at least one component.
01016      */
01017     if (!initial_pathname || !*initial_pathname)
01018         initial_pathname = ".";
01019     else if (all_slash(initial_pathname))
01020         initial_pathname = "/.";
01021 
01022     path_max = final_component->path_max;
01023     if (path_max < 0)
01024         path_max = pathconf(initial_pathname, _PC_PATH_MAX);
01025     if (path_max <= 0)
01026         path_max = PATH_MAX;
01027 
01028     if (expected_errno == ENAMETOOLONG)
01029     {
01030         size_t          len;
01031 
01032         len = strlen(initial_pathname);
01033         if (len > (size_t)path_max)
01034         {
01035             explain_string_buffer_printf_gettext
01036             (
01037                 sb,
01038                 /*
01039                  * xgettext: This message is used when a pathname
01040                  * exceeds the maximum (system specific) path name
01041                  * length (in bytes, not characters).
01042                  *
01043                  * %1$s => the name of the offending system call argument
01044                  */
01045                 i18n("%s exceeds the system maximum path length"),
01046                 caption
01047             );
01048             explain_string_buffer_printf
01049             (
01050                 sb,
01051                 " (%ld > %ld)",
01052                 (long)len,
01053                 path_max
01054             );
01055             return 0;
01056         }
01057     }
01058 
01059     explain_string_buffer_init(&pathname_buf, pathname, sizeof(pathname));
01060     if (initial_pathname[0] != '/' && current_directory_confusing())
01061     {
01062         if (getcwd(pathname, sizeof(pathname) - 1))
01063         {
01064             pathname_buf.position = strlen(pathname);
01065             explain_string_buffer_putc(&pathname_buf, '/');
01066         }
01067     }
01068     explain_string_buffer_puts(&pathname_buf, initial_pathname);
01069 
01070     /*
01071      * Trailing slashes
01072      * If a pathname ends in a '/', that forces resolution of the
01073      * preceding component as in Step 2: it has to exist and resolve
01074      * to a directory.  Otherwise a trailing '/' is ignored.  (Or,
01075      * equivalently, a pathname with a trailing '/' is equivalent to the
01076      * pathname obtained by appending '.' to it.)
01077      */
01078     if (pathname[pathname_buf.position - 1] == '/')
01079         explain_string_buffer_putc(&pathname_buf, '.');
01080 
01081     /*
01082      * Try to get the system's idea of the loop maximum.
01083      */
01084     symloop_max = explain_symloopmax();
01085 
01086     symlinks_so_far = malloc(2 * symloop_max * sizeof(char *));
01087     if
01088     (
01089         !symlinks_so_far
01090     &&
01091         (expected_errno == ELOOP || expected_errno == EMLINK)
01092     )
01093         return -1;
01094 
01095     pp = pathname;
01096 
01097     /*
01098      * Set the current lookup directory to the starting lookup directory.
01099      */
01100     explain_string_buffer_init
01101     (
01102         &lookup_directory_buf,
01103         lookup_directory,
01104         sizeof(lookup_directory)
01105     );
01106     explain_string_buffer_puts
01107     (
01108         &lookup_directory_buf,
01109         (*pp == '/' ? "/" : ".")
01110     );
01111     while (*pp == '/')
01112         ++pp;
01113 
01114     /*
01115      * Walk along the path
01116      */
01117     for (;;)
01118     {
01119         char            component[PATH_MAX + 1]; /* deliberately not NAME_MAX */
01120         explain_string_buffer_t component_buf;
01121         char            intermediate_path[PATH_MAX + 1];
01122         explain_string_buffer_t intermediate_path_buf;
01123         int             final;
01124         int             lookup_directory_writable;
01125         struct stat     lookup_directory_st;
01126         struct stat     intermediate_path_st;
01127 
01128         /*
01129          * Check that the lookup directory will play ball.
01130          */
01131         if (lstat(lookup_directory, &lookup_directory_st) != 0)
01132         {
01133             int lookup_directory_st_errnum = errno;
01134             if (lookup_directory_st_errnum != ENOENT)
01135                 goto return_minus_1;
01136             directory_does_not_exist(sb, caption, lookup_directory);
01137             return_0:
01138             if (symlinks_so_far)
01139             {
01140                 int             j;
01141 
01142                 for (j = 0; j < number_of_symlinks_followed; ++j)
01143                     free(symlinks_so_far[j]);
01144                 free(symlinks_so_far);
01145             }
01146             return 0;
01147         }
01148 
01149         /*
01150          * The lookup directory is never a symbolic link.
01151          * We take care to ensure it, see below.
01152          */
01153         assert(!S_ISLNK(lookup_directory_st.st_mode));
01154 
01155         if (!S_ISDIR(lookup_directory_st.st_mode))
01156         {
01157             /*
01158              * If the lookup_directory is found, but is not a directory,
01159              * an ENOTDIR error is returned ("Not a directory").
01160              */
01161             not_a_directory
01162             (
01163                 sb,
01164                 caption,
01165                 lookup_directory,
01166                 &lookup_directory_st
01167             );
01168             goto return_0;
01169         }
01170 
01171         /*
01172          * If the process does not have search permission on the current
01173          * lookup directory, an EACCES error is returned ("Permission
01174          * denied").
01175          */
01176         if
01177         (
01178             !explain_have_search_permission
01179             (
01180                 &lookup_directory_st,
01181                 &final_component->id
01182             )
01183         )
01184         {
01185             does_not_have_search_permission1
01186             (
01187                 sb,
01188                 caption,
01189                 lookup_directory,
01190                 &lookup_directory_st,
01191                 &final_component->id
01192             );
01193             goto return_0;
01194         }
01195 
01196         lookup_directory_writable =
01197             explain_have_write_permission
01198             (
01199                 &lookup_directory_st,
01200                 &final_component->id
01201             );
01202 
01203         /*
01204          * Extract the next path component.
01205          * A path component is a substring delimited by '/' characters.
01206          */
01207         explain_string_buffer_init
01208         (
01209             &component_buf,
01210             component,
01211             sizeof(component)
01212         );
01213         for (;;)
01214         {
01215             unsigned char c = *pp++;
01216             switch (c)
01217             {
01218             default:
01219                 explain_string_buffer_putc(&component_buf, c);
01220                 continue;
01221 
01222             case '\0':
01223                 --pp;
01224                 break;
01225 
01226             case '/':
01227                 break;
01228             }
01229             break;
01230         }
01231         while (*pp == '/')
01232             ++pp;
01233         final = !*pp;
01234 
01235         /*
01236          * Check the length of the component
01237          */
01238         if (expected_errno == ENAMETOOLONG)
01239         {
01240             long            no_trunc;
01241             int             silent_truncate;
01242             long            name_max;
01243 
01244             /*
01245              * Components can only be too long if the file system
01246              * they are on does not silently truncate over-long path
01247              * components.
01248              */
01249             no_trunc = pathconf(lookup_directory, _PC_NO_TRUNC);
01250             silent_truncate = (no_trunc == 0);
01251 
01252             name_max = pathconf(lookup_directory, _PC_NAME_MAX);
01253             if (name_max <= 0)
01254                 name_max = NAME_MAX;
01255             if (!silent_truncate && component_buf.position > (size_t)name_max)
01256             {
01257                 name_too_long
01258                 (
01259                     sb,
01260                     caption,
01261                     component,
01262                     (long)component_buf.position,
01263                     name_max
01264                 );
01265                 goto return_0;
01266             }
01267             if (component_buf.position > (size_t)name_max)
01268             {
01269                 explain_string_buffer_truncate(&component_buf, name_max);
01270             }
01271         }
01272         else
01273         {
01274             /*
01275              * Silently truncate over-long path components.
01276              */
01277             long name_max = pathconf(lookup_directory, _PC_NAME_MAX);
01278             if (name_max <= 0)
01279                 name_max = NAME_MAX;
01280             if (component_buf.position > (size_t)name_max)
01281             {
01282                 explain_string_buffer_truncate(&component_buf, name_max);
01283             }
01284         }
01285 
01286         /*
01287          * Build the intermediate path by joining the lookup_directory
01288          * and the component.
01289          */
01290         explain_string_buffer_init
01291         (
01292             &intermediate_path_buf,
01293             intermediate_path,
01294             sizeof(intermediate_path)
01295         );
01296         explain_string_buffer_puts(&intermediate_path_buf, lookup_directory);
01297         explain_string_buffer_path_join(&intermediate_path_buf, component);
01298 
01299         if (lstat(intermediate_path, &intermediate_path_st) < 0)
01300         {
01301             int             intermediate_path_st_errnum;
01302 
01303             intermediate_path_st_errnum = errno;
01304             if (!final)
01305             {
01306                 if (intermediate_path_st_errnum == ENOENT)
01307                 {
01308                     no_such_directory_entry
01309                     (
01310                         sb,
01311                         component,
01312                         S_IFDIR,
01313                         caption,
01314                         lookup_directory,
01315                         lookup_directory_st.st_mode
01316                     );
01317 
01318                     /*
01319                      * If it was a typo, see if we can find something similar.
01320                      */
01321                     look_for_similar(sb, lookup_directory, component);
01322                     goto return_0;
01323                 }
01324 
01325                 /*
01326                  * intermediate path of non-final component returned
01327                  * unexpected error to lstat (i.e. not ENOENT), bail out
01328                  */
01329                 goto return_minus_1;
01330             }
01331 
01332             /*
01333              * At this point, we know it is a final component.
01334              */
01335             if (final_component->must_not_exist)
01336             {
01337                 if (intermediate_path_st_errnum == ENOENT)
01338                 {
01339                     if (!lookup_directory_writable)
01340                     {
01341                         /* EACCES */
01342                         does_not_have_new_directory_entry_permission
01343                         (
01344                             sb,
01345                             caption,
01346                             lookup_directory,
01347                             &lookup_directory_st,
01348                             component,
01349                             final_component->st_mode,
01350                             &final_component->id
01351                         );
01352                         goto return_0;
01353                     }
01354 
01355                     /*
01356                      * yay,
01357                      * but we were looking for an error
01358                      * and didn't find it
01359                      */
01360                     goto return_minus_1;
01361                 }
01362 
01363                 /*
01364                  * The final component is not meant to exist, but the
01365                  * final component gave an unexpected error to lstat
01366                  * (i.e. not ENOENT), bail out
01367                  */
01368                 goto return_minus_1;
01369             }
01370             if (final_component->must_exist)
01371             {
01372                 if (intermediate_path_st_errnum != ENOENT)
01373                 {
01374                     /*
01375                      * The final component is meant to exist, but the
01376                      * final component gave an unexpected error to
01377                      * lstat (i.e. not success and not ENOENT), bail out
01378                      */
01379                     goto return_minus_1;
01380                 }
01381 
01382                 no_such_directory_entry
01383                 (
01384                     sb,
01385                     component,
01386                     final_component->st_mode,
01387                     caption,
01388                     lookup_directory,
01389                     lookup_directory_st.st_mode
01390                 );
01391 
01392                 /*
01393                  * If it was a typo, see if we can find something similar.
01394                  */
01395                 look_for_similar(sb, lookup_directory, component);
01396 
01397                 goto return_0;
01398             }
01399 
01400             /*
01401              * Creating a new file requires write permission in the
01402              * containing directory.
01403              */
01404             if
01405             (
01406                 (expected_errno == EACCES || expected_errno == EPERM)
01407             &&
01408                 intermediate_path_st_errnum == ENOENT
01409             &&
01410                 final_component->want_to_create
01411             &&
01412                 !lookup_directory_writable
01413             )
01414             {
01415                 does_not_have_new_directory_entry_permission
01416                 (
01417                     sb,
01418                     caption,
01419                     lookup_directory,
01420                     &lookup_directory_st,
01421                     component,
01422                     final_component->st_mode,
01423                     &final_component->id
01424                 );
01425 
01426                 /*
01427                  * What if they meant to overwrite an existing file?
01428                  * That would not have needed write permission on the
01429                  * containing directory.
01430                  */
01431                 look_for_similar(sb, lookup_directory, component);
01432                 goto return_0;
01433             }
01434 
01435             /*
01436              * It's OK if the final component path doesn't exist,
01437              * but we were looking for an error and didn't find one.
01438              */
01439             goto return_minus_1;
01440         }
01441 
01442         /*
01443          * At this point, we know that the intermediate path exists.
01444          */
01445         if
01446         (
01447             S_ISLNK(intermediate_path_st.st_mode)
01448         &&
01449             (!final || final_component->follow_symlink)
01450         )
01451         {
01452             int             n;
01453             char            rlb[PATH_MAX + 1];
01454 
01455             /*
01456              * Have we read this symlink before?
01457              */
01458             if (symlinks_so_far)
01459             {
01460                 int             j;
01461 
01462                 for (j = 0; j < number_of_symlinks_followed; ++j)
01463                 {
01464                     if (0 == strcmp(symlinks_so_far[j], intermediate_path))
01465                     {
01466                         char            qs[PATH_MAX * 2 + 1];
01467                         explain_string_buffer_t qs_sb;
01468 
01469                         explain_string_buffer_init(&qs_sb, qs, sizeof(qs));
01470                         explain_string_buffer_puts_quoted
01471                         (
01472                             &qs_sb,
01473                             intermediate_path
01474                         );
01475                         explain_string_buffer_printf_gettext
01476                         (
01477                             sb,
01478                             /*
01479                              * xgettext: This message is used when a
01480                              * symbolic link loop has been detected,
01481                              * usually as a result of an ELOOP error.
01482                              *
01483                              * %1$s => The name of the offending system
01484                              *         call argument
01485                              * %2$s => The path of the first symlink in
01486                              *         the loop, already quoted.
01487                              */
01488                             i18n("a symbolic link loop was encountered in %s, "
01489                                 "starting at %s"),
01490                             caption,
01491                             qs
01492                         );
01493                         goto return_0;
01494                     }
01495                 }
01496             }
01497 
01498             /*
01499              * Follow the symbolic link, that way we can give the actual
01500              * path in our error messages.
01501              */
01502             n = readlink(intermediate_path, rlb, sizeof(rlb) - 1);
01503             if (n >= 0)
01504             {
01505                 char            new_pathname[PATH_MAX + 1];
01506                 explain_string_buffer_t new_pathname_buf;
01507 
01508                 if (symlinks_so_far)
01509                 {
01510                     size_t          len;
01511                     char            *p;
01512 
01513                     len = strlen(intermediate_path) + 1;
01514                     p = malloc(len);
01515                     if (!p)
01516                     {
01517                         int             j;
01518 
01519                         for (j = 0; j < number_of_symlinks_followed; ++j)
01520                             free(symlinks_so_far[j]);
01521                         free(symlinks_so_far);
01522                         symlinks_so_far = 0;
01523                         if (expected_errno == ELOOP || expected_errno == EMLINK)
01524                             goto return_minus_1;
01525                     }
01526                     else
01527                     {
01528                         memcpy(p, intermediate_path, len);
01529                         symlinks_so_far[number_of_symlinks_followed] = p;
01530                     }
01531                 }
01532 
01533                 if (n == 0)
01534                 {
01535                     rlb[0] = '.';
01536                     n = 1;
01537                 }
01538                 rlb[n] = '\0';
01539 
01540                 explain_string_buffer_init
01541                 (
01542                     &new_pathname_buf,
01543                     new_pathname,
01544                     sizeof(new_pathname)
01545                 );
01546                 explain_string_buffer_puts(&new_pathname_buf, rlb);
01547                 explain_string_buffer_path_join(&new_pathname_buf, pp);
01548 
01549                 explain_string_buffer_copy(&pathname_buf, &new_pathname_buf);
01550 
01551                 /*
01552                  * Check for dangling symbolic links
01553                  */
01554                 explain_string_buffer_init
01555                 (
01556                     &intermediate_path_buf,
01557                     intermediate_path,
01558                     sizeof(intermediate_path)
01559                 );
01560                 if (rlb[0] == '/')
01561                 {
01562                     explain_string_buffer_puts(&intermediate_path_buf, rlb);
01563                 }
01564                 else
01565                 {
01566                     explain_string_buffer_puts
01567                     (
01568                         &intermediate_path_buf,
01569                         lookup_directory
01570                     );
01571                     explain_string_buffer_path_join
01572                     (
01573                         &intermediate_path_buf,
01574                         rlb
01575                     );
01576                 }
01577                 if
01578                 (
01579                     lstat(intermediate_path, &intermediate_path_st) < 0
01580                 &&
01581                     errno == ENOENT
01582                 )
01583                 {
01584                     dangling_symbolic_link
01585                     (
01586                         sb,
01587                         component,
01588                         S_IFLNK,
01589                         caption,
01590                         lookup_directory,
01591                         lookup_directory_st.st_mode,
01592                         rlb
01593                     );
01594                     goto return_0;
01595                 }
01596 
01597                 if (rlb[0] == '/')
01598                 {
01599                     explain_string_buffer_rewind(&lookup_directory_buf);
01600                     explain_string_buffer_putc(&lookup_directory_buf, '/');
01601                 }
01602                 ++number_of_symlinks_followed;
01603                 if (number_of_symlinks_followed >= symloop_max)
01604                 {
01605                     explain_string_buffer_printf_gettext
01606                     (
01607                         sb,
01608                         /*
01609                          * xgettext: This message is used when too
01610                          * may links (ELOOP or EMLINK) are seen when
01611                          * resolving a path.
01612                          *
01613                          * It may ioptionally be followed by the limit,
01614                          * in parentheses, so sentence structure that
01615                          * works that way would be a plus.
01616                          *
01617                          * %1$s => The name of the offending system call
01618                          *         argument.
01619                          */
01620                         i18n("too many symbolic links were encountered in %s"),
01621                         caption
01622                     );
01623                     if (explain_option_dialect_specific())
01624                     {
01625                         explain_string_buffer_printf
01626                         (
01627                             sb,
01628                             " (%d)",
01629                             number_of_symlinks_followed
01630                         );
01631                     }
01632                     goto return_0;
01633                 }
01634                 pp = pathname;
01635                 while (*pp == '/')
01636                     ++pp;
01637                 continue;
01638             }
01639         }
01640 
01641         if (!final)
01642         {
01643             /*
01644              * check that intermediate_path is, in fact, a directory
01645              */
01646             if (!S_ISDIR(intermediate_path_st.st_mode))
01647             {
01648                 /* ENOTDIR */
01649                 not_a_subdirectory
01650                 (
01651                     sb,
01652                     component,
01653                     intermediate_path_st.st_mode,
01654                     caption,
01655                     lookup_directory,
01656                     lookup_directory_st.st_mode
01657                 );
01658                 return 0;
01659             }
01660 
01661             explain_string_buffer_copy
01662             (
01663                 &lookup_directory_buf,
01664                 &intermediate_path_buf
01665             );
01666             continue;
01667         }
01668 
01669         /*
01670          * At this point, we know that intermediate_path is the final
01671          * path, and we know it *does* exist.
01672          */
01673         if (final_component->must_not_exist)
01674         {
01675             explain_buffer_eexist5
01676             (
01677                 sb,
01678                 component,
01679                 intermediate_path_st.st_mode,
01680                 lookup_directory,
01681                 lookup_directory_st.st_mode
01682             );
01683             goto return_0;
01684         }
01685 
01686         if
01687         (
01688             final_component->must_be_a_st_mode
01689         &&
01690             (intermediate_path_st.st_mode & S_IFMT) != final_component->st_mode
01691         )
01692         {
01693             wrong_file_type
01694             (
01695                 sb,
01696                 caption,
01697                 lookup_directory,
01698                 lookup_directory_st.st_mode,
01699                 component,
01700                 intermediate_path_st.st_mode,
01701                 final_component->st_mode
01702             );
01703             goto return_0;
01704         }
01705 
01706         if
01707         (
01708             (expected_errno == EACCES || expected_errno == EPERM)
01709         &&
01710             final_component->want_to_modify_inode
01711         &&
01712             !explain_have_inode_permission
01713             (
01714                 &intermediate_path_st,
01715                 &final_component->id
01716             )
01717         )
01718         {
01719             explain_buffer_does_not_have_inode_modify_permission
01720             (
01721                 sb,
01722                 component,
01723                 &intermediate_path_st,
01724                 caption,
01725                 lookup_directory,
01726                 &lookup_directory_st,
01727                 &final_component->id
01728             );
01729             goto return_0;
01730         }
01731 
01732         if
01733         (
01734             (expected_errno == EACCES || expected_errno == EPERM)
01735         &&
01736             final_component->want_to_unlink
01737         &&
01738             !lookup_directory_writable
01739         )
01740         {
01741             if ((lookup_directory_st.st_mode & S_ISVTX) == 0)
01742             {
01743                 /*
01744                  * No sticky bit set, therefore only need write permissions on
01745                  * the lookup directory.
01746                  */
01747                 need_dir_write_for_remove_dir_entry
01748                 (
01749                     sb,
01750                     caption,
01751                     lookup_directory,
01752                     lookup_directory_st.st_mode,
01753                     component,
01754                     intermediate_path_st.st_mode
01755                 );
01756                 goto return_0;
01757             }
01758             else
01759             {
01760                 int             uid;
01761 
01762                 uid = final_component->id.uid;
01763                 if
01764                 (
01765                     uid != (int)intermediate_path_st.st_uid
01766                 &&
01767                     uid != (int)lookup_directory_st.st_uid
01768                 &&
01769                     !explain_capability_fowner()
01770                 )
01771                 {
01772                     need_dir_write_for_remove_dir_entry
01773                     (
01774                         sb,
01775                         caption,
01776                         lookup_directory,
01777                         lookup_directory_st.st_mode,
01778                         component,
01779                         intermediate_path_st.st_mode
01780                     );
01781                     explain_sticky_bit_vs_unlink
01782                     (
01783                         sb,
01784                         &final_component->id,
01785                         &lookup_directory_st,
01786                         &intermediate_path_st
01787                     );
01788                     goto return_0;
01789                 }
01790             }
01791         }
01792 
01793         if (expected_errno == EACCES)
01794         {
01795             if
01796             (
01797                 final_component->want_to_read
01798             &&
01799                 !explain_have_read_permission
01800                 (
01801                     &intermediate_path_st,
01802                     &final_component->id
01803                 )
01804             )
01805             {
01806                 does_not_have_read_permission
01807                 (
01808                     sb,
01809                     component,
01810                     &intermediate_path_st,
01811                     caption,
01812                     lookup_directory,
01813                     &lookup_directory_st,
01814                     &final_component->id
01815                 );
01816                 goto return_0;
01817             }
01818 
01819             if
01820             (
01821                 final_component->want_to_write
01822             &&
01823                 !explain_have_write_permission
01824                 (
01825                     &intermediate_path_st,
01826                     &final_component->id
01827                 )
01828             )
01829             {
01830                 does_not_have_write_permission
01831                 (
01832                     sb,
01833                     component,
01834                     &intermediate_path_st,
01835                     caption,
01836                     lookup_directory,
01837                     &lookup_directory_st,
01838                     &final_component->id
01839                 );
01840                 goto return_0;
01841             }
01842 
01843             if (final_component->want_to_execute)
01844             {
01845                 if
01846                 (
01847                     explain_have_execute_permission
01848                     (
01849                         &intermediate_path_st,
01850                         &final_component->id
01851                     )
01852                 )
01853                 {
01854                     if
01855                     (
01856                         explain_mount_point_noexec(intermediate_path)
01857                     &&
01858                         !explain_capability_dac_override()
01859                     )
01860                     {
01861                         explain_buffer_gettext
01862                         (
01863                             sb,
01864                             /*
01865                              * xgettext: This message is used when the process
01866                              * attempts to execute a regular file which would
01867                              * otherwise be executable, except that it resides
01868                              * on a file system that is mounted with the
01869                              * "noexec" option.
01870                              */
01871                             i18n("the executable is on a file system that is "
01872                             "mounted with the \"noexec\" option")
01873                         );
01874                         explain_buffer_mount_point(sb, intermediate_path);
01875                         goto return_0;
01876                     }
01877 
01878                     if
01879                     (
01880                         (intermediate_path_st.st_mode & (S_ISUID | S_ISGID))
01881                     &&
01882                         explain_mount_point_nosuid(intermediate_path)
01883                     &&
01884                         !explain_capability_dac_override()
01885                     )
01886                     {
01887                         explain_buffer_gettext
01888                         (
01889                             sb,
01890                             /*
01891                              * xgettext: This message is used when the process
01892                              * attempts to execute a regular file which would
01893                              * otherwise be executable, except that it has the
01894                              * set-UID (S_ISUID) or set-GID (S_ISGID) bit set,
01895                              * and it resides on a file system that is mounted
01896                              * with the "nosuid" option.
01897                              */
01898                             i18n("the executable is on a file system that is "
01899                             "mounted with the \"nosuid\" option")
01900                         );
01901                         explain_buffer_mount_point(sb, intermediate_path);
01902                         goto return_0;
01903                     }
01904 
01905                     /*
01906                      * If it is a #! script, check the command interpreter.
01907                      * (But avoid command interpreter infinite loops.)
01908                      */
01909                     if (final_component->follow_interpreter)
01910                     {
01911                         if (!command_interpreter_broken(sb, intermediate_path))
01912                             goto return_0;
01913                     }
01914                     else
01915                     {
01916                         if (!hash_bang(sb, intermediate_path))
01917                             goto return_0;
01918                     }
01919                 }
01920                 else
01921                 {
01922                     if (!S_ISREG(intermediate_path_st.st_mode))
01923                     {
01924                         not_possible_to_execute
01925                         (
01926                             sb,
01927                             caption,
01928                             component,
01929                             intermediate_path_st.st_mode
01930                         );
01931                         goto return_0;
01932                     }
01933 
01934                     does_not_have_execute_permission
01935                     (
01936                         sb,
01937                         component,
01938                         &intermediate_path_st,
01939                         caption,
01940                         lookup_directory,
01941                         &lookup_directory_st,
01942                         &final_component->id
01943                     );
01944                     goto return_0;
01945                 }
01946             }
01947 
01948             if
01949             (
01950                 final_component->want_to_search
01951             &&
01952                 !explain_have_search_permission
01953                 (
01954                     &intermediate_path_st,
01955                     &final_component->id
01956                 )
01957             )
01958             {
01959                 does_not_have_search_permission
01960                 (
01961                     sb,
01962                     component,
01963                     &intermediate_path_st,
01964                     caption,
01965                     lookup_directory,
01966                     &lookup_directory_st,
01967                     &final_component->id
01968                 );
01969                 goto return_0;
01970             }
01971         }
01972 
01973         /*
01974          * No error, yay!  Except that we were looking for an error, and
01975          * did not find one.
01976          */
01977         return_minus_1:
01978         if (symlinks_so_far)
01979         {
01980             int             k;
01981 
01982             for (k = 0; k < number_of_symlinks_followed; ++k)
01983                 free(symlinks_so_far[k]);
01984             free(symlinks_so_far);
01985         }
01986         return -1;
01987     }
01988 }
01989 
01990 
01991 void
01992 explain_final_init(explain_final_t *p)
01993 {
01994     p->want_to_read = 0;
01995     p->want_to_write = 0;
01996     p->want_to_search = 0;
01997     p->want_to_execute = 0;
01998     p->want_to_create = 0;
01999     p->want_to_modify_inode = 0;
02000     p->want_to_unlink = 0;
02001     p->must_exist = 1;
02002     p->must_not_exist = 0;
02003     p->must_be_a_st_mode = 0;
02004     p->follow_symlink = 1;
02005     p->follow_interpreter = 1;
02006     p->st_mode = S_IFREG;
02007     explain_have_identity_init(&p->id);
02008     p->path_max = -1;
02009 }
02010 
02011 
02012 /* vim: set ts=8 sw=4 et : */