rpm  4.5
fs.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 #include <rpmlib.h>
7 #include <rpmmacro.h> /* XXX for rpmGetPath */
8 
9 #include "fs.h"
10 
11 #include "debug.h"
12 
13 /*@-usereleased -onlytrans@*/
14 
15 struct fsinfo {
16 /*@only@*/ /*@relnull@*/
17  const char * mntPoint;
18  dev_t dev;
19  int rdonly;
20 };
21 
22 /*@unchecked@*/
23 /*@only@*/ /*@null@*/
24 static struct fsinfo * filesystems = NULL;
25 /*@unchecked@*/
26 /*@only@*/ /*@null@*/
27 static const char ** fsnames = NULL;
28 /*@unchecked@*/
29 static int numFilesystems = 0;
30 
32  /*@globals filesystems, fsnames, numFilesystems @*/
33  /*@modifies filesystems, fsnames, numFilesystems @*/
34 {
35  int i;
36 
37 /*@-boundswrite@*/
38  if (filesystems)
39  for (i = 0; i < numFilesystems; i++)
40  filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
41 /*@=boundswrite@*/
42 
43  filesystems = _free(filesystems);
45  numFilesystems = 0;
46 }
47 
48 #if HAVE_MNTCTL
49 
50 /* modeled after sample code from Till Bubeck */
51 
52 #include <sys/mntctl.h>
53 #include <sys/vmount.h>
54 
55 /*
56  * There is NO mntctl prototype in any header file of AIX 3.2.5!
57  * So we have to declare it by ourself...
58  */
59 int mntctl(int command, int size, char *buffer);
60 
66 static int getFilesystemList(void)
67  /*@*/
68 {
69  int size;
70  void * buf;
71  struct vmount * vm;
72  struct stat sb;
73  int rdonly = 0;
74  int num;
75  int fsnameLength;
76  int i;
77 
78  num = mntctl(MCTL_QUERY, sizeof(size), (char *) &size);
79  if (num < 0) {
80  rpmError(RPMERR_MTAB, _("mntctl() failed to return size: %s\n"),
81  strerror(errno));
82  return 1;
83  }
84 
85  /*
86  * Double the needed size, so that even when the user mounts a
87  * filesystem between the previous and the next call to mntctl
88  * the buffer still is large enough.
89  */
90  size *= 2;
91 
92  buf = alloca(size);
93  num = mntctl(MCTL_QUERY, size, buf);
94  if ( num <= 0 ) {
95  rpmError(RPMERR_MTAB, _("mntctl() failed to return mount points: %s\n"),
96  strerror(errno));
97  return 1;
98  }
99 
100  numFilesystems = num;
101 
102  filesystems = xcalloc((numFilesystems + 1), sizeof(*filesystems));
103  fsnames = xcalloc((numFilesystems + 1), sizeof(char *));
104 
105  for (vm = buf, i = 0; i < num; i++) {
106  char *fsn;
107  fsnameLength = vm->vmt_data[VMT_STUB].vmt_size;
108  fsn = xmalloc(fsnameLength + 1);
109  strncpy(fsn, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
110  fsnameLength);
111 
112  filesystems[i].mntPoint = fsnames[i] = fsn;
113 
114  if (stat(filesystems[i].mntPoint, &sb)) {
115  rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), fsnames[i],
116  strerror(errno));
117 
119  return 1;
120  }
121 
122  filesystems[i].dev = sb.st_dev;
123  filesystems[i].rdonly = rdonly;
124 
125  /* goto the next vmount structure: */
126  vm = (struct vmount *)((char *)vm + vm->vmt_length);
127  }
128 
129  filesystems[i].mntPoint = NULL;
130  fsnames[i] = NULL;
131 
132  return 0;
133 }
134 
135 #else /* HAVE_MNTCTL */
136 
142 static int getFilesystemList(void)
143  /*@globals filesystems, fsnames, numFilesystems,
144  fileSystem, internalState @*/
145  /*@modifies filesystems, fsnames, numFilesystems,
146  fileSystem, internalState @*/
147 {
148  int numAlloced = 10;
149  struct stat sb;
150  int i;
151  const char * mntdir;
152  int rdonly = 0;
153 
154 # if GETMNTENT_ONE || GETMNTENT_TWO
155  our_mntent item;
156  FILE * mtab;
157 
158  mtab = fopen(MOUNTED, "r");
159  if (!mtab) {
160  rpmError(RPMERR_MTAB, _("failed to open %s: %s\n"), MOUNTED,
161  strerror(errno));
162  return 1;
163  }
164 # elif HAVE_GETMNTINFO_R
165  /* This is OSF */
166  struct statfs * mounts = NULL;
167  int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
168  int nextMount = 0;
169 
170  getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
171 # elif HAVE_GETMNTINFO
172  /* This is Mac OS X */
173  struct statfs * mounts = NULL;
174  int mntCount = 0, flags = MNT_NOWAIT;
175  int nextMount = 0;
176 
177  /* XXX 0 on error, errno set */
178  mntCount = getmntinfo(&mounts, flags);
179 # endif
180 
181  filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems)); /* XXX memory leak */
182 
183  numFilesystems = 0;
184  while (1) {
185 # if GETMNTENT_ONE
186  /* this is Linux */
187  /*@-modunconnomods -moduncon @*/
188  our_mntent * itemptr = getmntent(mtab);
189  if (!itemptr) break;
190 /*@-boundsread@*/
191  item = *itemptr; /* structure assignment */
192 /*@=boundsread@*/
193  mntdir = item.our_mntdir;
194 #if defined(MNTOPT_RO)
195  /*@-compdef@*/
196  if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
197  rdonly = 1;
198  /*@=compdef@*/
199 #endif
200  /*@=modunconnomods =moduncon @*/
201 # elif GETMNTENT_TWO
202  /* Solaris, maybe others */
203  if (getmntent(mtab, &item)) break;
204  mntdir = item.our_mntdir;
205 # elif HAVE_GETMNTINFO_R
206  /* This is OSF */
207  if (nextMount == mntCount) break;
208  mntdir = mounts[nextMount++].f_mntonname;
209 # elif HAVE_GETMNTINFO
210  /* This is Mac OS X */
211  if (nextMount == mntCount) break;
212  mntdir = mounts[nextMount++].f_mntonname;
213 # endif
214 
215  if (stat(mntdir, &sb)) {
216  switch(errno) {
217  default:
218  rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), mntdir,
219  strerror(errno));
221  return 1;
222  /*@notreached@*/ /*@switchbreak@*/ break;
223  case EACCES: /* XXX fuse fs #220991 */
224  case ESTALE:
225  continue;
226  /*@notreached@*/ /*@switchbreak@*/ break;
227  }
228  }
229 
230  if ((numFilesystems + 2) == numAlloced) {
231  numAlloced += 10;
232  filesystems = xrealloc(filesystems,
233  sizeof(*filesystems) * (numAlloced + 1));
234  }
235 
236  filesystems[numFilesystems].dev = sb.st_dev;
237  filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
238  filesystems[numFilesystems].rdonly = rdonly;
239 #if 0
240  rpmMessage(RPMMESS_DEBUG, "%5d 0x%04x %s %s\n",
242  (unsigned) filesystems[numFilesystems].dev,
243  (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
244  filesystems[numFilesystems].mntPoint);
245 #endif
246  numFilesystems++;
247  }
248 
249 # if GETMNTENT_ONE || GETMNTENT_TWO
250  (void) fclose(mtab);
251 # elif HAVE_GETMNTINFO_R
252  mounts = _free(mounts);
253 # endif
254 
255  filesystems[numFilesystems].dev = 0;
256  filesystems[numFilesystems].mntPoint = NULL;
257  filesystems[numFilesystems].rdonly = 0;
258 
259 /*@-boundswrite@*/
260  fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
261  for (i = 0; i < numFilesystems; i++)
262  fsnames[i] = filesystems[i].mntPoint;
263  fsnames[numFilesystems] = NULL;
264 /*@=boundswrite@*/
265 
266 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */
267  return 0;
268 /*@=nullstate@*/
269 }
270 #endif /* HAVE_MNTCTL */
271 
272 int rpmGetFilesystemList(const char *** listptr, int * num)
273 {
274  if (!fsnames)
275  if (getFilesystemList())
276  return 1;
277 
278 /*@-boundswrite@*/
279  if (listptr) *listptr = fsnames;
280  if (num) *num = numFilesystems;
281 /*@=boundswrite@*/
282 
283  return 0;
284 }
285 
286 int rpmGetFilesystemUsage(const char ** fileList, uint_32 * fssizes, int numFiles,
287  uint_64 ** usagesPtr, /*@unused@*/ int flags)
288 {
289  uint_64 * usages;
290  int i, len, j;
291  char * buf, * dirName;
292  char * chptr;
293  int maxLen;
294  char * lastDir;
295  const char * sourceDir;
296  int lastfs = 0;
297  int lastDev = -1; /* I hope nobody uses -1 for a st_dev */
298  struct stat sb;
299 
300  if (!fsnames)
301  if (getFilesystemList())
302  return 1;
303 
304  usages = xcalloc(numFilesystems, sizeof(*usages));
305 
306  sourceDir = rpmGetPath("%{_sourcedir}", NULL);
307 
308  maxLen = strlen(sourceDir);
309 /*@-boundsread@*/
310  for (i = 0; i < numFiles; i++) {
311  len = strlen(fileList[i]);
312  if (maxLen < len) maxLen = len;
313  }
314 /*@=boundsread@*/
315 
316 /*@-boundswrite@*/
317  buf = alloca(maxLen + 1);
318  lastDir = alloca(maxLen + 1);
319  dirName = alloca(maxLen + 1);
320  *lastDir = '\0';
321 
322  /* cut off last filename */
323  for (i = 0; i < numFiles; i++) {
324  if (*fileList[i] == '/') {
325  strcpy(buf, fileList[i]);
326  chptr = buf + strlen(buf) - 1;
327  while (*chptr != '/') chptr--;
328  if (chptr == buf)
329  buf[1] = '\0';
330  else
331  *chptr-- = '\0';
332  } else {
333  /* this should only happen for source packages (gulp) */
334  strcpy(buf, sourceDir);
335  }
336 
337  if (strcmp(lastDir, buf)) {
338  strcpy(dirName, buf);
339  chptr = dirName + strlen(dirName) - 1;
340  while (stat(dirName, &sb)) {
341  if (errno != ENOENT) {
342  rpmError(RPMERR_STAT, _("failed to stat %s: %s\n"), buf,
343  strerror(errno));
344  sourceDir = _free(sourceDir);
345  usages = _free(usages);
346  return 1;
347  }
348 
349  /* cut off last directory part, because it was not found. */
350  while (*chptr != '/') chptr--;
351 
352  if (chptr == dirName)
353  dirName[1] = '\0';
354  else
355  *chptr-- = '\0';
356  }
357 
358  if (lastDev != sb.st_dev) {
359  for (j = 0; j < numFilesystems; j++)
360  if (filesystems && filesystems[j].dev == sb.st_dev)
361  /*@innerbreak@*/ break;
362 
363  if (j == numFilesystems) {
365  _("file %s is on an unknown device\n"), buf);
366  sourceDir = _free(sourceDir);
367  usages = _free(usages);
368  return 1;
369  }
370 
371  lastfs = j;
372  lastDev = sb.st_dev;
373  }
374  }
375 
376  strcpy(lastDir, buf);
377  usages[lastfs] += fssizes[i];
378  }
379 /*@=boundswrite@*/
380 
381  sourceDir = _free(sourceDir);
382 
383 /*@-boundswrite@*/
384  /*@-branchstate@*/
385  if (usagesPtr)
386  *usagesPtr = usages;
387  else
388  usages = _free(usages);
389  /*@=branchstate@*/
390 /*@=boundswrite@*/
391 
392  return 0;
393 }
394 /*@=usereleased =onlytrans@*/