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

lib/fs.c

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

Generated at Thu Sep 6 11:32:28 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001