rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

fs.c
Go to the documentation of this file.
1
5 #include "system.h"
6 #include <rpmio.h>
7 #include <rpmiotypes.h>
8 #include <rpmlog.h>
9 #include <rpmmacro.h> /* XXX for rpmGetPath */
10
11 #include "fs.h"
12
13 #include "debug.h"
14
15 /*@-usereleased -onlytrans@*/
16
17 struct fsinfo {
18 /*@only@*/ /*@relnull@*/
19 const char * mntPoint;
20 dev_t dev;
21 int rdonly;
22 };
23
24 /*@unchecked@*/
25 /*@only@*/ /*@null@*/
26 static struct fsinfo * filesystems = NULL;
27 /*@unchecked@*/
28 /*@only@*/ /*@null@*/
29 static const char ** fsnames = NULL;
30 /*@unchecked@*/
31 static int numFilesystems = 0;
32
33 void rpmFreeFilesystems(void)
34 /*@globals filesystems, fsnames, numFilesystems @*/
35 /*@modifies filesystems, fsnames, numFilesystems @*/
36 {
37 int i;
38
39 if (filesystems)
40 for (i = 0; i < numFilesystems; i++)
41 filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
42
43 filesystems = _free(filesystems);
44 fsnames = _free(fsnames);
45 numFilesystems = 0;
46 }
47
48 #if defined(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 rpmlog(RPMLOG_ERR, _("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 rpmlog(RPMLOG_ERR, _("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 defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
115 if (!(strcmp(fsn, "/proc") == 0)) {
116 #endif
117 if (Stat(fsn, &sb) < 0) {
118 switch(errno) {
119 default:
120 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), fsn,
121 strerror(errno));
122 rpmFreeFilesystems();
123 return 1;
124 case ENOENT: /* XXX avoid /proc if leaked into *BSD jails. */
125 sb.st_dev = 0; /* XXXX make sure st_dev is initialized. */
126 /*@switchbreak@*/ break;
127 }
128 }
129
130 filesystems[i].dev = sb.st_dev;
131 filesystems[i].rdonly = rdonly;
132 #if defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
133 }
134 #endif
135
136 /* goto the next vmount structure: */
137 vm = (struct vmount *)((char *)vm + vm->vmt_length);
138 }
139
140 filesystems[i].mntPoint = NULL;
141 fsnames[i] = NULL;
142
143 return 0;
144 }
145
146 #else /* HAVE_MNTCTL */
147
153 static int getFilesystemList(void)
154 /*@globals h_errno, filesystems, fsnames, numFilesystems,
155 fileSystem, internalState @*/
156 /*@modifies filesystems, fsnames, numFilesystems,
157 fileSystem, internalState @*/
158 {
159 int numAlloced = 10;
160 struct stat sb;
161 int i;
162 const char * mntdir;
163 int rdonly = 0;
164
165 # if GETMNTENT_ONE || GETMNTENT_TWO
166 our_mntent item;
167 FILE * mtab;
168
169 mtab = fopen(MOUNTED, "r");
170 if (!mtab) {
171 rpmlog(RPMLOG_ERR, _("failed to open %s: %s\n"), MOUNTED,
172 strerror(errno));
173 return 1;
174 }
175 # elif defined(HAVE_GETMNTINFO_R)
176 /* This is OSF */
177 struct statfs * mounts = NULL;
178 int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
179 int nextMount = 0;
180
181 getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
182 # elif defined(HAVE_GETMNTINFO)
183 /* This is Mac OS X */
184 #if defined(__NetBSD__)
185 struct statvfs * mounts = NULL;
186 #else
187 struct statfs * mounts = NULL;
188 #endif
189 int mntCount = 0, flags = MNT_NOWAIT;
190 int nextMount = 0;
191
192 /* XXX 0 on error, errno set */
193 mntCount = getmntinfo(&mounts, flags);
194 # endif
195
196 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems)); /* XXX memory leak */
197
198 numFilesystems = 0;
199 while (1) {
200 # if GETMNTENT_ONE
201 /* this is Linux */
202 /*@-modunconnomods -moduncon @*/
203 our_mntent * itemptr = getmntent(mtab);
204 if (!itemptr) break;
205 item = *itemptr; /* structure assignment */
206 mntdir = item.our_mntdir;
207 #if defined(MNTOPT_RO)
208 /*@-compdef@*/
209 if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
210 rdonly = 1;
211 /*@=compdef@*/
212 #endif
213 /*@=modunconnomods =moduncon @*/
214 # elif GETMNTENT_TWO
215 /* Solaris, maybe others */
216 if (getmntent(mtab, &item)) break;
217 mntdir = item.our_mntdir;
218 # elif defined(HAVE_GETMNTINFO_R)
219 /* This is OSF */
220 if (nextMount == mntCount) break;
221 mntdir = mounts[nextMount++].f_mntonname;
222 # elif defined(HAVE_GETMNTINFO)
223 /* This is Mac OS X */
224 if (nextMount == mntCount) break;
225 mntdir = mounts[nextMount++].f_mntonname;
226 # endif
227
228 #if defined(RPM_VENDOR_OPENPKG) /* always-skip-proc-filesystem */
229 if (strcmp(mntdir, "/proc") == 0)
230 continue;
231 #endif
232
233 if (Stat(mntdir, &sb) < 0) {
234 switch(errno) {
235 default:
236 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), mntdir,
237 strerror(errno));
238 rpmFreeFilesystems();
239 return 1;
240 /*@notreached@*/ /*@switchbreak@*/ break;
241 case ENOENT: /* XXX avoid /proc if leaked into *BSD jails. */
242 case EACCES: /* XXX fuse fs #220991 */
243 case ESTALE:
244 continue;
245 /*@notreached@*/ /*@switchbreak@*/ break;
246 }
247 }
248
249 if ((numFilesystems + 2) == numAlloced) {
250 numAlloced += 10;
251 filesystems = xrealloc(filesystems,
252 sizeof(*filesystems) * (numAlloced + 1));
253 }
254
255 filesystems[numFilesystems].dev = sb.st_dev;
256 filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
257 filesystems[numFilesystems].rdonly = rdonly;
258 #if 0
259 rpmlog(RPMLOG_DEBUG, _("%5d 0x%04x %s %s\n"),
260 numFilesystems,
261 (unsigned) filesystems[numFilesystems].dev,
262 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
263 filesystems[numFilesystems].mntPoint);
264 #endif
265 numFilesystems++;
266 }
267
268 # if GETMNTENT_ONE || GETMNTENT_TWO
269 (void) fclose(mtab);
270 # elif defined(HAVE_GETMNTINFO_R)
271 mounts = _free(mounts);
272 # endif
273
274 filesystems[numFilesystems].dev = 0;
275 filesystems[numFilesystems].mntPoint = NULL;
276 filesystems[numFilesystems].rdonly = 0;
277
278 fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
279 for (i = 0; i < numFilesystems; i++)
280 fsnames[i] = filesystems[i].mntPoint;
281 fsnames[numFilesystems] = NULL;
282
283 /*@-nullstate@*/ /* FIX: fsnames[] may be NULL */
284 return 0;
285 /*@=nullstate@*/
286 }
287 #endif /* HAVE_MNTCTL */
288
289 int rpmGetFilesystemList(const char *** listptr, rpmuint32_t * num)
290 {
291 if (!fsnames)
292 if (getFilesystemList())
293 return 1;
294
295 if (listptr) *listptr = fsnames;
296 if (num) *num = numFilesystems;
297
298 return 0;
299 }
300
301 int rpmGetFilesystemUsage(const char ** fileList, rpmuint32_t * fssizes,
302 int numFiles, rpmuint64_t ** usagesPtr,
303 /*@unused@*/ int flags)
304 {
305 rpmuint64_t * usages;
306 int i, j;
307 char * buf, * dirName;
308 char * chptr;
309 size_t maxLen;
310 size_t len;
311 char * lastDir;
312 const char * sourceDir;
313 int lastfs = 0;
314 dev_t lastDev = (dev_t)-1; /* I hope nobody uses -1 for a st_dev */
315 struct stat sb;
316 int rc = 1; /* assume failure */
317
318 if (!fsnames)
319 if (getFilesystemList())
320 return rc;
321
322 usages = xcalloc(numFilesystems, sizeof(*usages));
323
324 sourceDir = rpmGetPath("%{_sourcedir}", NULL);
325
326 maxLen = strlen(sourceDir);
327 for (i = 0; i < numFiles; i++) {
328 len = strlen(fileList[i]);
329 if (maxLen < len) maxLen = len;
330 }
331
332 buf = alloca(maxLen + 1);
333 lastDir = alloca(maxLen + 1);
334 dirName = alloca(maxLen + 1);
335 *lastDir = '\0';
336
337 /* cut off last filename */
338 for (i = 0; i < numFiles; i++) {
339 if (*fileList[i] == '/') {
340 strcpy(buf, fileList[i]);
341 chptr = buf + strlen(buf) - 1;
342 while (*chptr != '/') chptr--;
343 if (chptr == buf)
344 buf[1] = '\0';
345 else
346 *chptr-- = '\0';
347 } else {
348 /* this should only happen for source packages (gulp) */
349 strcpy(buf, sourceDir);
350 }
351
352 if (strcmp(lastDir, buf)) {
353 strcpy(dirName, buf);
354 chptr = dirName + strlen(dirName) - 1;
355 while (Stat(dirName, &sb) < 0) {
356 switch(errno) {
357 default:
358 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), buf,
359 strerror(errno));
360 goto exit;
361 /*@notreached@*/ /*@switchbreak@*/ break;
362 case ENOENT: /* XXX paths in empty chroot's don't exist. */
363 /*@switchbreak@*/ break;
364 }
365
366 /* cut off last directory part, because it was not found. */
367 while (*chptr != '/') chptr--;
368
369 if (chptr == dirName)
370 dirName[1] = '\0';
371 else
372 *chptr-- = '\0';
373 }
374
375 if (lastDev != sb.st_dev) {
376 for (j = 0; j < numFilesystems; j++)
377 if (filesystems && filesystems[j].dev == sb.st_dev)
378 /*@innerbreak@*/ break;
379
380 if (j == numFilesystems) {
381 rpmlog(RPMLOG_ERR,
382 _("file %s is on an unknown device\n"), buf);
383 goto exit;
384 }
385
386 lastfs = j;
387 lastDev = sb.st_dev;
388 }
389 }
390
391 strcpy(lastDir, buf);
392 usages[lastfs] += fssizes[i];
393 }
394 rc = 0;
395
396 exit:
397 sourceDir = _free(sourceDir);
398
399 if (rc == 0 && usagesPtr)
400 *usagesPtr = usages;
401 else
402 usages = _free(usages);
403
404 return rc;
405 }
406 /*@=usereleased =onlytrans@*/