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

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2