.\" Automatically generated by Podwrapper::Man 1.24.1 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "nbdkit-curl-plugin 1" .TH nbdkit-curl-plugin 1 "2021-01-20" "nbdkit-1.24.1" "NBDKIT" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" nbdkit\-curl\-plugin \- nbdkit curl plugin (HTTP, FTP and other protocols) .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& nbdkit \-r curl [url=]http://example.com/disk.img .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\f(CW\*(C`nbdkit\-curl\-plugin\*(C'\fR is a plugin for \fBnbdkit\fR\|(1) which turns content served over \s-1HTTP, FTP,\s0 and more, into a Network Block Device. It uses a library called libcurl (also known as cURL) to read data from URLs. The exact list of protocols that libcurl can handle depends on how it was compiled, but most versions will handle \s-1HTTP, HTTPS, FTP, FTPS\s0 and more (see: \f(CW\*(C`curl \-V\*(C'\fR). .PP \&\fBNote:\fR This plugin supports writes. However for \s-1HTTP,\s0 you may not want nbdkit to issue \s-1PUT\s0 requests to the remote server (which probably doesn't understand them). To force nbdkit to use a readonly connection, pass the \fI\-r\fR flag. .PP Although this plugin can access \s-1SFTP\s0 (ie. \s-1SSH\s0) servers, it is much better to use \fBnbdkit\-ssh\-plugin\fR\|(1). This plugin can be used to access \f(CW\*(C`file:///\*(C'\fR URLs, but you should use \fBnbdkit\-file\-plugin\fR\|(1) instead. .SH "EXAMPLE" .IX Header "EXAMPLE" .Vb 1 \& nbdkit \-r curl http://example.com/disk.img .Ve .PP serves the remote disk image as \s-1NBD\s0 on \s-1TCP\s0 port 10809 (to control ports and protocols used to serve \s-1NBD\s0 see \fBnbdkit\fR\|(1)). .SH "PARAMETERS" .IX Header "PARAMETERS" .IP "\fBcainfo=\fR\s-1FILENAME\s0" 4 .IX Item "cainfo=FILENAME" (nbdkit ≥ 1.18) .Sp Configure \s-1CA\s0 bundle for libcurl. See \s-1\fBCURLOPT_CAINFO\s0\fR\|(3) for details. .IP "\fBcapath=\fR\s-1PATH\s0" 4 .IX Item "capath=PATH" (nbdkit ≥ 1.18) .Sp Set \s-1CA\s0 certificates directory location for libcurl. See \&\s-1\fBCURLOPT_CAPATH\s0\fR\|(3) for more information. .IP "\fBcookie=\fR\s-1COOKIE\s0" 4 .IX Item "cookie=COOKIE" .PD 0 .IP "\fBcookie=+\fR\s-1FILENAME\s0" 4 .IX Item "cookie=+FILENAME" .IP "\fBcookie=\-\fR" 4 .IX Item "cookie=-" .IP "\fBcookie=\-\fR\s-1FD\s0" 4 .IX Item "cookie=-FD" .PD (nbdkit ≥ 1.12) .Sp Set a cookie in the request header when connecting to the remote server. .Sp A typical example is: .Sp .Vb 1 \& cookie=\*(Aqvmware_soap_session="52a01262\-bf93\-ccce\-d379\-8dabb3e55560"\*(Aq .Ve .Sp This option can be used at most once. It only works for \s-1HTTP\s0 and \&\s-1HTTPS\s0 transports. To set multiple cookies you must concatenate them yourself, eg: .Sp .Vb 1 \& cookie=\*(Aqname1=content1; name2=content2\*(Aq .Ve .Sp See \s-1\fBCURLOPT_COOKIE\s0\fR\|(3) for more information about this. The format is quite strict and must consist of \f(CW\*(C`key=value\*(C'\fR, each cookie separated by exactly \f(CW"; "\fR (semicolon and space). .Sp If the cookie is used for authentication then passing it on the command line is not secure on shared machines. Use the alternate \&\f(CW\*(C`+FILENAME\*(C'\fR syntax to pass it in a file, \f(CW\*(C`\-\*(C'\fR to read the cookie interactively, or \f(CW\*(C`\-FD\*(C'\fR to read it from a file descriptor. .IP "\fBcookie\-script=\fR\s-1SCRIPT\s0" 4 .IX Item "cookie-script=SCRIPT" .PD 0 .IP "\fBcookie\-script\-renew=\fR\s-1SECS\s0" 4 .IX Item "cookie-script-renew=SECS" .PD (nbdkit ≥ 1.22, not Windows) .Sp Run \f(CW\*(C`SCRIPT\*(C'\fR (a command or shell script fragment) to generate the \&\s-1HTTP/HTTPS\s0 cookies. \f(CW\*(C`cookie\-script\*(C'\fR cannot be used with \f(CW\*(C`cookie\*(C'\fR. See \*(L"\s-1HEADER AND COOKIE SCRIPTS\*(R"\s0 below. .IP "\fBheader=\fR\s-1HEADER\s0" 4 .IX Item "header=HEADER" (nbdkit ≥ 1.22) .Sp For \s-1HTTP/HTTPS,\s0 send a custom header, or remove a header that curl has added. To add a custom header: .Sp .Vb 1 \& header=\*(AqX\-My\-Name: John Doe\*(Aq .Ve .Sp To remove a header that curl has added, add the header followed by a colon and no value: .Sp .Vb 1 \& header=\*(AqUser\-Agent:\*(Aq .Ve .Sp To add a custom header that has no value, you have to use a semicolon instead of colon. This adds an \f(CW\*(C`X\-Empty:\*(C'\fR header with no value: .Sp .Vb 1 \& header=\*(AqX\-Empty;\*(Aq .Ve .Sp See \s-1\fBCURLOPT_HTTPHEADER\s0\fR\|(3). You can use this option multiple times in order to add several headers. Note this sends the header in all requests, even when following a redirect, which can cause headers (eg. containing sensitive authorization information) to be sent to hosts other than the one originally requested. .IP "\fBheader\-script=\fR\s-1SCRIPT\s0" 4 .IX Item "header-script=SCRIPT" .PD 0 .IP "\fBheader\-script\-renew=\fR\s-1SECS\s0" 4 .IX Item "header-script-renew=SECS" .PD (nbdkit ≥ 1.22, not Windows) .Sp Run \f(CW\*(C`SCRIPT\*(C'\fR (a command or shell script fragment) to generate the \&\s-1HTTP/HTTPS\s0 headers. \f(CW\*(C`header\-script\*(C'\fR cannot be used with \f(CW\*(C`header\*(C'\fR. See \*(L"\s-1HEADER AND COOKIE SCRIPTS\*(R"\s0 below. .IP "\fBpassword=\fR\s-1PASSWORD\s0" 4 .IX Item "password=PASSWORD" Set the password to use when connecting to the remote server. .Sp Note that passing this on the command line is not secure on shared machines. .IP "\fBpassword=\-\fR" 4 .IX Item "password=-" Ask for the password (interactively) when nbdkit starts up. .IP "\fBpassword=+\fR\s-1FILENAME\s0" 4 .IX Item "password=+FILENAME" Read the password from the named file. This is a secure method to supply a password, as long as you set the permissions on the file appropriately. .IP "\fBpassword=\-\fR\s-1FD\s0" 4 .IX Item "password=-FD" Read the password from file descriptor number \f(CW\*(C`FD\*(C'\fR, inherited from the parent process when nbdkit starts up. This is also a secure method to supply a password. .IP "\fBprotocols=\fR\s-1PROTO,PROTO,...\s0" 4 .IX Item "protocols=PROTO,PROTO,..." (nbdkit ≥ 1.12) .Sp Limit the protocols that are allowed in the \s-1URL.\s0 Use this option for extra security if the \s-1URL\s0 comes from an untrusted source and you want to avoid security isues in the more obscure protocols that curl supports. (See qemu \s-1CVE\-2013\-0249\s0 for an example of a security bug introduced by allowing unrestricted protocols). .Sp For example if you only intend \s-1HTTP\s0 and \s-1HTTPS\s0 URLs to be used, then add this parameter: \f(CW\*(C`protocols=http,https\*(C'\fR .Sp The value of this parameter is a comma-separated list of protocols. The following protocols are known: \fBdict\fR, \fBfile\fR, \fBftp\fR, \fBftps\fR, \&\fBgopher\fR, \fBhttp\fR, \fBhttps\fR, \fBimap\fR, \fBimaps\fR, \fBldap\fR, \fBldaps\fR, \&\fBmqtt\fR, \fBpop3\fR, \fBpop3s\fR, \fBrtmp\fR, \fBrtmpe\fR, \fBrtmps\fR, \fBrtmpt\fR, \&\fBrtmpte\fR, \fBrtmpts\fR, \fBrtsp\fR, \fBscp\fR, \fBsftp\fR, \fBsmb\fR, \fBsmbs\fR, \&\fBsmtp\fR, \fBsmtps\fR, \fBtelnet\fR, \fBtftp\fR. .Sp The default is to allow any protocol. .IP "\fBproxy=\fR\s-1PROXY\s0" 4 .IX Item "proxy=PROXY" (nbdkit ≥ 1.20) .Sp Set the proxy. See \s-1\fBCURLOPT_PROXY\s0\fR\|(3). .IP "\fBproxy\-password=\fR\s-1PASSWORD\s0" 4 .IX Item "proxy-password=PASSWORD" .PD 0 .IP "\fBproxy\-password=\-\fR" 4 .IX Item "proxy-password=-" .IP "\fBproxy\-password=+\fR\s-1FILENAME\s0" 4 .IX Item "proxy-password=+FILENAME" .IP "\fBproxy\-password=\-\fR\s-1FD\s0" 4 .IX Item "proxy-password=-FD" .IP "\fBproxy\-user=\fR\s-1USERNAME\s0" 4 .IX Item "proxy-user=USERNAME" .PD (nbdkit ≥ 1.12) .Sp Set the proxy username and password. .IP "\fBsslverify=false\fR" 4 .IX Item "sslverify=false" Don't verify the \s-1SSL\s0 certificate of the remote host. .IP "\fBtcp\-keepalive=true\fR" 4 .IX Item "tcp-keepalive=true" (nbdkit ≥ 1.20) .Sp Enable \s-1TCP\s0 keepalives. .IP "\fBtcp\-nodelay=false\fR" 4 .IX Item "tcp-nodelay=false" (nbdkit ≥ 1.20) .Sp Disable Nagle’s algorithm. .IP "\fBtimeout=\fR\s-1SECS\s0" 4 .IX Item "timeout=SECS" Set the timeout for requests. .IP "\fBtimeout=0\fR" 4 .IX Item "timeout=0" Use the default libcurl timeout for requests. .IP "\fBunix\-socket\-path=\fR\s-1PATH\s0" 4 .IX Item "unix-socket-path=PATH" (nbdkit ≥ 1.10) .Sp Instead of using a \s-1TCP\s0 connection, connect to the server over the named Unix domain socket. See \s-1\fBCURLOPT_UNIX_SOCKET_PATH\s0\fR\|(3). .IP "[\fBurl=\fR]URL" 4 .IX Item "[url=]URL" The \s-1URL\s0 of the remote disk image. This is passed to libcurl directly via \s-1\fBCURLOPT_URL\s0\fR\|(3). .Sp This parameter is required. .Sp \&\f(CW\*(C`url=\*(C'\fR is a magic config key and may be omitted in most cases. See \*(L"Magic parameters\*(R" in \fBnbdkit\fR\|(1). .IP "\fBuser=\fR\s-1USERNAME\s0" 4 .IX Item "user=USERNAME" Set the username to use when connecting to the remote server. This may also be set in the \s-1URL\s0 (eg. \f(CW\*(C`http://foo@example.com/disk.img\*(C'\fR) .IP "\fBuser\-agent=\fRUSER-AGENT" 4 .IX Item "user-agent=USER-AGENT" (nbdkit ≥ 1.22) .Sp Send user-agent header when using \s-1HTTP\s0 or \s-1HTTPS.\s0 The default is no user-agent header. .SH "HEADER AND COOKIE SCRIPTS" .IX Header "HEADER AND COOKIE SCRIPTS" While the \f(CW\*(C`header\*(C'\fR and \f(CW\*(C`cookie\*(C'\fR parameters can be used to specify static headers and cookies which are used in every \s-1HTTP/HTTPS\s0 request, the alternate \f(CW\*(C`header\-script\*(C'\fR and \f(CW\*(C`cookie\-script\*(C'\fR parameters can be used to run an external script or program to generate headers and/or cookies. This is particularly useful to access services which require an authorization token. In addition the \f(CW\*(C`header\-script\-renew\*(C'\fR and \&\f(CW\*(C`cookie\-script\-renew\*(C'\fR parameters allow you to renew the authorization token by rerunning the script periodically. .PP \&\f(CW\*(C`header\-script\*(C'\fR is incompatible with \f(CW\*(C`header\*(C'\fR, and \f(CW\*(C`cookie\-script\*(C'\fR is incompatible with \f(CW\*(C`cookie\*(C'\fR. .SS "Header script" .IX Subsection "Header script" The header script should print zero or more \s-1HTTP\s0 headers, each line of output in the same format as the \f(CW\*(C`header\*(C'\fR parameter. The headers printed by the script are passed to \s-1\fBCURLOPT_HTTPHEADER\s0\fR\|(3). .PP In the following example, an imaginary web service requires authentication using a token fetched from a separate login server. The token expires after 60 seconds, so we also tell the plugin that it must renew the token (by re-running the script) if more than 50 seconds have elapsed since the last request: .PP .Vb 7 \& nbdkit curl https://service.example.com/disk.img \e \& header\-script=\*(Aq \& printf "Authorization: Bearer " \& curl \-s \-X POST https://auth.example.com/login | \& jq \-r .token \& \*(Aq \e \& header\-script\-renew=50 .Ve .SS "Cookie script" .IX Subsection "Cookie script" The cookie script should print a single line in the same format as the \&\f(CW\*(C`cookie\*(C'\fR parameter. This is passed to \s-1\fBCURLOPT_COOKIE\s0\fR\|(3). .SS "Header and cookie script shell variables" .IX Subsection "Header and cookie script shell variables" Within the \f(CW\*(C`header\-script\*(C'\fR and \f(CW\*(C`cookie\-script\*(C'\fR the following shell variables are available: .ie n .IP "$iteration" 4 .el .IP "\f(CW$iteration\fR" 4 .IX Item "$iteration" The number of times that the script has been called. The first time the script is called this contains \f(CW0\fR. .ie n .IP "$url" 4 .el .IP "\f(CW$url\fR" 4 .IX Item "$url" The \s-1URL\s0 as passed to the plugin. .SS "Example: VMware ESXi cookies" .IX Subsection "Example: VMware ESXi cookies" VMware ESXi’s web server can expose both \s-1VMDK\s0 and raw format disk images, but requires you to log in using \s-1HTTP\s0 Basic Authentication. While you can use the \f(CW\*(C`user\*(C'\fR and \f(CW\*(C`password\*(C'\fR parameters to send \s-1HTTP\s0 Basic Authentication headers in every request, tests have shown that it is faster to accept the cookie which the server returns and send that instead. (It is not clear why it is faster, but one theory is that VMware has to do a more expensive username and password check each time.) .PP The web server can be accessed as below. Since the cookie expires after a certain period of time, we use \f(CW\*(C`cookie\-script\-renew\*(C'\fR, and because the server uses a self-signed certificate we must use \&\fI\-\-insecure\fR and \f(CW\*(C`sslverify=false\*(C'\fR. .PP .Vb 5 \& SERVER=esx.example.com \& DCPATH=data \& DS=datastore1 \& GUEST=guest\-name \& URL="https://$SERVER/folder/$GUEST/$GUEST\-flat.vmdk?dcPath=$DCPATH&dsName=$DS" \& \& nbdkit curl "$URL" \e \& cookie\-script=\*(Aq \& curl \-\-head \-s \-\-insecure \-u root:password "$url" | \& sed \-ne "{ s/^Set\-Cookie: \e([^;]*\e);.*/\e1/ip }" \& \*(Aq \e \& cookie\-script\-renew=500 \e \& sslverify=false .Ve .SS "Example: Docker Hub authorization tokens" .IX Subsection "Example: Docker Hub authorization tokens" Accessing objects like container layers from Docker Hub requires that you first fetch an authorization token, even for anonymous access. These tokens expire after about 5 minutes (300 seconds) so must be periodically renewed. .PP You will need this authorization script (\fI/tmp/auth.sh\fR): .PP .Vb 4 \& #!/bin/sh \- \& IMAGE=library/fedora \& curl \-s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$IMAGE:pull" | \& jq \-r .token .Ve .PP You will also need this script to get the blobSum of the layer (\fI/tmp/blobsum.sh\fR): .PP .Vb 6 \& #!/bin/sh \- \& TOKEN=\`/tmp/auth.sh\` \& IMAGE=library/fedora \& curl \-s \-X GET \-H "Authorization: Bearer $TOKEN" \e \& "https://registry\-1.docker.io/v2/$IMAGE/manifests/latest" | \& jq \-r \*(Aq.fsLayers[0].blobSum\*(Aq .Ve .PP Both scripts must be executable, and both can be run on their own to check they are working. To run nbdkit: .PP .Vb 3 \& IMAGE=library/fedora \& BLOBSUM=\`/tmp/blobsum.sh\` \& URL="https://registry\-1.docker.io/v2/$IMAGE/blobs/$BLOBSUM" \& \& nbdkit curl "$URL" \e \& header\-script=\*(Aq printf "Authorization: Bearer "; /tmp/auth.sh \*(Aq \e \& header\-script\-renew=200 \e \& \-\-filter=gzip .Ve .PP Note that this exposes a tar file over \s-1NBD.\s0 See also \&\fBnbdkit\-tar\-filter\fR\|(1). .SH "DEBUG FLAGS" .IX Header "DEBUG FLAGS" .IP "\fB\-D curl.scripts=1\fR" 4 .IX Item "-D curl.scripts=1" This prints out the headers and cookies generated by the \&\f(CW\*(C`header\-script\*(C'\fR and \f(CW\*(C`cookie\-script\*(C'\fR options, which can be useful when debugging these scripts. .IP "\fB\-D curl.verbose=1\fR" 4 .IX Item "-D curl.verbose=1" This enables very verbose curl debugging. See \s-1\fBCURLOPT_VERBOSE\s0\fR\|(3). This is mainly useful if you suspect there is a bug inside libcurl itself. .SH "FILES" .IX Header "FILES" .IP "\fI\f(CI$plugindir\fI/nbdkit\-curl\-plugin.so\fR" 4 .IX Item "$plugindir/nbdkit-curl-plugin.so" The plugin. .Sp Use \f(CW\*(C`nbdkit \-\-dump\-config\*(C'\fR to find the location of \f(CW$plugindir\fR. .SH "VERSION" .IX Header "VERSION" \&\f(CW\*(C`nbdkit\-curl\-plugin\*(C'\fR first appeared in nbdkit 1.2. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fBcurl\fR\|(1), \&\fBlibcurl\fR\|(3), \&\s-1\fBCURLOPT_CAINFO\s0\fR\|(3), \&\s-1\fBCURLOPT_CAPATH\s0\fR\|(3), \&\s-1\fBCURLOPT_COOKIE\s0\fR\|(3), \&\s-1\fBCURLOPT_HTTPHEADER\s0\fR\|(3), \&\s-1\fBCURLOPT_PROXY\s0\fR\|(3), \&\s-1\fBCURLOPT_TCP_KEEPALIVE\s0\fR\|(3), \&\s-1\fBCURLOPT_TCP_NODELAY\s0\fR\|(3), \&\s-1\fBCURLOPT_URL\s0\fR\|(3), \&\s-1\fBCURLOPT_UNIX_SOCKET_PATH\s0\fR\|(3), \&\s-1\fBCURLOPT_USERAGENT\s0\fR\|(3), \&\s-1\fBCURLOPT_VERBOSE\s0\fR\|(3), \&\fBnbdkit\fR\|(1), \&\fBnbdkit\-extentlist\-filter\fR\|(1), \&\fBnbdkit\-file\-plugin\fR\|(1), \&\fBnbdkit\-readahead\-filter\fR\|(1), \&\fBnbdkit\-retry\-filter\fR\|(1), \&\fBnbdkit\-ssh\-plugin\fR\|(1), \&\fBnbdkit\-torrent\-plugin\fR\|(1), \&\fBnbdkit\-plugin\fR\|(3), http://curl.haxx.se. .SH "AUTHORS" .IX Header "AUTHORS" Richard W.M. Jones .PP Parts derived from Alexander Graf's \*(L"\s-1QEMU\s0 Block driver for \s-1CURL\s0 images\*(R". .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (C) 2014\-2020 Red Hat Inc. .SH "LICENSE" .IX Header "LICENSE" Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: .IP "\(bu" 4 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. .IP "\(bu" 4 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. .IP "\(bu" 4 Neither the name of Red Hat nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. .PP \&\s-1THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS\s0 ''\s-1AS IS\s0'' \s-1AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\s0 (\s-1INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES\s0; \s-1LOSS OF USE, DATA, OR PROFITS\s0; \s-1OR BUSINESS INTERRUPTION\s0) \s-1HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\s0 (\s-1INCLUDING NEGLIGENCE OR OTHERWISE\s0) \s-1ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\s0