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

Generated on Sun Feb 2 23:32:00 2003 for rpm by doxygen1.2.18