libexplain  1.4.D001
libexplain/buffer/mount_point.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2010, 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/limits.h> /* for PATH_MAX on Solaris */
00021 #include <libexplain/ac/mntent.h>
00022 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */
00023 #include <libexplain/ac/sys/stat.h>
00024 #include <libexplain/ac/sys/statvfs.h>
00025 #include <libexplain/ac/sys/vfs.h>
00026 
00027 #include <libexplain/buffer/mount_point.h>
00028 #include <libexplain/dirname.h>
00029 
00030 
00031 int
00032 explain_buffer_mount_point_dev(explain_string_buffer_t *sb, dev_t dev)
00033 {
00034     FILE            *fp;
00035 
00036     fp = setmntent(MOUNTED, "r");
00037     if (!fp)
00038         return -1;
00039     for (;;)
00040     {
00041         const char      *dir;
00042         struct stat     st2;
00043 #if GETMNTENT_NARGS == 2
00044         struct mnttab   mdata;
00045 
00046         if (getmntent(fp, &mdata) != 0)
00047             break;
00048         dir = mdata.mnt_mountp;
00049 #else
00050         struct mntent   *mnt;
00051 
00052         /* FIXME: use getmntent_r if available */
00053         mnt = getmntent(fp);
00054         if (!mnt)
00055             break;
00056         dir = mnt->mnt_dir;
00057 #endif
00058         if (lstat(dir, &st2) == 0)
00059         {
00060             if (dev == st2.st_dev)
00061             {
00062                 struct statvfs  f;
00063 
00064                 /*
00065                  * Insert the name of the mount point.
00066                  */
00067                 explain_string_buffer_puts(sb, " (");
00068                 explain_string_buffer_puts_quoted(sb, dir);
00069 
00070                 /*
00071                  * If possible, insert the percentage used of the file
00072                  * system, similar to how df(1) has a %used column.
00073                  */
00074                 if (statvfs(dir, &f) == 0)
00075                 {
00076                     long            reserved;
00077                     long            blocks;
00078                     long            used;
00079 
00080                     reserved = f.f_bfree - f.f_bavail;
00081                     if (reserved < 0)
00082                         reserved = 0;
00083                     blocks = f.f_blocks - reserved;
00084                     used = blocks - f.f_bavail;
00085                     if (blocks > 0 && used >= 0 && used <= (long)f.f_blocks)
00086                     {
00087                         explain_string_buffer_printf
00088                         (
00089                             sb,
00090                             ", %d%% full",
00091                             (int)(0.5 + (100. * used / blocks))
00092                         );
00093                     }
00094                 }
00095                 explain_string_buffer_putc(sb, ')');
00096 
00097                 endmntent(fp);
00098                 return 0;
00099             }
00100         }
00101     }
00102     endmntent(fp);
00103     return -1;
00104 }
00105 
00106 
00107 int
00108 explain_buffer_mount_point_stat(explain_string_buffer_t *sb,
00109     const struct stat *st1)
00110 {
00111     return explain_buffer_mount_point_dev(sb, st1->st_dev);
00112 }
00113 
00114 
00115 int
00116 explain_buffer_mount_point_fd(explain_string_buffer_t *sb, int fildes)
00117 {
00118     struct stat     st;
00119 
00120     if (fstat(fildes, &st) < 0)
00121         return -1;
00122     return explain_buffer_mount_point_stat(sb, &st);
00123 }
00124 
00125 
00126 int
00127 explain_buffer_mount_point(explain_string_buffer_t *sb, const char *path)
00128 {
00129     struct stat     st;
00130 
00131     if (stat(path, &st) < 0)
00132         return -1;
00133     return explain_buffer_mount_point_stat(sb, &st);
00134 }
00135 
00136 
00137 int
00138 explain_buffer_mount_point_dirname(explain_string_buffer_t *sb,
00139     const char *path)
00140 {
00141     char            dir[PATH_MAX + 1];
00142 
00143     explain_dirname(dir, path, sizeof(dir));
00144     return explain_buffer_mount_point(sb, dir);
00145 }
00146 
00147 
00148 static int
00149 explain_mount_point_dev_option(int st_dev, const char *option)
00150 {
00151     FILE            *fp;
00152 
00153     fp = setmntent(MOUNTED, "r");
00154     if (!fp)
00155         return 0;
00156     for (;;)
00157     {
00158         const char      *dir;
00159         struct stat     st2;
00160 #if GETMNTENT_NARGS == 2
00161         struct mnttab   mdata;
00162         struct mnttab   *mnt;
00163 
00164         if (getmntent(fp, &mdata) != 0)
00165             break;
00166         mnt = &mdata;
00167         dir = mnt->mnt_mountp;
00168 #else
00169         struct mntent   *mnt;
00170 
00171         /* FIXME: use getmntent_r if available */
00172         mnt = getmntent(fp);
00173         if (!mnt)
00174             break;
00175         dir = mnt->mnt_dir;
00176 #endif
00177         if (stat(dir, &st2) == 0)
00178         {
00179             if (st_dev == (int)st2.st_dev)
00180             {
00181                 int             result;
00182 
00183                 /*
00184                  * Found the mount point.
00185                  *
00186                  * (For linux this is "probably found the right mount
00187                  * point", because linux allows the same block special
00188                  * device to be mounted at more than one place, and they
00189                  * could have different options for different mount
00190                  * points.)
00191                  *
00192                  * We have to cast away const-ness because Solaris is stupid.
00193                  */
00194                 result = !!hasmntopt(mnt, (char *)option);
00195                 endmntent(fp);
00196                 return result;
00197             }
00198         }
00199     }
00200     endmntent(fp);
00201     return 0;
00202 }
00203 
00204 
00205 static int
00206 explain_mount_point_stat_option(const struct stat *st, const char *option)
00207 {
00208     return explain_mount_point_dev_option(st->st_dev, option);
00209 }
00210 
00211 
00212 static int
00213 explain_mount_point_option(const char *pathname, const char *option)
00214 {
00215     struct stat     st;
00216 
00217     if (stat(pathname, &st) < 0)
00218         return 0;
00219     return explain_mount_point_stat_option(&st, option);
00220 }
00221 
00222 
00223 int
00224 explain_mount_point_noexec(const char *pathname)
00225 {
00226     return explain_mount_point_option(pathname, "noexec");
00227 }
00228 
00229 
00230 int
00231 explain_mount_point_nosuid(const char *pathname)
00232 {
00233     return explain_mount_point_option(pathname, "nosuid");
00234 }
00235 
00236 
00237 int
00238 explain_mount_point_nodev(const struct stat *st)
00239 {
00240     return explain_mount_point_stat_option(st, "nodev");
00241 }
00242 
00243 
00244 /* vim: set ts=8 sw=4 et : */