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

Generated on Sat Oct 1 16:48:14 2011 for rpm by  doxygen 1.4.4