• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

lib/fs.c

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

Generated on Mon Nov 29 2010 05:18:42 for rpm by  doxygen 1.7.2