Main Page Modules Data Structures File List Data Fields Globals Related Pages

# lib/fs.c

Go to the documentation of this file.

    00001 /*@-mods@*/
    00006 #include "system.h"
    00007 #include <rpmlib.h>
    00008 #include <rpmmacro.h>   /* XXX for rpmGetPath */
    00009 #include "debug.h"
    00010
    00011 /*@-usereleased -onlytrans@*/
    00012
    00013 struct fsinfo {
    00014 /*@only@*/ const char * mntPoint;
    00015     dev_t dev;
    00016     int rdonly;
    00017 };
    00018
    00019 /*@unchecked@*/
    00020 /*@only@*/ /*@null@*/ static struct fsinfo * filesystems = NULL;
    00021 /*@unchecked@*/
    00022 /*@only@*/ /*@null@*/ static const char ** fsnames = NULL;
    00023 /*@unchecked@*/
    00024 static int numFilesystems = 0;
    00025
    00026 void freeFilesystems(void)
    00027 {
    00028     int i;
    00029
    00030 /*@-boundswrite@*/
    00031     if (filesystems)
    00032     for (i = 0; i < numFilesystems; i++)
    00033         filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
    00034 /*@=boundswrite@*/
    00035
    00036     filesystems = _free(filesystems);
    00037     fsnames = _free(fsnames);
    00038     numFilesystems = 0;
    00039 }
    00040
    00041 #if HAVE_MNTCTL
    00042
    00043 /* modeled after sample code from Till Bubeck */
    00044
    00045 #include <sys/mntctl.h>
    00046 #include <sys/vmount.h>
    00047
    00048 /*
    00049  * There is NO mntctl prototype in any header file of AIX 3.2.5!
    00050  * So we have to declare it by ourself...
    00051  */
    00052 int mntctl(int command, int size, char *buffer);
    00053
    00059 static int getFilesystemList(void)
    00060         /*@*/
    00061 {
    00062     int size;
    00063     void * buf;
    00064     struct vmount * vm;
    00065     struct stat sb;
    00066     int rdonly = 0;
    00067     int num;
    00068     int fsnameLength;
    00069     int i;
    00070
    00071     num = mntctl(MCTL_QUERY, sizeof(size), (char *) &size);
    00072     if (num < 0) {
    00073         rpmError(RPMERR_MTAB, _("mntctl() failed to return size: %s\n"),
    00074                  strerror(errno));
    00075         return 1;
    00076     }
    00077
    00078     /*
    00079      * Double the needed size, so that even when the user mounts a
    00080      * filesystem between the previous and the next call to mntctl
    00081      * the buffer still is large enough.
    00082      */
    00083     size *= 2;
    00084
    00085     buf = alloca(size);
    00086     num = mntctl(MCTL_QUERY, size, buf);
    00087     if ( num <= 0 ) {
    00088         rpmError(RPMERR_MTAB, _("mntctl() failed to return mount points: %s\n"),
    00089                  strerror(errno));
    00090         return 1;
    00091     }
    00092
    00093     numFilesystems = num;
    00094
    00095     filesystems = xcalloc((numFilesystems + 1), sizeof(*filesystems));
    00096     fsnames = xcalloc((numFilesystems + 1), sizeof(char *));
    00097
    00098     for (vm = buf, i = 0; i < num; i++) {
    00099         char *fsn;
    00100         fsnameLength = vm->vmt_data[VMT_STUB].vmt_size;
    00101         fsn = xmalloc(fsnameLength + 1);
    00102         strncpy(fsn, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
    00103                 fsnameLength);
    00104
    00105         filesystems[i].mntPoint = fsnames[i] = fsn;
    00106
    00107         if (stat(filesystems[i].mntPoint, &sb)) {
    00108             rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), fsnames[i],
    00109                         strerror(errno));
    00110
    00111             freeFilesystems();
    00112             return 1;
    00113         }
    00114
    00115         filesystems[i].dev = sb.st_dev;
    00116         filesystems[i].rdonly = rdonly;
    00117
    00118         /* goto the next vmount structure: */
    00119         vm = (struct vmount *)((char *)vm + vm->vmt_length);
    00120     }
    00121
    00122     filesystems[i].mntPoint = NULL;
    00123     fsnames[i]              = NULL;
    00124
    00125     return 0;
    00126 }
    00127
    00128 #else   /* HAVE_MNTCTL */
    00129
    00135 static int getFilesystemList(void)
    00136         /*@globals fileSystem, internalState@*/
    00137         /*@modifies fileSystem, internalState@*/
    00138 {
    00139     int numAlloced = 10;
    00140     struct stat sb;
    00141     int i;
    00142     const char * mntdir;
    00143     int rdonly = 0;
    00144
    00145 #   if GETMNTENT_ONE || GETMNTENT_TWO
    00146     our_mntent item;
    00147     FILE * mtab;
    00148
    00149         mtab = fopen(MOUNTED, "r");
    00150         if (!mtab) {
    00151             rpmError(RPMERR_MTAB, _("failed to open %s: %s\n"), MOUNTED,
    00152                      strerror(errno));
    00153             return 1;
    00154         }
    00155 #   elif HAVE_GETMNTINFO_R
    00156     struct statfs * mounts = NULL;
    00157     int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
    00158     int nextMount = 0;
    00159
    00160         getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
    00161 #   endif
    00162
    00163     filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));      /* XXX memory leak */
    00164
    00165     numFilesystems = 0;
    00166     while (1) {
    00167 #       if GETMNTENT_ONE
    00168             /* this is Linux */
    00169             /*@-modunconnomods -moduncon @*/
    00170             our_mntent * itemptr = getmntent(mtab);
    00171             if (!itemptr) break;
    00172 /*@-boundsread@*/
    00173             item = *itemptr;    /* structure assignment */
    00174 /*@=boundsread@*/
    00175             mntdir = item.our_mntdir;
    00176 #if defined(MNTOPT_RO)
    00177             /*@-compdef@*/
    00178             if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
    00179                 rdonly = 1;
    00180             /*@=compdef@*/
    00181 #endif
    00182             /*@=modunconnomods =moduncon @*/
    00183 #       elif GETMNTENT_TWO
    00184             /* Solaris, maybe others */
    00185             if (getmntent(mtab, &item)) break;
    00186             mntdir = item.our_mntdir;
    00187 #       elif HAVE_GETMNTINFO_R
    00188             if (nextMount == mntCount) break;
    00189             mntdir = mounts[nextMount++].f_mntonname;
    00190 #       endif
    00191
    00192         if (stat(mntdir, &sb)) {
    00193             rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), mntdir,
    00194                         strerror(errno));
    00195
    00196             freeFilesystems();
    00197             return 1;
    00198         }
    00199
    00200         numFilesystems++;
    00201         if ((numFilesystems + 1) == numAlloced) {
    00202             numAlloced += 10;
    00203             filesystems = xrealloc(filesystems,
    00204                                   sizeof(*filesystems) * (numAlloced + 1));
    00205         }
    00206
    00207         filesystems[numFilesystems-1].dev = sb.st_dev;
    00208         filesystems[numFilesystems-1].mntPoint = xstrdup(mntdir);
    00209         filesystems[numFilesystems-1].rdonly = rdonly;
    00210     }
    00211
    00212 #   if GETMNTENT_ONE || GETMNTENT_TWO
    00213         (void) fclose(mtab);
    00214 #   elif HAVE_GETMNTINFO_R
    00215         mounts = _free(mounts);
    00216 #   endif
    00217
    00218     filesystems[numFilesystems].dev = 0;
    00219     filesystems[numFilesystems].mntPoint = NULL;
    00220     filesystems[numFilesystems].rdonly = 0;
    00221
    00222 /*@-boundswrite@*/
    00223     fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
    00224     for (i = 0; i < numFilesystems; i++)
    00225         fsnames[i] = filesystems[i].mntPoint;
    00226     fsnames[numFilesystems] = NULL;
    00227 /*@=boundswrite@*/
    00228
    00229     return 0;
    00230 }
    00231 #endif  /* HAVE_MNTCTL */
    00232
    00233 int rpmGetFilesystemList(const char *** listptr, int * num)
    00234 {
    00235     if (!fsnames)
    00236         if (getFilesystemList())
    00237             return 1;
    00238
    00239 /*@-boundswrite@*/
    00240     if (listptr) *listptr = fsnames;
    00241     if (num) *num = numFilesystems;
    00242 /*@=boundswrite@*/
    00243
    00244     return 0;
    00245 }
    00246
    00247 int rpmGetFilesystemUsage(const char ** fileList, int_32 * fssizes, int numFiles,
    00248                           uint_32 ** usagesPtr, /*@unused@*/ int flags)
    00249 {
    00250     int_32 * usages;
    00251     int i, len, j;
    00252     char * buf, * dirName;
    00253     char * chptr;
    00254     int maxLen;
    00255     char * lastDir;
    00256     const char * sourceDir;
    00257     int lastfs = 0;
    00258     int lastDev = -1;           /* I hope nobody uses -1 for a st_dev */
    00259     struct stat sb;
    00260
    00261     if (!fsnames)
    00262         if (getFilesystemList())
    00263             return 1;
    00264
    00265     usages = xcalloc(numFilesystems, sizeof(usages));
    00266
    00267     sourceDir = rpmGetPath("%{_sourcedir}", NULL);
    00268
    00269     maxLen = strlen(sourceDir);
    00270 /*@-boundsread@*/
    00271     for (i = 0; i < numFiles; i++) {
    00272         len = strlen(fileList[i]);
    00273         if (maxLen < len) maxLen = len;
    00274     }
    00275 /*@=boundsread@*/
    00276
    00277 /*@-boundswrite@*/
    00278     buf = alloca(maxLen + 1);
    00279     lastDir = alloca(maxLen + 1);
    00280     dirName = alloca(maxLen + 1);
    00281     *lastDir = '\0';
    00282
    00283     /* cut off last filename */
    00284     for (i = 0; i < numFiles; i++) {
    00285         if (*fileList[i] == '/') {
    00286             strcpy(buf, fileList[i]);
    00287             chptr = buf + strlen(buf) - 1;
    00288             while (*chptr != '/') chptr--;
    00289             if (chptr == buf)
    00290                 buf[1] = '\0';
    00291             else
    00292                 *chptr-- = '\0';
    00293         } else {
    00294             /* this should only happen for source packages (gulp) */
    00295             strcpy(buf,  sourceDir);
    00296         }
    00297
    00298         if (strcmp(lastDir, buf)) {
    00299             strcpy(dirName, buf);
    00300             chptr = dirName + strlen(dirName) - 1;
    00301             while (stat(dirName, &sb)) {
    00302                 if (errno != ENOENT) {
    00303                     rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf,
    00304                                 strerror(errno));
    00305                     sourceDir = _free(sourceDir);
    00306                     usages = _free(usages);
    00307                     return 1;
    00308                 }
    00309
    00310                 /* cut off last directory part, because it was not found. */
    00311                 while (*chptr != '/') chptr--;
    00312
    00313                 if (chptr == dirName)
    00314                     dirName[1] = '\0';
    00315                 else
    00316                     *chptr-- = '\0';
    00317             }
    00318
    00319             if (lastDev != sb.st_dev) {
    00320                 for (j = 0; j < numFilesystems; j++)
    00321                     if (filesystems && filesystems[j].dev == sb.st_dev)
    00322                         /*@innerbreak@*/ break;
    00323
    00324                 if (j == numFilesystems) {
    00325                     rpmError(RPMERR_BADDEV,
    00326                                 _("file %s is on an unknown device\n"), buf);
    00327                     sourceDir = _free(sourceDir);
    00328                     usages = _free(usages);
    00329                     return 1;
    00330                 }
    00331
    00332                 lastfs = j;
    00333                 lastDev = sb.st_dev;
    00334             }
    00335         }
    00336
    00337         strcpy(lastDir, buf);
    00338         usages[lastfs] += fssizes[i];
    00339     }
    00340 /*@=boundswrite@*/
    00341
    00342     sourceDir = _free(sourceDir);
    00343
    00344 /*@-boundswrite@*/
    00345     /*@-branchstate@*/
    00346     if (usagesPtr)
    00347         *usagesPtr = usages;
    00348     else
    00349         usages = _free(usages);
    00350     /*@=branchstate@*/
    00351 /*@=boundswrite@*/
    00352
    00353     return 0;
    00354 }
    00355 /*@=usereleased =onlytrans@*/
    00356 /*@=mods@*/