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     /* This is OSF */
00163     struct statfs * mounts = NULL;
00164     int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
00165     int nextMount = 0;
00166 
00167         getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
00168 #   elif HAVE_GETMNTINFO
00169     /* This is Mac OS X */
00170     struct statfs * mounts = NULL;
00171     int mntCount = 0, flags = MNT_NOWAIT;
00172     int nextMount = 0;
00173 
00174         /* XXX 0 on error, errno set */
00175         mntCount = getmntinfo(&mounts, flags);
00176 #   endif
00177 
00178     filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));      /* XXX memory leak */
00179 
00180     numFilesystems = 0;
00181     while (1) {
00182 #       if GETMNTENT_ONE
00183             /* this is Linux */
00184             /*@-modunconnomods -moduncon @*/
00185             our_mntent * itemptr = getmntent(mtab);
00186             if (!itemptr) break;
00187 /*@-boundsread@*/
00188             item = *itemptr;    /* structure assignment */
00189 /*@=boundsread@*/
00190             mntdir = item.our_mntdir;
00191 #if defined(MNTOPT_RO)
00192             /*@-compdef@*/
00193             if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
00194                 rdonly = 1;
00195             /*@=compdef@*/
00196 #endif
00197             /*@=modunconnomods =moduncon @*/
00198 #       elif GETMNTENT_TWO
00199             /* Solaris, maybe others */
00200             if (getmntent(mtab, &item)) break;
00201             mntdir = item.our_mntdir;
00202 #       elif HAVE_GETMNTINFO_R
00203             /* This is OSF */
00204             if (nextMount == mntCount) break;
00205             mntdir = mounts[nextMount++].f_mntonname;
00206 #       elif HAVE_GETMNTINFO
00207             /* This is Mac OS X */
00208             if (nextMount == mntCount) break;
00209             mntdir = mounts[nextMount++].f_mntonname;
00210 #       endif
00211 
00212         if (stat(mntdir, &sb)) {
00213             rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), mntdir,
00214                         strerror(errno));
00215 
00216             freeFilesystems();
00217             return 1;
00218         }
00219 
00220         if ((numFilesystems + 2) == numAlloced) {
00221             numAlloced += 10;
00222             filesystems = xrealloc(filesystems, 
00223                                   sizeof(*filesystems) * (numAlloced + 1));
00224         }
00225 
00226         filesystems[numFilesystems].dev = sb.st_dev;
00227         filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
00228         filesystems[numFilesystems].rdonly = rdonly;
00229 #if 0
00230         rpmMessage(RPMMESS_DEBUG, _("%5d 0x%04x %s %s\n"),
00231                 numFilesystems,
00232                 (unsigned) filesystems[numFilesystems].dev,
00233                 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
00234                 filesystems[numFilesystems].mntPoint);
00235 #endif
00236         numFilesystems++;
00237     }
00238 
00239 #   if GETMNTENT_ONE || GETMNTENT_TWO
00240         (void) fclose(mtab);
00241 #   elif HAVE_GETMNTINFO_R
00242         mounts = _free(mounts);
00243 #   endif
00244 
00245     filesystems[numFilesystems].dev = 0;
00246     filesystems[numFilesystems].mntPoint = NULL;
00247     filesystems[numFilesystems].rdonly = 0;
00248 
00249 /*@-boundswrite@*/
00250     fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
00251     for (i = 0; i < numFilesystems; i++)
00252         fsnames[i] = filesystems[i].mntPoint;
00253     fsnames[numFilesystems] = NULL;
00254 /*@=boundswrite@*/
00255 
00256 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */
00257     return 0; 
00258 /*@=nullstate@*/
00259 }
00260 #endif  /* HAVE_MNTCTL */
00261 
00262 int rpmGetFilesystemList(const char *** listptr, int * num)
00263 {
00264     if (!fsnames) 
00265         if (getFilesystemList())
00266             return 1;
00267 
00268 /*@-boundswrite@*/
00269     if (listptr) *listptr = fsnames;
00270     if (num) *num = numFilesystems;
00271 /*@=boundswrite@*/
00272 
00273     return 0;
00274 }
00275 
00276 int rpmGetFilesystemUsage(const char ** fileList, int_32 * fssizes, int numFiles,
00277                           uint_32 ** usagesPtr, /*@unused@*/ int flags)
00278 {
00279     int_32 * usages;
00280     int i, len, j;
00281     char * buf, * dirName;
00282     char * chptr;
00283     int maxLen;
00284     char * lastDir;
00285     const char * sourceDir;
00286     int lastfs = 0;
00287     int lastDev = -1;           /* I hope nobody uses -1 for a st_dev */
00288     struct stat sb;
00289 
00290     if (!fsnames) 
00291         if (getFilesystemList())
00292             return 1;
00293 
00294     usages = xcalloc(numFilesystems, sizeof(usages));
00295 
00296     sourceDir = rpmGetPath("%{_sourcedir}", NULL);
00297 
00298     maxLen = strlen(sourceDir);
00299 /*@-boundsread@*/
00300     for (i = 0; i < numFiles; i++) {
00301         len = strlen(fileList[i]);
00302         if (maxLen < len) maxLen = len;
00303     }
00304 /*@=boundsread@*/
00305     
00306 /*@-boundswrite@*/
00307     buf = alloca(maxLen + 1);
00308     lastDir = alloca(maxLen + 1);
00309     dirName = alloca(maxLen + 1);
00310     *lastDir = '\0';
00311 
00312     /* cut off last filename */
00313     for (i = 0; i < numFiles; i++) {
00314         if (*fileList[i] == '/') {
00315             strcpy(buf, fileList[i]);
00316             chptr = buf + strlen(buf) - 1;
00317             while (*chptr != '/') chptr--;
00318             if (chptr == buf)
00319                 buf[1] = '\0';
00320             else
00321                 *chptr-- = '\0';
00322         } else {
00323             /* this should only happen for source packages (gulp) */
00324             strcpy(buf,  sourceDir);
00325         }
00326 
00327         if (strcmp(lastDir, buf)) {
00328             strcpy(dirName, buf);
00329             chptr = dirName + strlen(dirName) - 1;
00330             while (stat(dirName, &sb)) {
00331                 if (errno != ENOENT) {
00332                     rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf,
00333                                 strerror(errno));
00334                     sourceDir = _free(sourceDir);
00335                     usages = _free(usages);
00336                     return 1;
00337                 }
00338 
00339                 /* cut off last directory part, because it was not found. */
00340                 while (*chptr != '/') chptr--;
00341 
00342                 if (chptr == dirName)
00343                     dirName[1] = '\0';
00344                 else
00345                     *chptr-- = '\0';
00346             }
00347 
00348             if (lastDev != sb.st_dev) {
00349                 for (j = 0; j < numFilesystems; j++)
00350                     if (filesystems && filesystems[j].dev == sb.st_dev)
00351                         /*@innerbreak@*/ break;
00352 
00353                 if (j == numFilesystems) {
00354                     rpmError(RPMERR_BADDEV, 
00355                                 _("file %s is on an unknown device\n"), buf);
00356                     sourceDir = _free(sourceDir);
00357                     usages = _free(usages);
00358                     return 1;
00359                 }
00360 
00361                 lastfs = j;
00362                 lastDev = sb.st_dev;
00363             }
00364         }
00365 
00366         strcpy(lastDir, buf);
00367         usages[lastfs] += fssizes[i];
00368     }
00369 /*@=boundswrite@*/
00370 
00371     sourceDir = _free(sourceDir);
00372 
00373 /*@-boundswrite@*/
00374     /*@-branchstate@*/
00375     if (usagesPtr)
00376         *usagesPtr = usages;
00377     else
00378         usages = _free(usages);
00379     /*@=branchstate@*/
00380 /*@=boundswrite@*/
00381 
00382     return 0;
00383 }
00384 /*@=usereleased =onlytrans@*/

Generated on Thu Oct 25 09:23:13 2007 for rpm by  doxygen 1.5.1