# 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     if (filesystems) {
    00029         int i;
    00030         for (i = 0; i < numFilesystems; i++)
    00031             filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
    00032         filesystems = _free(filesystems);
    00033     }
    00034     if (fsnames) {
    00035 #if 0   /* XXX leak/segfault on exit of "rpm -qp --qf '%{#fsnames}' pkg" */
    00036         free(fsnames);
    00037 #endif
    00038         fsnames = NULL;
    00039     }
    00040     numFilesystems = 0;
    00041 }
    00042
    00043 #if HAVE_MNTCTL
    00044
    00045 /* modeled after sample code from Till Bubeck */
    00046
    00047 #include <sys/mntctl.h>
    00048 #include <sys/vmount.h>
    00049
    00050 /*
    00051  * There is NO mntctl prototype in any header file of AIX 3.2.5!
    00052  * So we have to declare it by ourself...
    00053  */
    00054 int mntctl(int command, int size, char *buffer);
    00055
    00061 static int getFilesystemList(void)
    00062         /*@*/
    00063 {
    00064     int size;
    00065     void * buf;
    00066     struct vmount * vm;
    00067     struct stat sb;
    00068     int rdonly = 0;
    00069     int num;
    00070     int fsnameLength;
    00071     int i;
    00072
    00073     num = mntctl(MCTL_QUERY, sizeof(size), (char *) &size);
    00074     if (num < 0) {
    00075         rpmError(RPMERR_MTAB, _("mntctl() failed to return size: %s\n"),
    00076                  strerror(errno));
    00077         return 1;
    00078     }
    00079
    00080     /*
    00081      * Double the needed size, so that even when the user mounts a
    00082      * filesystem between the previous and the next call to mntctl
    00083      * the buffer still is large enough.
    00084      */
    00085     size *= 2;
    00086
    00087     buf = alloca(size);
    00088     num = mntctl(MCTL_QUERY, size, buf);
    00089     if ( num <= 0 ) {
    00090         rpmError(RPMERR_MTAB, _("mntctl() failed to return mount points: %s\n"),
    00091                  strerror(errno));
    00092         return 1;
    00093     }
    00094
    00095     numFilesystems = num;
    00096
    00097     filesystems = xcalloc((numFilesystems + 1), sizeof(*filesystems));
    00098     fsnames = xcalloc((numFilesystems + 1), sizeof(char *));
    00099
    00100     for (vm = buf, i = 0; i < num; i++) {
    00101         char *fsn;
    00102         fsnameLength = vm->vmt_data[VMT_STUB].vmt_size;
    00103         fsn = xmalloc(fsnameLength + 1);
    00104         strncpy(fsn, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
    00105                 fsnameLength);
    00106
    00107         filesystems[i].mntPoint = fsnames[i] = fsn;
    00108
    00109         if (stat(filesystems[i].mntPoint, &sb)) {
    00110             rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), fsnames[i],
    00111                         strerror(errno));
    00112
    00113             freeFilesystems();
    00114             return 1;
    00115         }
    00116
    00117         filesystems[i].dev = sb.st_dev;
    00118         filesystems[i].rdonly = rdonly;
    00119
    00120         /* goto the next vmount structure: */
    00121         vm = (struct vmount *)((char *)vm + vm->vmt_length);
    00122     }
    00123
    00124     filesystems[i].mntPoint = NULL;
    00125     fsnames[i]              = NULL;
    00126
    00127     return 0;
    00128 }
    00129
    00130 #else   /* HAVE_MNTCTL */
    00131
    00137 static int getFilesystemList(void)
    00138         /*@globals fileSystem, internalState@*/
    00139         /*@modifies fileSystem, internalState@*/
    00140 {
    00141     int numAlloced = 10;
    00142     struct stat sb;
    00143     int i;
    00144     const char * mntdir;
    00145     int rdonly = 0;
    00146
    00147 #   if GETMNTENT_ONE || GETMNTENT_TWO
    00148     our_mntent item;
    00149     FILE * mtab;
    00150
    00151         mtab = fopen(MOUNTED, "r");
    00152         if (!mtab) {
    00153             rpmError(RPMERR_MTAB, _("failed to open %s: %s\n"), MOUNTED,
    00154                      strerror(errno));
    00155             return 1;
    00156         }
    00157 #   elif HAVE_GETMNTINFO_R
    00158     struct statfs * mounts = NULL;
    00159     int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
    00160     int nextMount = 0;
    00161
    00162         getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
    00163 #   endif
    00164
    00165     filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));      /* XXX memory leak */
    00166
    00167     numFilesystems = 0;
    00168     while (1) {
    00169 #       if GETMNTENT_ONE
    00170             /* this is Linux */
    00171             /*@-modunconnomods -moduncon @*/
    00172             our_mntent * itemptr = getmntent(mtab);
    00173             if (!itemptr) break;
    00174             item = *itemptr;    /* structure assignment */
    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     fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
    00223     for (i = 0; i < numFilesystems; i++)
    00224         fsnames[i] = filesystems[i].mntPoint;
    00225     fsnames[numFilesystems] = NULL;
    00226
    00227     return 0;
    00228 }
    00229 #endif  /* HAVE_MNTCTL */
    00230
    00231 int rpmGetFilesystemList(const char *** listptr, int * num)
    00232 {
    00233     if (!fsnames)
    00234         if (getFilesystemList())
    00235             return 1;
    00236
    00237     if (listptr) *listptr = fsnames;
    00238     if (num) *num = numFilesystems;
    00239
    00240     return 0;
    00241 }
    00242
    00243 int rpmGetFilesystemUsage(const char ** fileList, int_32 * fssizes, int numFiles,
    00244                           uint_32 ** usagesPtr, /*@unused@*/ int flags)
    00245 {
    00246     int_32 * usages;
    00247     int i, len, j;
    00248     char * buf, * dirName;
    00249     char * chptr;
    00250     int maxLen;
    00251     char * lastDir;
    00252     const char * sourceDir;
    00253     int lastfs = 0;
    00254     int lastDev = -1;           /* I hope nobody uses -1 for a st_dev */
    00255     struct stat sb;
    00256
    00257     if (!fsnames)
    00258         if (getFilesystemList())
    00259             return 1;
    00260
    00261     usages = xcalloc(numFilesystems, sizeof(usages));
    00262
    00263     sourceDir = rpmGetPath("%{_sourcedir}", NULL);
    00264
    00265     maxLen = strlen(sourceDir);
    00266     for (i = 0; i < numFiles; i++) {
    00267         len = strlen(fileList[i]);
    00268         if (maxLen < len) maxLen = len;
    00269     }
    00270
    00271     buf = alloca(maxLen + 1);
    00272     lastDir = alloca(maxLen + 1);
    00273     dirName = alloca(maxLen + 1);
    00274     *lastDir = '\0';
    00275
    00276     /* cut off last filename */
    00277     for (i = 0; i < numFiles; i++) {
    00278         if (*fileList[i] == '/') {
    00279             strcpy(buf, fileList[i]);
    00280             chptr = buf + strlen(buf) - 1;
    00281             while (*chptr != '/') chptr--;
    00282             if (chptr == buf)
    00283                 buf[1] = '\0';
    00284             else
    00285                 *chptr-- = '\0';
    00286         } else {
    00287             /* this should only happen for source packages (gulp) */
    00288             strcpy(buf,  sourceDir);
    00289         }
    00290
    00291         if (strcmp(lastDir, buf)) {
    00292             strcpy(dirName, buf);
    00293             chptr = dirName + strlen(dirName) - 1;
    00294             while (stat(dirName, &sb)) {
    00295                 if (errno != ENOENT) {
    00296                     rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf,
    00297                                 strerror(errno));
    00298                     sourceDir = _free(sourceDir);
    00299                     usages = _free(usages);
    00300                     return 1;
    00301                 }
    00302
    00303                 /* cut off last directory part, because it was not found. */
    00304                 while (*chptr != '/') chptr--;
    00305
    00306                 if (chptr == dirName)
    00307                     dirName[1] = '\0';
    00308                 else
    00309                     *chptr-- = '\0';
    00310             }
    00311
    00312             if (lastDev != sb.st_dev) {
    00313                 for (j = 0; j < numFilesystems; j++)
    00314                     if (filesystems && filesystems[j].dev == sb.st_dev)
    00315                         /*@innerbreak@*/ break;
    00316
    00317                 if (j == numFilesystems) {
    00318                     rpmError(RPMERR_BADDEV,
    00319                                 _("file %s is on an unknown device\n"), buf);
    00320                     sourceDir = _free(sourceDir);
    00321                     usages = _free(usages);
    00322                     return 1;
    00323                 }
    00324
    00325                 lastfs = j;
    00326                 lastDev = sb.st_dev;
    00327             }
    00328         }
    00329
    00330         strcpy(lastDir, buf);
    00331         usages[lastfs] += fssizes[i];
    00332     }
    00333
    00334     sourceDir = _free(sourceDir);
    00335
    00336     /*@-branchstate@*/
    00337     if (usagesPtr)
    00338         *usagesPtr = usages;
    00339     else
    00340         usages = _free(usages);
    00341     /*@=branchstate@*/
    00342
    00343     return 0;
    00344 }
    00345 /*@=usereleased =onlytrans@*/
    00346 /*@=mods@*/