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@*/

Generated on Thu Mar 9 17:27:43 2006 for rpm by  doxygen 1.4.6