rpm 5.2.1

- 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 <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@*/