00001
00005 #include "system.h"
00006 #include <rpmio.h>
00007 #include <rpmlog.h>
00008 #include <rpmmacro.h>
00009
00010 #include "fs.h"
00011
00012 #include "debug.h"
00013
00014
00015
00016 struct fsinfo {
00017
00018 const char * mntPoint;
00019 dev_t dev;
00020 int rdonly;
00021 };
00022
00023
00024
00025 static struct fsinfo * filesystems = NULL;
00026
00027
00028 static const char ** fsnames = NULL;
00029
00030 static int numFilesystems = 0;
00031
00032 void rpmFreeFilesystems(void)
00033
00034
00035 {
00036 int i;
00037
00038 if (filesystems)
00039 for (i = 0; i < numFilesystems; i++)
00040 filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
00041
00042 filesystems = _free(filesystems);
00043 fsnames = _free(fsnames);
00044 numFilesystems = 0;
00045 }
00046
00047 #if defined(HAVE_MNTCTL)
00048
00049
00050
00051 #include <sys/mntctl.h>
00052 #include <sys/vmount.h>
00053
00054
00055
00056
00057
00058 int mntctl(int command, int size, char *buffer);
00059
00065 static int getFilesystemList(void)
00066
00067 {
00068 int size;
00069 void * buf;
00070 struct vmount * vm;
00071 struct stat sb;
00072 int rdonly = 0;
00073 int num;
00074 int fsnameLength;
00075 int i;
00076
00077 num = mntctl(MCTL_QUERY, sizeof(size), (char *) &size);
00078 if (num < 0) {
00079 rpmlog(RPMLOG_ERR, _("mntctl() failed to return size: %s\n"),
00080 strerror(errno));
00081 return 1;
00082 }
00083
00084
00085
00086
00087
00088
00089 size *= 2;
00090
00091 buf = alloca(size);
00092 num = mntctl(MCTL_QUERY, size, buf);
00093 if ( num <= 0 ) {
00094 rpmlog(RPMLOG_ERR, _("mntctl() failed to return mount points: %s\n"),
00095 strerror(errno));
00096 return 1;
00097 }
00098
00099 numFilesystems = num;
00100
00101 filesystems = xcalloc((numFilesystems + 1), sizeof(*filesystems));
00102 fsnames = xcalloc((numFilesystems + 1), sizeof(char *));
00103
00104 for (vm = buf, i = 0; i < num; i++) {
00105 char *fsn;
00106 fsnameLength = vm->vmt_data[VMT_STUB].vmt_size;
00107 fsn = xmalloc(fsnameLength + 1);
00108 strncpy(fsn, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
00109 fsnameLength);
00110
00111 filesystems[i].mntPoint = fsnames[i] = fsn;
00112
00113 if (stat(filesystems[i].mntPoint, &sb)) {
00114 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), fsnames[i],
00115 strerror(errno));
00116
00117 rpmFreeFilesystems();
00118 return 1;
00119 }
00120
00121 filesystems[i].dev = sb.st_dev;
00122 filesystems[i].rdonly = rdonly;
00123
00124
00125 vm = (struct vmount *)((char *)vm + vm->vmt_length);
00126 }
00127
00128 filesystems[i].mntPoint = NULL;
00129 fsnames[i] = NULL;
00130
00131 return 0;
00132 }
00133
00134 #else
00135
00141 static int getFilesystemList(void)
00142
00143
00144
00145
00146 {
00147 int numAlloced = 10;
00148 struct stat sb;
00149 int i;
00150 const char * mntdir;
00151 int rdonly = 0;
00152
00153 # if GETMNTENT_ONE || GETMNTENT_TWO
00154 our_mntent item;
00155 FILE * mtab;
00156
00157 mtab = fopen(MOUNTED, "r");
00158 if (!mtab) {
00159 rpmlog(RPMLOG_ERR, _("failed to open %s: %s\n"), MOUNTED,
00160 strerror(errno));
00161 return 1;
00162 }
00163 # elif defined(HAVE_GETMNTINFO_R)
00164
00165 struct statfs * mounts = NULL;
00166 int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
00167 int nextMount = 0;
00168
00169 getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
00170 # elif defined(HAVE_GETMNTINFO)
00171
00172 #if defined(__NetBSD__)
00173 struct statvfs * mounts = NULL;
00174 #else
00175 struct statfs * mounts = NULL;
00176 #endif
00177 int mntCount = 0, flags = MNT_NOWAIT;
00178 int nextMount = 0;
00179
00180
00181 mntCount = getmntinfo(&mounts, flags);
00182 # endif
00183
00184 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));
00185
00186 numFilesystems = 0;
00187 while (1) {
00188 # if GETMNTENT_ONE
00189
00190
00191 our_mntent * itemptr = getmntent(mtab);
00192 if (!itemptr) break;
00193 item = *itemptr;
00194 mntdir = item.our_mntdir;
00195 #if defined(MNTOPT_RO)
00196
00197 if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
00198 rdonly = 1;
00199
00200 #endif
00201
00202 # elif GETMNTENT_TWO
00203
00204 if (getmntent(mtab, &item)) break;
00205 mntdir = item.our_mntdir;
00206 # elif defined(HAVE_GETMNTINFO_R)
00207
00208 if (nextMount == mntCount) break;
00209 mntdir = mounts[nextMount++].f_mntonname;
00210 # elif defined(HAVE_GETMNTINFO)
00211
00212 if (nextMount == mntCount) break;
00213 mntdir = mounts[nextMount++].f_mntonname;
00214 # endif
00215
00216 if (stat(mntdir, &sb)) {
00217 switch(errno) {
00218 default:
00219 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), mntdir,
00220 strerror(errno));
00221 rpmFreeFilesystems();
00222 return 1;
00223 break;
00224 case EACCES:
00225 case ESTALE:
00226 continue;
00227 break;
00228 }
00229 }
00230
00231 if ((numFilesystems + 2) == numAlloced) {
00232 numAlloced += 10;
00233 filesystems = xrealloc(filesystems,
00234 sizeof(*filesystems) * (numAlloced + 1));
00235 }
00236
00237 filesystems[numFilesystems].dev = sb.st_dev;
00238 filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
00239 filesystems[numFilesystems].rdonly = rdonly;
00240 #if 0
00241 rpmlog(RPMLOG_DEBUG, _("%5d 0x%04x %s %s\n"),
00242 numFilesystems,
00243 (unsigned) filesystems[numFilesystems].dev,
00244 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
00245 filesystems[numFilesystems].mntPoint);
00246 #endif
00247 numFilesystems++;
00248 }
00249
00250 # if GETMNTENT_ONE || GETMNTENT_TWO
00251 (void) fclose(mtab);
00252 # elif defined(HAVE_GETMNTINFO_R)
00253 mounts = _free(mounts);
00254 # endif
00255
00256 filesystems[numFilesystems].dev = 0;
00257 filesystems[numFilesystems].mntPoint = NULL;
00258 filesystems[numFilesystems].rdonly = 0;
00259
00260 fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
00261 for (i = 0; i < numFilesystems; i++)
00262 fsnames[i] = filesystems[i].mntPoint;
00263 fsnames[numFilesystems] = NULL;
00264
00265
00266 return 0;
00267
00268 }
00269 #endif
00270
00271 int rpmGetFilesystemList(const char *** listptr, uint32_t * num)
00272 {
00273 if (!fsnames)
00274 if (getFilesystemList())
00275 return 1;
00276
00277 if (listptr) *listptr = fsnames;
00278 if (num) *num = numFilesystems;
00279
00280 return 0;
00281 }
00282
00283 int rpmGetFilesystemUsage(const char ** fileList, uint32_t * fssizes, int numFiles,
00284 uint64_t ** usagesPtr, int flags)
00285 {
00286 uint64_t * usages;
00287 int i, len, j;
00288 char * buf, * dirName;
00289 char * chptr;
00290 int maxLen;
00291 char * lastDir;
00292 const char * sourceDir;
00293 int lastfs = 0;
00294 int lastDev = -1;
00295 struct stat sb;
00296
00297 if (!fsnames)
00298 if (getFilesystemList())
00299 return 1;
00300
00301 usages = xcalloc(numFilesystems, sizeof(*usages));
00302
00303 sourceDir = rpmGetPath("%{_sourcedir}", NULL);
00304
00305 maxLen = strlen(sourceDir);
00306 for (i = 0; i < numFiles; i++) {
00307 len = strlen(fileList[i]);
00308 if (maxLen < len) maxLen = len;
00309 }
00310
00311 buf = alloca(maxLen + 1);
00312 lastDir = alloca(maxLen + 1);
00313 dirName = alloca(maxLen + 1);
00314 *lastDir = '\0';
00315
00316
00317 for (i = 0; i < numFiles; i++) {
00318 if (*fileList[i] == '/') {
00319 strcpy(buf, fileList[i]);
00320 chptr = buf + strlen(buf) - 1;
00321 while (*chptr != '/') chptr--;
00322 if (chptr == buf)
00323 buf[1] = '\0';
00324 else
00325 *chptr-- = '\0';
00326 } else {
00327
00328 strcpy(buf, sourceDir);
00329 }
00330
00331 if (strcmp(lastDir, buf)) {
00332 strcpy(dirName, buf);
00333 chptr = dirName + strlen(dirName) - 1;
00334 while (stat(dirName, &sb)) {
00335 if (errno != ENOENT) {
00336 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), buf,
00337 strerror(errno));
00338 sourceDir = _free(sourceDir);
00339 usages = _free(usages);
00340 return 1;
00341 }
00342
00343
00344 while (*chptr != '/') chptr--;
00345
00346 if (chptr == dirName)
00347 dirName[1] = '\0';
00348 else
00349 *chptr-- = '\0';
00350 }
00351
00352 if (lastDev != sb.st_dev) {
00353 for (j = 0; j < numFilesystems; j++)
00354 if (filesystems && filesystems[j].dev == sb.st_dev)
00355 break;
00356
00357 if (j == numFilesystems) {
00358 rpmlog(RPMLOG_ERR,
00359 _("file %s is on an unknown device\n"), buf);
00360 sourceDir = _free(sourceDir);
00361 usages = _free(usages);
00362 return 1;
00363 }
00364
00365 lastfs = j;
00366 lastDev = sb.st_dev;
00367 }
00368 }
00369
00370 strcpy(lastDir, buf);
00371 usages[lastfs] += fssizes[i];
00372 }
00373
00374 sourceDir = _free(sourceDir);
00375
00376 if (usagesPtr)
00377 *usagesPtr = usages;
00378 else
00379 usages = _free(usages);
00380
00381 return 0;
00382 }
00383