00001
00005 #include "system.h"
00006 #include <rpmio.h>
00007 #include <rpmiotypes.h>
00008 #include <rpmlog.h>
00009 #include <rpmmacro.h>
00010
00011 #include "fs.h"
00012
00013 #include "debug.h"
00014
00015
00016
00017 struct fsinfo {
00018
00019 const char * mntPoint;
00020 dev_t dev;
00021 int rdonly;
00022 };
00023
00024
00025
00026 static struct fsinfo * filesystems = NULL;
00027
00028
00029 static const char ** fsnames = NULL;
00030
00031 static int numFilesystems = 0;
00032
00033 void rpmFreeFilesystems(void)
00034
00035
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
00051
00052 #include <sys/mntctl.h>
00053 #include <sys/vmount.h>
00054
00055
00056
00057
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
00087
00088
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)
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:
00125 sb.st_dev = 0;
00126 break;
00127 }
00128 }
00129
00130 filesystems[i].dev = sb.st_dev;
00131 filesystems[i].rdonly = rdonly;
00132 #if defined(RPM_VENDOR_OPENPKG)
00133 }
00134 #endif
00135
00136
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
00147
00153 static int getFilesystemList(void)
00154
00155
00156
00157
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
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
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
00193 mntCount = getmntinfo(&mounts, flags);
00194 # endif
00195
00196 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));
00197
00198 numFilesystems = 0;
00199 while (1) {
00200 # if GETMNTENT_ONE
00201
00202
00203 our_mntent * itemptr = getmntent(mtab);
00204 if (!itemptr) break;
00205 item = *itemptr;
00206 mntdir = item.our_mntdir;
00207 #if defined(MNTOPT_RO)
00208
00209 if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
00210 rdonly = 1;
00211
00212 #endif
00213
00214 # elif GETMNTENT_TWO
00215
00216 if (getmntent(mtab, &item)) break;
00217 mntdir = item.our_mntdir;
00218 # elif defined(HAVE_GETMNTINFO_R)
00219
00220 if (nextMount == mntCount) break;
00221 mntdir = mounts[nextMount++].f_mntonname;
00222 # elif defined(HAVE_GETMNTINFO)
00223
00224 if (nextMount == mntCount) break;
00225 mntdir = mounts[nextMount++].f_mntonname;
00226 # endif
00227
00228 #if defined(RPM_VENDOR_OPENPKG)
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 break;
00241 case ENOENT:
00242 case EACCES:
00243 case ESTALE:
00244 continue;
00245 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
00284 return 0;
00285
00286 }
00287 #endif
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 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;
00315 struct stat sb;
00316 int rc = 1;
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
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
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 break;
00362 case ENOENT:
00363 break;
00364 }
00365
00366
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 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