diff options
author | skydrome | 2015-06-01 15:47:44 -0400 |
---|---|---|
committer | skydrome | 2015-06-01 15:47:44 -0400 |
commit | dfe7859f845cabe6ea68ea8d38290450cd52d0bd (patch) | |
tree | a776e6187aa8f672bdb405d4e6d717ce89535fca | |
download | aur-dfe7859f845cabe6ea68ea8d38290450cd52d0bd.tar.gz |
Initial commit
-rw-r--r-- | .SRCINFO | 46 | ||||
-rwxr-xr-x | 0001-multiple-introducer-support.patch | 305 | ||||
-rwxr-xr-x | 0002-proxy-support.patch | 36 | ||||
-rwxr-xr-x | 0003-allow-non-routable.patch | 34 | ||||
-rwxr-xr-x | PKGBUILD | 87 | ||||
-rwxr-xr-x | exclude_buildtest_package.patch | 38 | ||||
-rwxr-xr-x | tahoe-repair-all.sh | 50 |
7 files changed, 596 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..01c13332163a --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,46 @@ +pkgbase = tahoe-lafs-i2p + pkgdesc = Secure, decentralized, and fault-tolerant filesystem over the I2P network + pkgver = 1.10.0.post26 + pkgrel = 1 + url = http://tahoe-lafs.org + arch = any + license = GPL + depends = python2-twisted + depends = python2-foolscap-i2p + depends = python2-mock + depends = python2-pyopenssl>=0.14 + depends = python2-pyasn1 + depends = python2-pyasn1-modules + depends = python2-crypto + depends = python2-cryptography + depends = python2-zope-interface + depends = python2-setuptools<0.8 + depends = python2-characteristic + depends = python2-service-identity + depends = python2-numpy + depends = pycryptopp + depends = pyutil + depends = python2-simplejson + depends = python2-cffi + depends = python2-enum34 + depends = python2-pycparser + depends = python2-six + depends = libffi + depends = net-tools + depends = nevow + depends = zbase32 + depends = zfec + optdepends = grid-updates: helps keep you up to date with latest grid news + provides = tahoe-lafs + conflicts = tahoe-lafs + source = https://tahoe-lafs.org/source/tahoe-lafs/snapshots/allmydata-tahoe-1.10.0.post26.tar.bz2 + source = exclude_buildtest_package.patch + source = http://killyourtv.i2p.us/tahoe-lafs/patches/tahoe-lafs-i2p-1.10.0-r0.patch + source = tahoe-repair-all.sh + sha256sums = 542830908e6deb66767ef98271bcf067f9787c0013b764caae23c7649b4f3171 + sha256sums = 469aa0ace523b64449e7d2d52958119a84032c50b07828b3dffbb81dca5327bd + sha256sums = 425456a08477da50ef1511ea1b24cc6a529c4abaae345a3da89a31c025d74b80 + sha256sums = 1525fd5c2ac2c93844f23160e70bb47040a9a8ee7dff8b6fff8ca48b374ac216 + +pkgname = tahoe-lafs-i2p + diff --git a/0001-multiple-introducer-support.patch b/0001-multiple-introducer-support.patch new file mode 100755 index 000000000000..4154cb017035 --- /dev/null +++ b/0001-multiple-introducer-support.patch @@ -0,0 +1,305 @@ +From: Kill Your TV <killyourtv@i2pmail.org> +Date: Wed, 27 Jun 2012 20:59:05 +0000 +Subject: multiple introducer support + +--- + docs/architecture.rst | 8 +++-- + docs/configuration.rst | 12 +++++-- + src/allmydata/client.py | 70 +++++++++++++++++++++++++++++++++------ + src/allmydata/test/test_web.py | 6 ++-- + src/allmydata/web/root.py | 26 +++++++++++---- + src/allmydata/web/welcome.xhtml | 27 +++++++++++---- + 6 files changed, 118 insertions(+), 31 deletions(-) + +diff --git a/docs/architecture.rst b/docs/architecture.rst +index 9e016e0..d1fba50 100644 +--- a/docs/architecture.rst ++++ b/docs/architecture.rst +@@ -78,9 +78,13 @@ private key, which are easy to move to a new host in case the original one + suffers an unrecoverable hardware problem. Second, even if the private key is + lost, clients can be reconfigured to use a new introducer. + +-For future releases, we have plans to decentralize introduction, allowing any +-server to tell a new client about all the others. ++By deploying multiple introducers in a Tahoe-LAFS grid, the above SPoF challenge ++can be overcome. In that case if one introducer fails clients are still be ++able to get announcement about new servers from remaining introducers. This is ++our first step towards implementing a fully distributed introduction. + ++For future releases, we have plans to enhance our distributed introduction, ++allowing any server to tell a new client about all the others. + + File Encoding + ============= +diff --git a/docs/configuration.rst b/docs/configuration.rst +index 31962d4..3f8f5eb 100644 +--- a/docs/configuration.rst ++++ b/docs/configuration.rst +@@ -33,6 +33,12 @@ create-client``" command will create an initial ``tahoe.cfg`` file for + you. After creation, the node will never modify the ``tahoe.cfg`` file: all + persistent state is put in other files. + ++A second file "BASEDIR/introducers" configures introducers. It is necessary to ++write all FURL entries into this file. Each line in this file contains exactly ++one FURL entry. For backward compatibility reasons, any "introducer.furl" ++entry found in tahoe.cfg file will automatically be copied into this file. Keeping ++any FURL entry in tahoe.cfg file is not recommended for new users. ++ + The item descriptions below use the following types: + + ``boolean`` +@@ -665,16 +671,16 @@ a legal one. + timeout.disconnect = 1800 + ssh.port = 8022 + ssh.authorized_keys_file = ~/.ssh/authorized_keys +- ++ + [client] + introducer.furl = pb://ok45ssoklj4y7eok5c3xkmj@tahoe.example:44801/ii3uumo + helper.furl = pb://ggti5ssoklj4y7eok5c3xkmj@helper.tahoe.example:7054/kk8lhr +- ++ + [storage] + enabled = True + readonly = True + reserved_space = 10000000000 +- ++ + [helper] + enabled = True + +diff --git a/src/allmydata/client.py b/src/allmydata/client.py +index b78fd7b..7200856 100644 +--- a/src/allmydata/client.py ++++ b/src/allmydata/client.py +@@ -35,6 +35,8 @@ GiB=1024*MiB + TiB=1024*GiB + PiB=1024*TiB + ++MULTI_INTRODUCERS_CFG = "introducers" ++ + class StubClient(Referenceable): + implements(RIStubClient) + +@@ -137,7 +139,7 @@ class Client(node.Node, pollmixin.PollMixin): + self.started_timestamp = time.time() + self.logSource="Client" + self.DEFAULT_ENCODING_PARAMETERS = self.DEFAULT_ENCODING_PARAMETERS.copy() +- self.init_introducer_client() ++ self.init_introducer_clients() + self.init_stats_provider() + self.init_secrets() + self.init_storage() +@@ -169,13 +171,47 @@ class Client(node.Node, pollmixin.PollMixin): + if webport: + self.init_web(webport) # strports string + +- def init_introducer_client(self): +- self.introducer_furl = self.get_config("client", "introducer.furl") +- ic = IntroducerClient(self.tub, self.introducer_furl, ++ def init_introducer_clients(self): ++ self.introducer_furls = [] ++ self.warn_flag = False ++ # Try to load ""BASEDIR/introducers" cfg file ++ cfg = os.path.join(self.basedir, MULTI_INTRODUCERS_CFG) ++ if os.path.exists(cfg): ++ f = open(cfg, 'r') ++ for introducer_furl in f.read().split('\n'): ++ if not introducer_furl.strip(): ++ continue ++ self.introducer_furls.append(introducer_furl) ++ f.close() ++ furl_count = len(self.introducer_furls) ++ #print "@icfg: furls: %d" %furl_count ++ ++ # read furl from tahoe.cfg ++ ifurl = self.get_config("client", "introducer.furl", None) ++ if ifurl and ifurl not in self.introducer_furls: ++ self.introducer_furls.append(ifurl) ++ f = open(cfg, 'a') ++ f.write(ifurl) ++ f.write('\n') ++ f.close() ++ if furl_count > 1: ++ self.warn_flag = True ++ self.log("introducers config file modified.") ++ print "Warning! introducers config file modified." ++ ++ # create a pool of introducer_clients ++ self.introducer_clients = [] ++ for introducer_furl in self.introducer_furls: ++ ic = IntroducerClient(self.tub, introducer_furl, + self.nickname, + str(allmydata.__full_version__), + str(self.OLDEST_SUPPORTED_VERSION)) +- self.introducer_client = ic ++ self.introducer_clients.append(ic) ++ # init introducer_clients as usual ++ for ic in self.introducer_clients: ++ self.init_introducer_client(ic) ++ ++ def init_introducer_client(self, ic): + # hold off on starting the IntroducerClient until our tub has been + # started, so we'll have a useful address on our RemoteReference, so + # that the introducer's status page will show us. +@@ -263,7 +299,9 @@ class Client(node.Node, pollmixin.PollMixin): + furl_file = os.path.join(self.basedir, "private", "storage.furl").encode(get_filesystem_encoding()) + furl = self.tub.registerReference(ss, furlFile=furl_file) + ri_name = RIStorageServer.__remote_name__ +- self.introducer_client.publish(furl, "storage", ri_name) ++ # Now, publish multiple introducers ++ for ic in self.introducer_clients: ++ ic.publish(furl, "storage", ri_name) + d.addCallback(_publish) + d.addErrback(log.err, facility="tahoe.init", + level=log.BAD, umid="aLGBKw") +@@ -316,7 +354,10 @@ class Client(node.Node, pollmixin.PollMixin): + # check to see if we're supposed to use the introducer too + if self.get_config("client-server-selection", "use_introducer", + default=True, boolean=True): +- sb.use_introducer(self.introducer_client) ++ ++ # Now, use our multiple introducers ++ for ic in self.introducer_clients: ++ sb.use_introducer(ic) + + def get_storage_broker(self): + return self.storage_broker +@@ -329,7 +370,9 @@ class Client(node.Node, pollmixin.PollMixin): + sc = StubClient() + furl = self.tub.registerReference(sc) + ri_name = RIStubClient.__remote_name__ +- self.introducer_client.publish(furl, "stub_client", ri_name) ++ # Now publish our multiple introducers ++ for ic in self.introducer_clients: ++ ic.publish(furl, "stub_client", ri_name) + d = self.when_tub_ready() + d.addCallback(_publish) + d.addErrback(log.err, facility="tahoe.init", +@@ -469,10 +512,15 @@ class Client(node.Node, pollmixin.PollMixin): + def get_encoding_parameters(self): + return self.DEFAULT_ENCODING_PARAMETERS + ++ # In case we configure multiple introducers + def connected_to_introducer(self): +- if self.introducer_client: +- return self.introducer_client.connected_to_introducer() +- return False ++ status = [] ++ if self.introducer_clients: ++ s = False ++ for ic in self.introducer_clients: ++ s = ic.connected_to_introducer() ++ status.append(s) ++ return status + + def get_renewal_secret(self): # this will go away + return self._secret_holder.get_renewal_secret() +diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py +index 1c7dada..52656b1 100644 +--- a/src/allmydata/test/test_web.py ++++ b/src/allmydata/test/test_web.py +@@ -42,7 +42,7 @@ from allmydata.introducer import IntroducerNode + # create a fake uploader/downloader, and a couple of fake dirnodes, then + # create a webserver that works against them + +-timeout = 480 # Most of these take longer than 240 seconds on Francois's arm box. ++timeout = 960 # allmydata.test.test_web.Grid.test_deep_check took longer than 480 seconds on zomp + + unknown_rwcap = u"lafs://from_the_future_rw_\u263A".encode('utf-8') + unknown_rocap = u"ro.lafs://readonly_from_the_future_ro_\u263A".encode('utf-8') +@@ -171,13 +171,13 @@ class FakeClient(Client): + self.all_contents = {} + self.nodeid = "fake_nodeid" + self.nickname = "fake_nickname" +- self.introducer_furl = "None" ++ self.introducer_furls = "None" + self.stats_provider = FakeStatsProvider() + self._secret_holder = SecretHolder("lease secret", "convergence secret") + self.helper = None + self.convergence = "some random string" + self.storage_broker = StorageFarmBroker(None, permute_peers=True) +- self.introducer_client = None ++ self.introducer_clients = None + self.history = FakeHistory() + self.uploader = FakeUploader() + self.uploader.all_contents = self.all_contents +diff --git a/src/allmydata/web/root.py b/src/allmydata/web/root.py +index 3b9dd1c..956de67 100644 +--- a/src/allmydata/web/root.py ++++ b/src/allmydata/web/root.py +@@ -219,12 +219,26 @@ class Root(rend.Page): + + return ctx.tag[ul] + +- def data_introducer_furl(self, ctx, data): +- return self.client.introducer_furl +- def data_connected_to_introducer(self, ctx, data): +- if self.client.connected_to_introducer(): +- return "yes" +- return "no" ++ # In case we configure multiple introducers ++ def data_introducers(self, ctx, data): ++ connection_status = [] ++ connection_status = self.client.connected_to_introducer() ++ s = [] ++ furls = self.client.introducer_furls ++ for furl in furls: ++ if connection_status: ++ i = furls.index(furl) ++ s.append((furl, bool(connection_status[i]))) ++ s.sort() ++ return s ++ ++ def render_introducers_row(self, ctx, s): ++ (furl, connected) = s ++ status = ("No", "Yes") ++ ctx.fillSlots("introducer_furl", "%s" % (furl)) ++ ctx.fillSlots("connected-bool", "%s" % (connected)) ++ ctx.fillSlots("connected", "%s" % (status[int(connected)])) ++ return ctx.tag + + def data_helper_furl(self, ctx, data): + try: +diff --git a/src/allmydata/web/welcome.xhtml b/src/allmydata/web/welcome.xhtml +index 5fd3cdd..a3b546c 100644 +--- a/src/allmydata/web/welcome.xhtml ++++ b/src/allmydata/web/welcome.xhtml +@@ -35,16 +35,31 @@ + <div n:render="download_form" /> + </div> + ++<h2>Connected Introducer(s)</h2> ++ ++<div> ++<table n:render="sequence" n:data="introducers"> ++ <tr n:pattern="header"> ++ <td>Introducer FURL</td> ++ <td>Connected?</td> ++ </tr> ++ <tr n:pattern="item" n:render="introducers_row"> ++ <td><tt><n:slot name="introducer_furl"/></tt></td> ++ <td> ++ <n:slot name="connected"/> ++ <n:attr name="class">service-connected connected-<n:slot name="connected-bool"/></n:attr> ++ </td> ++ </tr> ++ <tr n:pattern="empty"><td>no introducers!</td></tr> ++</table> ++</div> ++ ++ ++ + <div class="section" id="grid"> + <h2>Status of the Storage Grid</h2> + + <div> +- <n:attr name="class">connected-<n:invisible n:render="string" n:data="connected_to_introducer" /></n:attr> +- <div>Introducer: <span class="data-chars" n:render="string" n:data="introducer_furl" /></div> +- <div>Connected to introducer?: <span n:render="string" n:data="connected_to_introducer" /></div> +- </div> +- +- <div> + <n:attr name="class">connected-<n:invisible n:render="string" n:data="connected_to_helper" /></n:attr> + <div>Helper: <span n:render="string" n:data="helper_furl" /></div> + <div>Connected to helper?: <span n:render="string" n:data="connected_to_helper" /></div> diff --git a/0002-proxy-support.patch b/0002-proxy-support.patch new file mode 100755 index 000000000000..fe8c111f37c5 --- /dev/null +++ b/0002-proxy-support.patch @@ -0,0 +1,36 @@ +From: Kill Your TV <killyourtv@i2pmail.org> +Date: Wed, 27 Jun 2012 20:59:53 +0000 +Subject: proxy support + +--- + src/allmydata/node.py | 4 ++++ + src/allmydata/scripts/create_node.py | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/src/allmydata/node.py b/src/allmydata/node.py +index a971c4e..84d1a98 100644 +--- a/src/allmydata/node.py ++++ b/src/allmydata/node.py +@@ -185,6 +185,10 @@ class Node(service.MultiService): + # N.B.: this is in seconds, so use "1800" to get 30min + self.tub.setOption("disconnectTimeout", int(disconnect_timeout_s)) + ++ http_proxy = self.get_config("node", "http_proxy", "") ++ if http_proxy: ++ self.tub.setOption("http-proxy", http_proxy) ++ + self.nodeid = b32decode(self.tub.tubID.upper()) # binary format + self.write_config("my_nodeid", b32encode(self.nodeid).lower() + "\n") + self.short_nodeid = b32encode(self.nodeid).lower()[:8] # ready for printing +diff --git a/src/allmydata/scripts/create_node.py b/src/allmydata/scripts/create_node.py +index 7e9dcf7..09ef9bf 100644 +--- a/src/allmydata/scripts/create_node.py ++++ b/src/allmydata/scripts/create_node.py +@@ -91,6 +91,7 @@ def write_node_config(c, config): + webport = "" + c.write("web.port = %s\n" % (webport.encode('utf-8'),)) + c.write("web.static = public_html\n") ++ c.write("#http_proxy =\n") + c.write("#tub.port =\n") + c.write("#tub.location = \n") + c.write("#log_gatherer.furl =\n") diff --git a/0003-allow-non-routable.patch b/0003-allow-non-routable.patch new file mode 100755 index 000000000000..b8b30138f19b --- /dev/null +++ b/0003-allow-non-routable.patch @@ -0,0 +1,34 @@ +From: Kill Your TV <killyourtv@i2pmail.org> +Date: Wed, 27 Jun 2012 20:00:22 +0000 +Subject: allow non-routable + +--- + src/allmydata/node.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/allmydata/node.py b/src/allmydata/node.py +index 84d1a98..6ea303a 100644 +--- a/src/allmydata/node.py ++++ b/src/allmydata/node.py +@@ -280,7 +280,11 @@ class Node(service.MultiService): + + service.MultiService.startService(self) + d = defer.succeed(None) +- d.addCallback(lambda res: iputil.get_local_addresses_async()) ++ location = self.get_config("node", "tub.location", None) ++ if location == "": ++ d.addCallback(lambda res: ['127.0.0.1']) ++ else: ++ d.addCallback(lambda res: iputil.get_local_addresses_async()) + d.addCallback(self._setup_tub) + def _ready(res): + self.log("%s running" % self.NODETYPE) +@@ -356,6 +360,8 @@ class Node(service.MultiService): + base_location = ",".join([ "%s:%d" % (addr, portnum) + for addr in local_addresses ]) + location = self.get_config("node", "tub.location", base_location) ++ if location == "": ++ location = base_location + self.log("Tub location set to %s" % location) + self.tub.setLocation(location) + diff --git a/PKGBUILD b/PKGBUILD new file mode 100755 index 000000000000..6d33e5985cf7 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,87 @@ +# Maintainer : Skydrome <skydrome@i2pmail.org> +# Contributor: DaNiMoTh <jjdanimoth@gmail.com> + +pkgname=tahoe-lafs-i2p +pkgver=1.10.0.post26 +_patchver=1.10.0-r0 +pkgrel=1 +pkgdesc="Secure, decentralized, and fault-tolerant filesystem over the I2P network" +url='http://tahoe-lafs.org' +license=('GPL') +arch=('any') +conflicts=('tahoe-lafs') +provides=('tahoe-lafs') +BUILDENV+=(!check) + +depends=('python2-twisted' + 'python2-foolscap-i2p' + 'python2-mock' + 'python2-pyopenssl>=0.14' + 'python2-pyasn1' + 'python2-pyasn1-modules' + 'python2-crypto' + 'python2-cryptography' + 'python2-zope-interface' + 'python2-setuptools<0.8' + 'python2-characteristic' + 'python2-service-identity' + 'python2-numpy' + 'pycryptopp' + 'pyutil' + 'python2-simplejson' + 'python2-cffi' + 'python2-enum34' + 'python2-pycparser' + 'python2-six' + 'libffi' + 'net-tools' # provides /sbin/ifconfig + 'nevow' + 'zbase32' + 'zfec') + +optdepends=('grid-updates: helps keep you up to date with latest grid news') + +source=("https://tahoe-lafs.org/source/tahoe-lafs/snapshots/allmydata-tahoe-${pkgver}.tar.bz2" + #"setuptools_fix.diff" + #'0001-multiple-introducer-support.patch' + #'0002-proxy-support.patch' + #'0003-allow-non-routable.patch' + 'exclude_buildtest_package.patch' + "http://killyourtv.i2p.us/tahoe-lafs/patches/tahoe-lafs-i2p-${_patchver}.patch" + 'tahoe-repair-all.sh') + +sha256sums=('542830908e6deb66767ef98271bcf067f9787c0013b764caae23c7649b4f3171' + #'6d37e7003bb91c07963a71fde217b5e4f5b6eb638f6d602d82dae7a13bcaf959' + '469aa0ace523b64449e7d2d52958119a84032c50b07828b3dffbb81dca5327bd' + '425456a08477da50ef1511ea1b24cc6a529c4abaae345a3da89a31c025d74b80' + '1525fd5c2ac2c93844f23160e70bb47040a9a8ee7dff8b6fff8ca48b374ac216') + +prepare() { + cd "${srcdir}/allmydata-tahoe-${pkgver}" + #patch -Np0 -i ../setuptools_fix.diff + if [[ ! -r "${srcdir}/tahoe-lafs-i2p-${_patchver}.patch" ]]; then + for p in $(ls ${srcdir}/*.patch); do + patch -Np1 -i $p + done + else + patch -Np1 -i "${srcdir}/tahoe-lafs-i2p-${_patchver}.patch" + fi +} + +build(){ + cd "${srcdir}/allmydata-tahoe-${pkgver}" + python2 setup.py build +} + +check() { + cd "${srcdir}/allmydata-tahoe-${pkgver}" + msg "This may take a while" + python2 bin/tahoe debug trial $MAKEFLAGS +} + +package(){ + cd "${srcdir}/allmydata-tahoe-${pkgver}" + python2 setup.py install --root="$pkgdir" --optimize=1 + install -Dm644 COPYING.GPL "${pkgdir}/usr/share/licenses/${pkgname}/COPYING" + install -Dm755 "$srcdir/tahoe-repair-all.sh" "${pkgdir}/usr/bin/tahoe-repair-all" +} diff --git a/exclude_buildtest_package.patch b/exclude_buildtest_package.patch new file mode 100755 index 000000000000..c28b331ba08d --- /dev/null +++ b/exclude_buildtest_package.patch @@ -0,0 +1,38 @@ + By default tahoe-lafs also install a buildtest package but this isn't relevant + in the context of the Debian package. +Author: bertagaz <bertagaz@ptitcanardnoir.org> +Index: tahoe/setup.py +=================================================================== +--- tahoe.orig/setup.py 2012-07-04 21:42:07.000000000 +0200 ++++ tahoe/setup.py 2012-07-04 21:59:45.051169297 +0200 +@@ -467,8 +467,7 @@ + 'allmydata.util', + 'allmydata.web', + 'allmydata.web.static', +- 'allmydata.windows', +- 'buildtest'], ++ 'allmydata.windows'], + classifiers=trove_classifiers, + test_suite="allmydata.test", + install_requires=install_requires, +Index: tahoe/src/allmydata_tahoe.egg-info/SOURCES.txt +=================================================================== +--- tahoe.orig/src/allmydata_tahoe.egg-info/SOURCES.txt 2012-07-04 21:41:43.000000000 +0200 ++++ tahoe/src/allmydata_tahoe.egg-info/SOURCES.txt 2012-07-04 21:59:25.615659017 +0200 +@@ -431,7 +431,5 @@ + src/allmydata_tahoe.egg-info/not-zip-safe + src/allmydata_tahoe.egg-info/requires.txt + src/allmydata_tahoe.egg-info/top_level.txt +-src/buildtest/__init__.py +-src/buildtest/test_build_with_fake_dist.py + static/tahoe.py +-twisted/plugins/allmydata_trial.py +\ No newline at end of file ++twisted/plugins/allmydata_trial.py +Index: tahoe/src/allmydata_tahoe.egg-info/top_level.txt +=================================================================== +--- tahoe.orig/src/allmydata_tahoe.egg-info/top_level.txt 2012-07-04 21:41:43.295659068 +0200 ++++ tahoe/src/allmydata_tahoe.egg-info/top_level.txt 2012-07-04 21:59:25.615659017 +0200 +@@ -1,2 +1 @@ + allmydata +-buildtest diff --git a/tahoe-repair-all.sh b/tahoe-repair-all.sh new file mode 100755 index 000000000000..ab8e7673f849 --- /dev/null +++ b/tahoe-repair-all.sh @@ -0,0 +1,50 @@ +#!/bin/sh +########################################################## +# Stop multiple instances from running simultaneously # +# Nothing in this section should require editing # +########################################################## +if [ -w /var/lock ]; then # the default lock directory in Linux + LOCKDIR="/var/lock/tahoe-repair-all.lck" +else + LOCKDIR="/tmp/tahoe-repair-all.lck" # but maybe not elsewhere... +fi +PIDFILE="${LOCKDIR}/PID" +ENO_SUCCESS=0; +ENO_GENERAL=1; +ENO_LOCKFAIL=2; +ENO_RECVSIG=3; + +if mkdir "${LOCKDIR}" > /dev/null 2>&1 ; then + trap 'ECODE=$?; + rm -rf "${LOCKDIR}"' 0 + touch $PIDFILE + echo $$ > "${PIDFILE}" + trap 'echo "ERROR: Killed by a signal $ECODE $ENO_RECVSIG" >&2 + exit ${ENO_RECVSIG}' 1 2 3 15 +else + # lock failed, check if it's stale + OTHERPID="$(cat "${PIDFILE}")" + + if [ $? != 0 ]; then + echo "ERROR: Another instance of `basename $0` is active with PID ${OTHERPID}" >&2 + exit ${ENO_LOCKFAIL} + fi + + if ! kill -0 ${OTHERPID} >/dev/null 2>&1; then + #stale lock, removing it and restarting + echo "INFO: Removing stale PID ${OTHERPID}" >&2 + rm -rf ${LOCKDIR} + echo "INFO: [`basename $0`] restarting" >&2 + exec "$0" "$@" + else + #lock is valid and OTHERPID is active + echo "ERROR: Another instance of `basename $0` is active with PID ${OTHERPID}" >&2 + exit ${ENO_LOCKFAIL} + fi +fi +########################################################## +for item in `tahoe list-aliases | cut -f 1 -d :`; do + echo '*** '"$item" + tahoe deep-check -v --repair --add-lease $item: | perl -pe 's/^/\t/' + echo +done |