libexplain
1.4.D001
|
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 : */