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

Generated at Sun Apr 8 18:42:59 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000