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

Generated on Sun Oct 26 13:01:59 2003 for rpm by doxygen1.2.18