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