Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/fs.c

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

Generated on Tue Sep 17 15:59:48 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002