rpm
4.5
|
00001 00005 #include "system.h" 00006 #include <rpmlib.h> 00007 #include <rpmmacro.h> /* XXX for rpmGetPath */ 00008 00009 #include "fs.h" 00010 00011 #include "debug.h" 00012 00013 /*@-usereleased -onlytrans@*/ 00014 00015 struct fsinfo { 00016 /*@only@*/ /*@relnull@*/ 00017 const char * mntPoint; 00018 dev_t dev; 00019 int rdonly; 00020 }; 00021 00022 /*@unchecked@*/ 00023 /*@only@*/ /*@null@*/ 00024 static struct fsinfo * filesystems = NULL; 00025 /*@unchecked@*/ 00026 /*@only@*/ /*@null@*/ 00027 static const char ** fsnames = NULL; 00028 /*@unchecked@*/ 00029 static int numFilesystems = 0; 00030 00031 void rpmFreeFilesystems(void) 00032 /*@globals filesystems, fsnames, numFilesystems @*/ 00033 /*@modifies filesystems, fsnames, numFilesystems @*/ 00034 { 00035 int i; 00036 00037 /*@-boundswrite@*/ 00038 if (filesystems) 00039 for (i = 0; i < numFilesystems; i++) 00040 filesystems[i].mntPoint = _free(filesystems[i].mntPoint); 00041 /*@=boundswrite@*/ 00042 00043 filesystems = _free(filesystems); 00044 fsnames = _free(fsnames); 00045 numFilesystems = 0; 00046 } 00047 00048 #if 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 rpmError(RPMERR_MTAB, _("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 rpmError(RPMERR_MTAB, _("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 (stat(filesystems[i].mntPoint, &sb)) { 00115 rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), fsnames[i], 00116 strerror(errno)); 00117 00118 rpmFreeFilesystems(); 00119 return 1; 00120 } 00121 00122 filesystems[i].dev = sb.st_dev; 00123 filesystems[i].rdonly = rdonly; 00124 00125 /* goto the next vmount structure: */ 00126 vm = (struct vmount *)((char *)vm + vm->vmt_length); 00127 } 00128 00129 filesystems[i].mntPoint = NULL; 00130 fsnames[i] = NULL; 00131 00132 return 0; 00133 } 00134 00135 #else /* HAVE_MNTCTL */ 00136 00142 static int getFilesystemList(void) 00143 /*@globals filesystems, fsnames, numFilesystems, 00144 fileSystem, internalState @*/ 00145 /*@modifies filesystems, fsnames, numFilesystems, 00146 fileSystem, internalState @*/ 00147 { 00148 int numAlloced = 10; 00149 struct stat sb; 00150 int i; 00151 const char * mntdir; 00152 int rdonly = 0; 00153 00154 # if GETMNTENT_ONE || GETMNTENT_TWO 00155 our_mntent item; 00156 FILE * mtab; 00157 00158 mtab = fopen(MOUNTED, "r"); 00159 if (!mtab) { 00160 rpmError(RPMERR_MTAB, _("failed to open %s: %s\n"), MOUNTED, 00161 strerror(errno)); 00162 return 1; 00163 } 00164 # elif HAVE_GETMNTINFO_R 00165 /* This is OSF */ 00166 struct statfs * mounts = NULL; 00167 int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT; 00168 int nextMount = 0; 00169 00170 getmntinfo_r(&mounts, flags, &mntCount, &bufSize); 00171 # elif HAVE_GETMNTINFO 00172 /* This is Mac OS X */ 00173 struct statfs * mounts = NULL; 00174 int mntCount = 0, flags = MNT_NOWAIT; 00175 int nextMount = 0; 00176 00177 /* XXX 0 on error, errno set */ 00178 mntCount = getmntinfo(&mounts, flags); 00179 # endif 00180 00181 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems)); /* XXX memory leak */ 00182 00183 numFilesystems = 0; 00184 while (1) { 00185 # if GETMNTENT_ONE 00186 /* this is Linux */ 00187 /*@-modunconnomods -moduncon @*/ 00188 our_mntent * itemptr = getmntent(mtab); 00189 if (!itemptr) break; 00190 /*@-boundsread@*/ 00191 item = *itemptr; /* structure assignment */ 00192 /*@=boundsread@*/ 00193 mntdir = item.our_mntdir; 00194 #if defined(MNTOPT_RO) 00195 /*@-compdef@*/ 00196 if (hasmntopt(itemptr, MNTOPT_RO) != NULL) 00197 rdonly = 1; 00198 /*@=compdef@*/ 00199 #endif 00200 /*@=modunconnomods =moduncon @*/ 00201 # elif GETMNTENT_TWO 00202 /* Solaris, maybe others */ 00203 if (getmntent(mtab, &item)) break; 00204 mntdir = item.our_mntdir; 00205 # elif HAVE_GETMNTINFO_R 00206 /* This is OSF */ 00207 if (nextMount == mntCount) break; 00208 mntdir = mounts[nextMount++].f_mntonname; 00209 # elif HAVE_GETMNTINFO 00210 /* This is Mac OS X */ 00211 if (nextMount == mntCount) break; 00212 mntdir = mounts[nextMount++].f_mntonname; 00213 # endif 00214 00215 if (stat(mntdir, &sb)) { 00216 switch(errno) { 00217 default: 00218 rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), mntdir, 00219 strerror(errno)); 00220 rpmFreeFilesystems(); 00221 return 1; 00222 /*@notreached@*/ /*@switchbreak@*/ break; 00223 case EACCES: /* XXX fuse fs #220991 */ 00224 case ESTALE: 00225 continue; 00226 /*@notreached@*/ /*@switchbreak@*/ break; 00227 } 00228 } 00229 00230 if ((numFilesystems + 2) == numAlloced) { 00231 numAlloced += 10; 00232 filesystems = xrealloc(filesystems, 00233 sizeof(*filesystems) * (numAlloced + 1)); 00234 } 00235 00236 filesystems[numFilesystems].dev = sb.st_dev; 00237 filesystems[numFilesystems].mntPoint = xstrdup(mntdir); 00238 filesystems[numFilesystems].rdonly = rdonly; 00239 #if 0 00240 rpmMessage(RPMMESS_DEBUG, "%5d 0x%04x %s %s\n", 00241 numFilesystems, 00242 (unsigned) filesystems[numFilesystems].dev, 00243 (filesystems[numFilesystems].rdonly ? "ro" : "rw"), 00244 filesystems[numFilesystems].mntPoint); 00245 #endif 00246 numFilesystems++; 00247 } 00248 00249 # if GETMNTENT_ONE || GETMNTENT_TWO 00250 (void) fclose(mtab); 00251 # elif HAVE_GETMNTINFO_R 00252 mounts = _free(mounts); 00253 # endif 00254 00255 filesystems[numFilesystems].dev = 0; 00256 filesystems[numFilesystems].mntPoint = NULL; 00257 filesystems[numFilesystems].rdonly = 0; 00258 00259 /*@-boundswrite@*/ 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 /*@=boundswrite@*/ 00265 00266 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */ 00267 return 0; 00268 /*@=nullstate@*/ 00269 } 00270 #endif /* HAVE_MNTCTL */ 00271 00272 int rpmGetFilesystemList(const char *** listptr, int * num) 00273 { 00274 if (!fsnames) 00275 if (getFilesystemList()) 00276 return 1; 00277 00278 /*@-boundswrite@*/ 00279 if (listptr) *listptr = fsnames; 00280 if (num) *num = numFilesystems; 00281 /*@=boundswrite@*/ 00282 00283 return 0; 00284 } 00285 00286 int rpmGetFilesystemUsage(const char ** fileList, uint_32 * fssizes, int numFiles, 00287 uint_64 ** usagesPtr, /*@unused@*/ int flags) 00288 { 00289 uint_64 * usages; 00290 int i, len, j; 00291 char * buf, * dirName; 00292 char * chptr; 00293 int maxLen; 00294 char * lastDir; 00295 const char * sourceDir; 00296 int lastfs = 0; 00297 int lastDev = -1; /* I hope nobody uses -1 for a st_dev */ 00298 struct stat sb; 00299 00300 if (!fsnames) 00301 if (getFilesystemList()) 00302 return 1; 00303 00304 usages = xcalloc(numFilesystems, sizeof(*usages)); 00305 00306 sourceDir = rpmGetPath("%{_sourcedir}", NULL); 00307 00308 maxLen = strlen(sourceDir); 00309 /*@-boundsread@*/ 00310 for (i = 0; i < numFiles; i++) { 00311 len = strlen(fileList[i]); 00312 if (maxLen < len) maxLen = len; 00313 } 00314 /*@=boundsread@*/ 00315 00316 /*@-boundswrite@*/ 00317 buf = alloca(maxLen + 1); 00318 lastDir = alloca(maxLen + 1); 00319 dirName = alloca(maxLen + 1); 00320 *lastDir = '\0'; 00321 00322 /* cut off last filename */ 00323 for (i = 0; i < numFiles; i++) { 00324 if (*fileList[i] == '/') { 00325 strcpy(buf, fileList[i]); 00326 chptr = buf + strlen(buf) - 1; 00327 while (*chptr != '/') chptr--; 00328 if (chptr == buf) 00329 buf[1] = '\0'; 00330 else 00331 *chptr-- = '\0'; 00332 } else { 00333 /* this should only happen for source packages (gulp) */ 00334 strcpy(buf, sourceDir); 00335 } 00336 00337 if (strcmp(lastDir, buf)) { 00338 strcpy(dirName, buf); 00339 chptr = dirName + strlen(dirName) - 1; 00340 while (stat(dirName, &sb)) { 00341 if (errno != ENOENT) { 00342 rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf, 00343 strerror(errno)); 00344 sourceDir = _free(sourceDir); 00345 usages = _free(usages); 00346 return 1; 00347 } 00348 00349 /* cut off last directory part, because it was not found. */ 00350 while (*chptr != '/') chptr--; 00351 00352 if (chptr == dirName) 00353 dirName[1] = '\0'; 00354 else 00355 *chptr-- = '\0'; 00356 } 00357 00358 if (lastDev != sb.st_dev) { 00359 for (j = 0; j < numFilesystems; j++) 00360 if (filesystems && filesystems[j].dev == sb.st_dev) 00361 /*@innerbreak@*/ break; 00362 00363 if (j == numFilesystems) { 00364 rpmError(RPMERR_BADDEV, 00365 _("file %s is on an unknown device\n"), buf); 00366 sourceDir = _free(sourceDir); 00367 usages = _free(usages); 00368 return 1; 00369 } 00370 00371 lastfs = j; 00372 lastDev = sb.st_dev; 00373 } 00374 } 00375 00376 strcpy(lastDir, buf); 00377 usages[lastfs] += fssizes[i]; 00378 } 00379 /*@=boundswrite@*/ 00380 00381 sourceDir = _free(sourceDir); 00382 00383 /*@-boundswrite@*/ 00384 /*@-branchstate@*/ 00385 if (usagesPtr) 00386 *usagesPtr = usages; 00387 else 00388 usages = _free(usages); 00389 /*@=branchstate@*/ 00390 /*@=boundswrite@*/ 00391 00392 return 0; 00393 } 00394 /*@=usereleased =onlytrans@*/