00001
00005 #include "system.h"
00006 #include <rpmlib.h>
00007 #include <rpmmacro.h>
00008
00009 #include "fs.h"
00010
00011 #include "debug.h"
00012
00013
00014
00015 struct fsinfo {
00016
00017 const char * mntPoint;
00018 dev_t dev;
00019 int rdonly;
00020 };
00021
00022
00023
00024 static struct fsinfo * filesystems = NULL;
00025
00026
00027 static const char ** fsnames = NULL;
00028
00029 static int numFilesystems = 0;
00030
00031 void rpmFreeFilesystems(void)
00032
00033
00034 {
00035 int i;
00036
00037
00038 if (filesystems)
00039 for (i = 0; i < numFilesystems; i++)
00040 filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
00041
00042
00043 filesystems = _free(filesystems);
00044 fsnames = _free(fsnames);
00045 numFilesystems = 0;
00046 }
00047
00048 #if 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 rpmError(RPMERR_MTAB, _("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 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
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
00136
00142 static int getFilesystemList(void)
00143
00144
00145
00146
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
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
00173 struct statfs * mounts = NULL;
00174 int mntCount = 0, flags = MNT_NOWAIT;
00175 int nextMount = 0;
00176
00177
00178 mntCount = getmntinfo(&mounts, flags);
00179 # endif
00180
00181 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems));
00182
00183 numFilesystems = 0;
00184 while (1) {
00185 # if GETMNTENT_ONE
00186
00187
00188 our_mntent * itemptr = getmntent(mtab);
00189 if (!itemptr) break;
00190
00191 item = *itemptr;
00192
00193 mntdir = item.our_mntdir;
00194 #if defined(MNTOPT_RO)
00195
00196 if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
00197 rdonly = 1;
00198
00199 #endif
00200
00201 # elif GETMNTENT_TWO
00202
00203 if (getmntent(mtab, &item)) break;
00204 mntdir = item.our_mntdir;
00205 # elif HAVE_GETMNTINFO_R
00206
00207 if (nextMount == mntCount) break;
00208 mntdir = mounts[nextMount++].f_mntonname;
00209 # elif HAVE_GETMNTINFO
00210
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 break;
00223 case EACCES:
00224 case ESTALE:
00225 continue;
00226 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
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
00265
00266
00267 return 0;
00268
00269 }
00270 #endif
00271
00272 int rpmGetFilesystemList(const char *** listptr, int * num)
00273 {
00274 if (!fsnames)
00275 if (getFilesystemList())
00276 return 1;
00277
00278
00279 if (listptr) *listptr = fsnames;
00280 if (num) *num = numFilesystems;
00281
00282
00283 return 0;
00284 }
00285
00286 int rpmGetFilesystemUsage(const char ** fileList, uint_32 * fssizes, int numFiles,
00287 uint_64 ** usagesPtr, 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;
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
00310 for (i = 0; i < numFiles; i++) {
00311 len = strlen(fileList[i]);
00312 if (maxLen < len) maxLen = len;
00313 }
00314
00315
00316
00317 buf = alloca(maxLen + 1);
00318 lastDir = alloca(maxLen + 1);
00319 dirName = alloca(maxLen + 1);
00320 *lastDir = '\0';
00321
00322
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
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
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 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
00380
00381 sourceDir = _free(sourceDir);
00382
00383
00384
00385 if (usagesPtr)
00386 *usagesPtr = usages;
00387 else
00388 usages = _free(usages);
00389
00390
00391
00392 return 0;
00393 }
00394