libexplain  1.4.D001
libexplain/program_name.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
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at 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/limits.h> /* for PATH_MAX except Solaris */
00021 #include <libexplain/ac/stdlib.h>
00022 #include <libexplain/ac/string.h>
00023 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */
00024 
00025 #include <libexplain/fileinfo.h>
00026 #include <libexplain/name_max.h>
00027 #include <libexplain/program_name.h>
00028 
00029 
00030 static char progname[NAME_MAX + 1];
00031 
00032 
00033 static void
00034 explain_program_name_set_real(const char *name)
00035 {
00036     const char      *cp;
00037 
00038     if (!name)
00039         name = "";
00040     progname[0] = '\0';
00041     if (!name)
00042         return;
00043 
00044     cp = name;
00045     for (;;)
00046     {
00047         char            *pnp;
00048 
00049         if (*cp == '/')
00050         {
00051             /*
00052              * Weird but true: some Unix implementations allow trailing
00053              * slahses on command names.  Ugh.  Not POSIX conforming, either.
00054              */
00055             ++cp;
00056             continue;
00057         }
00058         if (*cp == '\0')
00059             break;
00060 
00061         /*
00062          * GNU Libtool makes intermediate binaries with "lt-" prefixes,
00063          * ignore them when we see them.
00064          */
00065         if (0 == memcmp(cp, "lt-", 3))
00066             cp += 3;
00067 
00068         pnp = progname;
00069         for (;;)
00070         {
00071             if (pnp < progname + sizeof(progname) - 1)
00072                 *pnp++ = *cp;
00073             ++cp;
00074             if (*cp == '\0' || *cp == '/')
00075                 break;
00076         }
00077         *pnp = '\0';
00078     }
00079 }
00080 
00081 
00082 const char *
00083 explain_program_name_get(void)
00084 {
00085     /*
00086      * Use the cached result, if possible.
00087      */
00088     if (progname[0])
00089         return progname;
00090 
00091     /*
00092      * See if /proc can help us.
00093      */
00094     {
00095         char            path[PATH_MAX + 1];
00096 
00097         if (explain_fileinfo_self_exe(path, sizeof(path)))
00098         {
00099             explain_program_name_set_real(path);
00100             if (progname[0])
00101                 return progname;
00102         }
00103     }
00104 
00105     /*
00106      * bash(1) sets the "_" environment variable,
00107      * use that if available.
00108      */
00109     {
00110         const char      *path;
00111 
00112         path = getenv("_");
00113         if (path && *path)
00114         {
00115             explain_program_name_set_real(path);
00116             if (progname[0])
00117                 return progname;
00118         }
00119     }
00120 
00121     /*
00122      * Sorry, can't help you.
00123      */
00124     return "";
00125 }
00126 
00127 
00128 void
00129 explain_program_name_set(const char *name)
00130 {
00131     explain_program_name_set_real(name);
00132     if (!progname[0])
00133         explain_program_name_assemble(0);
00134 }
00135 
00136 
00137 /* vim: set ts=8 sw=4 et : */