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             switch (errno) {
00220             case ESTALE:
00221             case EACCES:
00222                 continue;
00223             default:
00224                 rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), mntdir,
00225                         strerror(errno));
00226                 freeFilesystems();
00227                 return 1;
00228             }
00229         }
00230 
00231         if ((numFilesystems + 2) == numAlloced) {
00232             numAlloced += 10;
00233             filesystems = xrealloc(filesystems, 
00234                                   sizeof(*filesystems) * (numAlloced + 1));
00235         }
00236 
00237         filesystems[numFilesystems].dev = sb.st_dev;
00238         filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
00239         filesystems[numFilesystems].rdonly = rdonly;
00240 #if 0
00241         rpmMessage(RPMMESS_DEBUG, _("%5d 0x%04x %s %s\n"),
00242                 numFilesystems,
00243                 (unsigned) filesystems[numFilesystems].dev,
00244                 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
00245                 filesystems[numFilesystems].mntPoint);
00246 #endif
00247         numFilesystems++;
00248     }
00249 
00250 #   if GETMNTENT_ONE || GETMNTENT_TWO
00251         (void) fclose(mtab);
00252 #   elif HAVE_GETMNTINFO_R
00253         mounts = _free(mounts);
00254 #   endif
00255 
00256     filesystems[numFilesystems].dev = 0;
00257     filesystems[numFilesystems].mntPoint = NULL;
00258     filesystems[numFilesystems].rdonly = 0;
00259 
00260 /*@-boundswrite@*/
00261     fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
00262     for (i = 0; i < numFilesystems; i++)
00263         fsnames[i] = filesystems[i].mntPoint;
00264     fsnames[numFilesystems] = NULL;
00265 /*@=boundswrite@*/
00266 
00267 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */
00268     return 0; 
00269 /*@=nullstate@*/
00270 }
00271 #endif  /* HAVE_MNTCTL */
00272 
00273 int rpmGetFilesystemList(const char *** listptr, int * num)
00274 {
00275     if (!fsnames) 
00276         if (getFilesystemList())
00277             return 1;
00278 
00279 /*@-boundswrite@*/
00280     if (listptr) *listptr = fsnames;
00281     if (num) *num = numFilesystems;
00282 /*@=boundswrite@*/
00283 
00284     return 0;
00285 }
00286 
00287 int rpmGetFilesystemUsage(const char ** fileList, int_32 * fssizes, int numFiles,
00288                           uint_32 ** usagesPtr, /*@unused@*/ int flags)
00289 {
00290     int_32 * usages;
00291     int i, len, j;
00292     char * buf, * dirName;
00293     char * chptr;
00294     int maxLen;
00295     char * lastDir;
00296     const char * sourceDir;
00297     int lastfs = 0;
00298     int lastDev = -1;           /* I hope nobody uses -1 for a st_dev */
00299     struct stat sb;
00300 
00301     if (!fsnames) 
00302         if (getFilesystemList())
00303             return 1;
00304 
00305     usages = xcalloc(numFilesystems, sizeof(usages));
00306 
00307     sourceDir = rpmGetPath("%{_sourcedir}", NULL);
00308 
00309     maxLen = strlen(sourceDir);
00310 /*@-boundsread@*/
00311     for (i = 0; i < numFiles; i++) {
00312         len = strlen(fileList[i]);
00313         if (maxLen < len) maxLen = len;
00314     }
00315 /*@=boundsread@*/
00316     
00317 /*@-boundswrite@*/
00318     buf = alloca(maxLen + 1);
00319     lastDir = alloca(maxLen + 1);
00320     dirName = alloca(maxLen + 1);
00321     *lastDir = '\0';
00322 
00323     /* cut off last filename */
00324     for (i = 0; i < numFiles; i++) {
00325         if (*fileList[i] == '/') {
00326             strcpy(buf, fileList[i]);
00327             chptr = buf + strlen(buf) - 1;
00328             while (*chptr != '/') chptr--;
00329             if (chptr == buf)
00330                 buf[1] = '\0';
00331             else
00332                 *chptr-- = '\0';
00333         } else {
00334             /* this should only happen for source packages (gulp) */
00335             strcpy(buf,  sourceDir);
00336         }
00337 
00338         if (strcmp(lastDir, buf)) {
00339             strcpy(dirName, buf);
00340             chptr = dirName + strlen(dirName) - 1;
00341             while (stat(dirName, &sb)) {
00342                 if (errno != ENOENT) {
00343                     rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf,
00344                                 strerror(errno));
00345                     sourceDir = _free(sourceDir);
00346                     usages = _free(usages);
00347                     return 1;
00348                 }
00349 
00350                 /* cut off last directory part, because it was not found. */
00351                 while (*chptr != '/') chptr--;
00352 
00353                 if (chptr == dirName)
00354                     dirName[1] = '\0';
00355                 else
00356                     *chptr-- = '\0';
00357             }
00358 
00359             if (lastDev != sb.st_dev) {
00360                 for (j = 0; j < numFilesystems; j++)
00361                     if (filesystems && filesystems[j].dev == sb.st_dev)
00362                         /*@innerbreak@*/ break;
00363 
00364                 if (j == numFilesystems) {
00365                     rpmError(RPMERR_BADDEV, 
00366                                 _("file %s is on an unknown device\n"), buf);
00367                     sourceDir = _free(sourceDir);
00368                     usages = _free(usages);
00369                     return 1;
00370                 }
00371 
00372                 lastfs = j;
00373                 lastDev = sb.st_dev;
00374             }
00375         }
00376 
00377         strcpy(lastDir, buf);
00378         usages[lastfs] += fssizes[i];
00379     }
00380 /*@=boundswrite@*/
00381 
00382     sourceDir = _free(sourceDir);
00383 
00384 /*@-boundswrite@*/
00385     /*@-branchstate@*/
00386     if (usagesPtr)
00387         *usagesPtr = usages;
00388     else
00389         usages = _free(usages);
00390     /*@=branchstate@*/
00391 /*@=boundswrite@*/
00392 
00393     return 0;
00394 }
00395 /*@=usereleased =onlytrans@*/

Generated on Tue Jan 5 15:36:37 2010 for rpm by  doxygen 1.4.7