- Main Page
- Related Pages
- Modules
- Data Structures
- Files

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