Abort transaction if there's not enough free space on disk.

Close #7.
This commit is contained in:
Juan RP 2014-07-13 11:45:04 +02:00
parent 79fe312302
commit 4356b6fd65
4 changed files with 40 additions and 5 deletions

5
NEWS
View File

@ -1,5 +1,10 @@
xbps-0.38 (???): xbps-0.38 (???):
* Before accepting a transaction, xbps now checks if there's enough free space
on the target rootdir (on disk) to proceed with the operation. In code terms,
xbps_transaction_prepare() now returns ENOSPC if the size of the transaction
exceeds the size of the free space. Close issue #7.
* When installing or updating packages, now proper statistics are generated * When installing or updating packages, now proper statistics are generated
when a binary package from a repository repository exists in the cachedir, when a binary package from a repository repository exists in the cachedir,
and when a package has the "preserve" property. and when a package has the "preserve" property.

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2013 Juan Romero Pardines. * Copyright (c) 2009-2014 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -97,7 +97,7 @@ show_package_list(xbps_object_iterator_t iter, const char *match, int cols)
static int static int
show_transaction_sizes(struct transaction *trans, int cols) show_transaction_sizes(struct transaction *trans, int cols)
{ {
uint64_t dlsize = 0, instsize = 0, rmsize = 0; uint64_t dlsize = 0, instsize = 0, rmsize = 0, disk_free_size = 0;
char size[8]; char size[8];
/* /*
@ -139,10 +139,10 @@ show_transaction_sizes(struct transaction *trans, int cols)
* Show total download/installed/removed size for all required packages. * Show total download/installed/removed size for all required packages.
*/ */
xbps_dictionary_get_uint64(trans->d, "total-download-size", &dlsize); xbps_dictionary_get_uint64(trans->d, "total-download-size", &dlsize);
xbps_dictionary_get_uint64(trans->d, "total-installed-size", xbps_dictionary_get_uint64(trans->d, "total-installed-size", &instsize);
&instsize);
xbps_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize); xbps_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize);
if (dlsize || instsize || rmsize) xbps_dictionary_get_uint64(trans->d, "disk-free-size", &disk_free_size);
if (dlsize || instsize || rmsize || disk_free_size)
printf("\n"); printf("\n");
if (dlsize) { if (dlsize) {
@ -169,6 +169,14 @@ show_transaction_sizes(struct transaction *trans, int cols)
} }
printf("Size freed on disk: %6s\n", size); printf("Size freed on disk: %6s\n", size);
} }
if (disk_free_size) {
if (xbps_humanize_number(size, (int64_t)disk_free_size) == -1) {
xbps_error_printf("humanize_number3 returns "
"%s\n", strerror(errno));
return -1;
}
printf("Free space on disk: %6s\n", size);
}
printf("\n"); printf("\n");
return 0; return 0;

View File

@ -1121,6 +1121,8 @@ int xbps_transaction_autoremove_pkgs(struct xbps_handle *xhp);
* array of strings object in xhp->transd dictionary). * array of strings object in xhp->transd dictionary).
* @retval EAGAIN if there are package conflicts in transaction ("conflicts" * @retval EAGAIN if there are package conflicts in transaction ("conflicts"
* array of strings object in xhp->transd dictionary). * array of strings object in xhp->transd dictionary).
* @retval ENOSPC Not enough free space on target rootdir to continue with the
* transaction.
* @retval EINVAL There was an error sorting packages or computing the transaction * @retval EINVAL There was an error sorting packages or computing the transaction
* sizes. * sizes.
*/ */

View File

@ -28,6 +28,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/statvfs.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
@ -58,6 +59,8 @@ compute_transaction_stats(struct xbps_handle *xhp)
xbps_dictionary_t pkg_metad; xbps_dictionary_t pkg_metad;
xbps_object_iterator_t iter; xbps_object_iterator_t iter;
xbps_object_t obj; xbps_object_t obj;
struct statvfs svfs;
unsigned long rootdir_free_size;
uint64_t tsize, dlsize, instsize, rmsize; uint64_t tsize, dlsize, instsize, rmsize;
uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt; uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt;
const char *tract, *pkgver, *repo; const char *tract, *pkgver, *repo;
@ -101,6 +104,8 @@ compute_transaction_stats(struct xbps_handle *xhp)
!xbps_binpkg_exists(xhp, obj)) { !xbps_binpkg_exists(xhp, obj)) {
xbps_dictionary_get_uint64(obj, xbps_dictionary_get_uint64(obj,
"filename-size", &tsize); "filename-size", &tsize);
/* signature file: 512 bytes */
tsize += 512;
dlsize += tsize; dlsize += tsize;
instsize += tsize; instsize += tsize;
} }
@ -159,6 +164,21 @@ compute_transaction_stats(struct xbps_handle *xhp)
"total-removed-size", rmsize)) "total-removed-size", rmsize))
return EINVAL; return EINVAL;
/* Get free space from target rootdir: return ENOSPC if there's not enough space */
if (statvfs(xhp->rootdir, &svfs) == -1) {
xbps_dbg_printf(xhp, "%s: statvfs failed: %s\n", __func__, strerror(errno));
return EINVAL;
}
/* compute free space on disk */
rootdir_free_size = svfs.f_bfree * svfs.f_bsize - instsize;
if (!xbps_dictionary_set_uint64(xhp->transd,
"disk-free-size", rootdir_free_size))
return EINVAL;
if (instsize > rootdir_free_size)
return ENOSPC;
return 0; return 0;
} }