rpm 5.2.1

lib/fs.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 #include <rpmio.h>
00007 #include <rpmiotypes.h>
00008 #include <rpmlog.h>
00009 #include <rpmmacro.h>   /* XXX for rpmGetPath */
00010 
00011 #include "fs.h"
00012 
00013 #include "debug.h"
00014 
00015 /*@-usereleased -onlytrans@*/
00016 
00017 struct fsinfo {
00018 /*@only@*/ /*@relnull@*/
00019     const char * mntPoint;      
00020     dev_t dev;                  
00021     int rdonly;                 
00022 };
00023 
00024 /*@unchecked@*/
00025 /*@only@*/ /*@null@*/
00026 static struct fsinfo * filesystems = NULL;
00027 /*@unchecked@*/
00028 /*@only@*/ /*@null@*/
00029 static const char ** fsnames = NULL;
00030 /*@unchecked@*/
00031 static int numFilesystems = 0;
00032 
00033 void rpmFreeFilesystems(void)
00034         /*@globals filesystems, fsnames, numFilesystems @*/
00035         /*@modifies filesystems, fsnames, numFilesystems @*/
00036 {
00037     int i;
00038 
00039     if (filesystems)
00040     for (i = 0; i < numFilesystems; i++)
00041         filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
00042 
00043     filesystems = _free(filesystems);
00044     fsnames = _free(fsnames);
00045     numFilesystems = 0;
00046 }
00047 
00048 #if defined(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         rpmlog(RPMLOG_ERR, _("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         rpmlog(RPMLOG_ERR, _("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 defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
00115         if (!(strcmp(fsn, "/proc") == 0)) {
00116 #endif
00117         if (Stat(fsn, &sb) < 0) {
00118             switch(errno) {
00119             default:
00120                 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), fsn,
00121                         strerror(errno));
00122                 rpmFreeFilesystems();
00123                 return 1;
00124             case ENOENT:        /* XXX avoid /proc if leaked into *BSD jails. */
00125                 sb.st_dev = 0;  /* XXXX make sure st_dev is initialized. */
00126                 /*@switchbreak@*/ break;
00127             }
00128         }
00129         
00130         filesystems[i].dev = sb.st_dev;
00131         filesystems[i].rdonly = rdonly;
00132 #if defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
00133         }
00134 #endif
00135 
00136         /* goto the next vmount structure: */
00137         vm = (struct vmount *)((char *)vm + vm->vmt_length);
00138     }
00139 
00140     filesystems[i].mntPoint = NULL;
00141     fsnames[i]              = NULL;
00142 
00143     return 0;
00144 }
00145 
00146 #else   /* HAVE_MNTCTL */
00147 
00153 static int getFilesystemList(void)
00154         /*@globals h_errno, filesystems, fsnames, numFilesystems,
00155                 fileSystem, internalState @*/
00156         /*@modifies filesystems, fsnames, numFilesystems,
00157                 fileSystem, internalState @*/
00158 {
00159     int numAlloced = 10;
00160     struct stat sb;
00161     int i;
00162     const char * mntdir;
00163     int rdonly = 0;
00164 
00165 #   if GETMNTENT_ONE || GETMNTENT_TWO
00166     our_mntent item;
00167     FILE * mtab;
00168 
00169         mtab = fopen(MOUNTED, "r");
00170         if (!mtab) {
00171             rpmlog(RPMLOG_ERR, _("failed to open %s: %s\n"), MOUNTED, 
00172                      strerror(errno));
00173             return 1;
00174         }
00175 #   elif defined(HAVE_GETMNTINFO_R)
00176     /* This is OSF */
00177     struct statfs * mounts = NULL;
00178     int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
00179     int nextMount = 0;
00180 
00181         getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
00182 #   elif defined(HAVE_GETMNTINFO)
00183     /* This is Mac OS X */
00184 #if defined(__NetBSD__)
00185     struct statvfs * mounts = NULL;
00186 #else
00187     struct statfs * mounts = NULL;
00188 #endif
00189     int mntCount = 0, flags = MNT_NOWAIT;
00190     int nextMount = 0;
00191 
00192         /* XXX 0 on error, errno set */
00193         mntCount = getmntinfo(&mounts, flags);
00194 #   endif
00195 
00196     filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));      /* XXX memory leak */
00197 
00198     numFilesystems = 0;
00199     while (1) {
00200 #       if GETMNTENT_ONE
00201             /* this is Linux */
00202             /*@-modunconnomods -moduncon @*/
00203             our_mntent * itemptr = getmntent(mtab);
00204             if (!itemptr) break;
00205             item = *itemptr;    /* structure assignment */
00206             mntdir = item.our_mntdir;
00207 #if defined(MNTOPT_RO)
00208             /*@-compdef@*/
00209             if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
00210                 rdonly = 1;
00211             /*@=compdef@*/
00212 #endif
00213             /*@=modunconnomods =moduncon @*/
00214 #       elif GETMNTENT_TWO
00215             /* Solaris, maybe others */
00216             if (getmntent(mtab, &item)) break;
00217             mntdir = item.our_mntdir;
00218 #       elif defined(HAVE_GETMNTINFO_R)
00219             /* This is OSF */
00220             if (nextMount == mntCount) break;
00221             mntdir = mounts[nextMount++].f_mntonname;
00222 #       elif defined(HAVE_GETMNTINFO)
00223             /* This is Mac OS X */
00224             if (nextMount == mntCount) break;
00225             mntdir = mounts[nextMount++].f_mntonname;
00226 #       endif
00227 
00228 #if defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
00229         if (strcmp(mntdir, "/proc") == 0)
00230                 continue;
00231 #endif
00232 
00233         if (Stat(mntdir, &sb) < 0) {
00234             switch(errno) {
00235             default:
00236                 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), mntdir,
00237                         strerror(errno));
00238                 rpmFreeFilesystems();
00239                 return 1;
00240                 /*@notreached@*/ /*@switchbreak@*/ break;
00241             case ENOENT:        /* XXX avoid /proc if leaked into *BSD jails. */
00242             case EACCES:        /* XXX fuse fs #220991 */
00243             case ESTALE:
00244                 continue;
00245                 /*@notreached@*/ /*@switchbreak@*/ break;
00246             }
00247         }
00248 
00249         if ((numFilesystems + 2) == numAlloced) {
00250             numAlloced += 10;
00251             filesystems = xrealloc(filesystems, 
00252                                   sizeof(*filesystems) * (numAlloced + 1));
00253         }
00254 
00255         filesystems[numFilesystems].dev = sb.st_dev;
00256         filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
00257         filesystems[numFilesystems].rdonly = rdonly;
00258 #if 0
00259         rpmlog(RPMLOG_DEBUG, _("%5d 0x%04x %s %s\n"),
00260                 numFilesystems,
00261                 (unsigned) filesystems[numFilesystems].dev,
00262                 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
00263                 filesystems[numFilesystems].mntPoint);
00264 #endif
00265         numFilesystems++;
00266     }
00267 
00268 #   if GETMNTENT_ONE || GETMNTENT_TWO
00269         (void) fclose(mtab);
00270 #   elif defined(HAVE_GETMNTINFO_R)
00271         mounts = _free(mounts);
00272 #   endif
00273 
00274     filesystems[numFilesystems].dev = 0;
00275     filesystems[numFilesystems].mntPoint = NULL;
00276     filesystems[numFilesystems].rdonly = 0;
00277 
00278     fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
00279     for (i = 0; i < numFilesystems; i++)
00280         fsnames[i] = filesystems[i].mntPoint;
00281     fsnames[numFilesystems] = NULL;
00282 
00283 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */
00284     return 0; 
00285 /*@=nullstate@*/
00286 }
00287 #endif  /* HAVE_MNTCTL */
00288 
00289 int rpmGetFilesystemList(const char *** listptr, rpmuint32_t * num)
00290 {
00291     if (!fsnames) 
00292         if (getFilesystemList())
00293             return 1;
00294 
00295     if (listptr) *listptr = fsnames;
00296     if (num) *num = numFilesystems;
00297 
00298     return 0;
00299 }
00300 
00301 int rpmGetFilesystemUsage(const char ** fileList, rpmuint32_t * fssizes,
00302                 int numFiles, rpmuint64_t ** usagesPtr,
00303                 /*@unused@*/ int flags)
00304 {
00305     rpmuint64_t * usages;
00306     int i, j;
00307     char * buf, * dirName;
00308     char * chptr;
00309     size_t maxLen;
00310     size_t len;
00311     char * lastDir;
00312     const char * sourceDir;
00313     int lastfs = 0;
00314     dev_t lastDev = (dev_t)-1;          /* I hope nobody uses -1 for a st_dev */
00315     struct stat sb;
00316     int rc = 1;         /* assume failure */
00317 
00318     if (!fsnames) 
00319         if (getFilesystemList())
00320             return rc;
00321 
00322     usages = xcalloc(numFilesystems, sizeof(*usages));
00323 
00324     sourceDir = rpmGetPath("%{_sourcedir}", NULL);
00325 
00326     maxLen = strlen(sourceDir);
00327     for (i = 0; i < numFiles; i++) {
00328         len = strlen(fileList[i]);
00329         if (maxLen < len) maxLen = len;
00330     }
00331     
00332     buf = alloca(maxLen + 1);
00333     lastDir = alloca(maxLen + 1);
00334     dirName = alloca(maxLen + 1);
00335     *lastDir = '\0';
00336 
00337     /* cut off last filename */
00338     for (i = 0; i < numFiles; i++) {
00339         if (*fileList[i] == '/') {
00340             strcpy(buf, fileList[i]);
00341             chptr = buf + strlen(buf) - 1;
00342             while (*chptr != '/') chptr--;
00343             if (chptr == buf)
00344                 buf[1] = '\0';
00345             else
00346                 *chptr-- = '\0';
00347         } else {
00348             /* this should only happen for source packages (gulp) */
00349             strcpy(buf,  sourceDir);
00350         }
00351 
00352         if (strcmp(lastDir, buf)) {
00353             strcpy(dirName, buf);
00354             chptr = dirName + strlen(dirName) - 1;
00355             while (Stat(dirName, &sb) < 0) {
00356                 switch(errno) {
00357                 default:
00358                     rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), buf,
00359                                 strerror(errno));
00360                     goto exit;
00361                     /*@notreached@*/ /*@switchbreak@*/ break;
00362                 case ENOENT:    /* XXX paths in empty chroot's don't exist. */
00363                     /*@switchbreak@*/ break;
00364                 }
00365 
00366                 /* cut off last directory part, because it was not found. */
00367                 while (*chptr != '/') chptr--;
00368 
00369                 if (chptr == dirName)
00370                     dirName[1] = '\0';
00371                 else
00372                     *chptr-- = '\0';
00373             }
00374 
00375             if (lastDev != sb.st_dev) {
00376                 for (j = 0; j < numFilesystems; j++)
00377                     if (filesystems && filesystems[j].dev == sb.st_dev)
00378                         /*@innerbreak@*/ break;
00379 
00380                 if (j == numFilesystems) {
00381                     rpmlog(RPMLOG_ERR, 
00382                                 _("file %s is on an unknown device\n"), buf);
00383                     goto exit;
00384                 }
00385 
00386                 lastfs = j;
00387                 lastDev = sb.st_dev;
00388             }
00389         }
00390 
00391         strcpy(lastDir, buf);
00392         usages[lastfs] += fssizes[i];
00393     }
00394     rc = 0;
00395 
00396 exit:
00397     sourceDir = _free(sourceDir);
00398 
00399     if (rc == 0 && usagesPtr)
00400         *usagesPtr = usages;
00401     else
00402         usages = _free(usages);
00403 
00404     return rc;
00405 }
00406 /*@=usereleased =onlytrans@*/