File krunvm-0.2.3+git12dac81.obscpio of Package krunvm

07070100000000000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000002000000000krunvm-0.2.3+git12dac81/.github07070100000001000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000002A00000000krunvm-0.2.3+git12dac81/.github/workflows07070100000002000081A4000000000000000000000001636923F100000378000000000000000000000000000000000000003B00000000krunvm-0.2.3+git12dac81/.github/workflows/code_quality.ymlname: Code Quality (rustfmt and clippy)
on: [pull_request, create]

jobs:
  build:
    if: github.event_name == 'pull_request'
    name: Code Quality (clippy, rustfmt)
    runs-on: ubuntu-latest
    strategy:
      matrix:
        rust:
          - stable
        target:
          - x86_64-unknown-linux-gnu
    steps:
      - name: Code checkout
        uses: actions/checkout@v2
      - name: Install Rust toolchain (${{ matrix.rust }})
        uses: actions-rs/toolchain@v1
        with:
            toolchain: ${{ matrix.rust }}
            target: ${{ matrix.target }}
            override: true
            components: rustfmt, clippy

      - name: Install asciidoctor
        run: sudo apt-get install -y asciidoctor

      - name: Formatting (rustfmt)
        run: cargo fmt -- --check

      - name: Clippy (all features)
        run: cargo clippy --all-targets --all-features
07070100000003000081A4000000000000000000000001636923F100000038000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/.gitignore/build/
target
*.rs.bk
*.iml
.idea
__pycache__
*.pyc
*~
07070100000004000081A4000000000000000000000001636923F1000000BD000000000000000000000000000000000000002B00000000krunvm-0.2.3+git12dac81/CODE-OF-CONDUCT.md## The krunvm Project Community Code of Conduct

The krunvm Project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).
07070100000005000081A4000000000000000000000001636923F10000229E000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/Cargo.lock# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
 "winapi",
]

[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"

[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"

[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
 "hermit-abi",
 "libc",
 "winapi",
]

[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"

[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"

[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"

[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
 "arrayref",
 "arrayvec",
 "constant_time_eq",
]

[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
 "ansi_term",
 "atty",
 "bitflags",
 "strsim",
 "textwrap",
 "unicode-width",
 "vec_map",
]

[[package]]
name = "confy"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2913470204e9e8498a0f31f17f90a0de801ae92c8c5ac18c49af4819e6786697"
dependencies = [
 "directories",
 "serde",
 "toml",
]

[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"

[[package]]
name = "crossbeam-utils"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
dependencies = [
 "autocfg",
 "cfg-if 1.0.0",
 "lazy_static",
]

[[package]]
name = "directories"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c"
dependencies = [
 "cfg-if 0.1.10",
 "dirs-sys",
]

[[package]]
name = "dirs-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [
 "libc",
 "redox_users",
 "winapi",
]

[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
 "cfg-if 1.0.0",
 "libc",
 "wasi",
]

[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
 "libc",
]

[[package]]
name = "krunvm"
version = "0.2.3"
dependencies = [
 "clap",
 "confy",
 "libc",
 "serde",
 "serde_derive",
 "text_io",
]

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

[[package]]
name = "libc"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"

[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
 "unicode-xid",
]

[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"

[[package]]
name = "redox_users"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
 "getrandom",
 "redox_syscall",
 "rust-argon2",
]

[[package]]
name = "rust-argon2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
 "base64",
 "blake2b_simd",
 "constant_time_eq",
 "crossbeam-utils",
]

[[package]]
name = "serde"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"

[[package]]
name = "serde_derive"
version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"

[[package]]
name = "syn"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]
name = "text_io"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb170b4f47dc48835fbc56259c12d8963e542b05a24be2e3a1f5a6c320fd2d4"

[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
 "unicode-width",
]

[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
 "serde",
]

[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"

[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"

[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"

[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
07070100000006000081A4000000000000000000000001636923F100000174000000000000000000000000000000000000002300000000krunvm-0.2.3+git12dac81/Cargo.toml[package]
name = "krunvm"
version = "0.2.3"
authors = ["Sergio Lopez <slp@redhat.com>"]
description = "Create microVMs from OCI images"
repository = "https://github.com/containers/krunvm"
license = "Apache-2.0"
edition = "2018"
build = "build.rs"

[dependencies]
clap = "2.33.3"
confy = "0.4.0"
libc = "0.2.82"
serde = "1.0.120"
serde_derive = "1.0.120"
text_io = "0.1.8"
07070100000007000081A4000000000000000000000001636923F100002C5E000000000000000000000000000000000000002000000000krunvm-0.2.3+git12dac81/LICENSE
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
07070100000008000081A4000000000000000000000001636923F10000022A000000000000000000000000000000000000002100000000krunvm-0.2.3+git12dac81/MakefileOS = $(shell uname -s)
KRUNVM_RELEASE = target/release/krunvm
KRUNVM_DEBUG = target/debug/krunvm
INIT_BINARY = init/init

ifeq ($(PREFIX),)
    PREFIX := /usr/local
endif

.PHONY: install clean

all: $(KRUNVM_RELEASE)

debug: $(KRUNVM_DEBUG)

$(KRUNVM_RELEASE):
	cargo build --release
ifeq ($(OS),Darwin)
	codesign --entitlements krunvm.entitlements --force -s - $@
endif

$(KRUNVM_DEBUG):
	cargo build --debug

install: $(KRUNVM_RELEASE)
	install -d $(DESTDIR)$(PREFIX)/bin
	install -m 755 $(KRUNVM_RELEASE) $(DESTDIR)$(PREFIX)/bin

clean:
	cargo clean
07070100000009000081A4000000000000000000000001636923F10000042B000000000000000000000000000000000000002200000000krunvm-0.2.3+git12dac81/README.md# krunvm

```krunvm``` is a CLI-based utility for creating microVMs from OCI images, using [libkrun](https://github.com/containers/libkrun) and [buildah](https://github.com/containers/buildah).

## Features

* Minimal footprint
* Fast boot time
* Zero disk image maintenance
* Zero network configuration
* Support for mapping host volumes into the guest
* Support for exposing guest ports to the host

## Demo

[![asciicast](https://asciinema.org/a/CGtTS93VsdzWwUfkY1kqVnaik.svg)](https://asciinema.org/a/CGtTS93VsdzWwUfkY1kqVnaik)

## Supported platforms

- Linux/KVM on x86_64.
- Linux/KVM on AArch64.
- macOS/Hypervisor.framework on ARM64.

## Installation

### macOS

```
brew tap slp/krun
brew install krunvm
```

### Fedora

```
dnf copr enable -y slp/libkrunfw
dnf copr enable -y slp/libkrun
dnf copr enable -y slp/krunvm
dnf install -y krunvm
```

### Building from sources

#### Dependencies

* Rust Toolchain
* [libkrun](https://github.com/containers/libkrun)
* [buildah](https://github.com/containers/buildah)

#### Building

```
cargo build --release
```
0707010000000A000081A4000000000000000000000001636923F1000000EE000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/SECURITY.md## Security and Disclosure Information Policy for the krunvm Project

The krunvm Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects.

0707010000000B000081A4000000000000000000000001636923F1000006A0000000000000000000000000000000000000002100000000krunvm-0.2.3+git12dac81/build.rsuse std::path::Path;
use std::{env, fs, io, process};

const COMMANDS: [&str; 7] = [
    "krunvm",
    "krunvm-changevm",
    "krunvm-create",
    "krunvm-config",
    "krunvm-delete",
    "krunvm-list",
    "krunvm-start",
];

fn main() {
    let outdir = match env::var_os("OUT_DIR") {
        Some(outdir) => outdir,
        None => {
            panic!("OUT_DIR environment variable not defined.");
        }
    };
    fs::create_dir_all(&outdir).unwrap();

    for command in COMMANDS {
        if let Err(err) = generate_man_page(&outdir, command) {
            panic!("failed to generate man page: {}", err);
        }
    }

    #[cfg(target_os = "macos")]
    println!("cargo:rustc-link-search=/opt/homebrew/lib");
}

fn generate_man_page<P: AsRef<Path>>(outdir: P, command: &str) -> io::Result<()> {
    // If asciidoctor isn't installed, fallback to asciidoc.
    if let Err(err) = process::Command::new("asciidoctor").output() {
        eprintln!("Error from running 'asciidoctor': {}", err);
        return Err(err);
    }

    let outdir = outdir.as_ref();
    let outfile = outdir.join(format!("{}.1", command));
    let cwd = env::current_dir()?;
    let txt_path = cwd.join("docs").join(format!("{}.1.txt", command));

    let result = process::Command::new("asciidoctor")
        .arg("--doctype")
        .arg("manpage")
        .arg("--backend")
        .arg("manpage")
        .arg("--out-file")
        .arg(&outfile)
        .arg(&txt_path)
        .spawn()?
        .wait()?;
    if !result.success() {
        let msg = format!("'asciidoctor' failed with exit code {:?}", result.code());
        return Err(io::Error::new(io::ErrorKind::Other, msg));
    }
    Ok(())
}
0707010000000C000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000001D00000000krunvm-0.2.3+git12dac81/docs0707010000000D000081A4000000000000000000000001636923F1000006AD000000000000000000000000000000000000003300000000krunvm-0.2.3+git12dac81/docs/krunvm-changevm.1.txtkrunvm-changevm(1)
==================

NAME
----
krunvm-changevm - Change the configuration of a microVM


SYNOPSIS
--------
*krunvm changevm* [_OPTIONS_] _microVM_


DESCRIPTION
-----------
*krunvm changevm* changes the configuration of an existing microVM.

When run without any _OPTIONS_, it displays the current configuration
of the microVM.


OPTIONS
-------
*--remove-ports*::
  Removes all port mappings.

*--remote-volumes*::
  Removes all volume mappings.

*--cpus* _NUM_::
  Changes the number of vCPUs that will be created for this microVM.

*--mem* _NUM_::
  Changes the amount of RAM, in MiB, that will be available to this
  microVM.
+
The memory configured for the microVM will not be reserved
immediately. Instead, it will be provided as the guest demands it, and
both the guest and libkrun (acting as the Virtual Machine Monitor)
will attempt to return as many pages as possible to the host.

*--name* _NAME_::
  Assigns a new name to the microVM.

*-p, --port* _HOST_PORT:GUEST_PORT_::
  Exposes a port in the guest running in the microVM through a port in the host.
+
This option can be specified multiple times to expose as many guest
ports as desired.

*-v, --volume* _HOST_PATH:GUEST_PATH_::
  Makes _HOST_PATH_ visible in the guest running in the microVM through _GUEST_PATH_.
+
This option can be specified multiple times to make more paths in the
host visible in the guest.

*-w, --workdir* _GUEST_PATH_::
  Configures _GUEST_PATH_ as the working directory for the first
  binary executed in the microVM.
+
An empty string ("") tells krunvm to not set a working directory
explicitly, letting libkrun decide which one should be set.


SEE ALSO
--------
*krunvm(1)*, *krunvm-create(1)*
0707010000000E000081A4000000000000000000000001636923F1000002F2000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-config.1.txtkrunvm-config(1)
================

NAME
----
krunvm-config - Configure default values


SYNOPSIS
--------
*krunvm config* [_OPTIONS_]


DESCRIPTION
-----------
*krunvm config* configures the default values that will be used for
newly created microVMs when a explicit value has not been passed to
*krunvm-create(1)*

When run without any _OPTIONS_ it displays the current default values.


OPTIONS
-------
*--cpus* _NUM_::
  Sets the default number of vCPUs that will be configured for newly
  created microVMs.

*--dns* _IP_::
  Sets the default IP that will be configured as DNS for newly created
  microVMs.

*--mem* _NUM_::
  Sets the default mount of RAM, in MiB, that will be configured for
  newly created microVMs.


SEE ALSO
--------
*krunvm(1)*
0707010000000F000081A4000000000000000000000001636923F10000066F000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-create.1.txtkrunvm-create(1)
================

NAME
----
krunvm-create - Create a new microVM from an OCI image


SYNOPSIS
--------
*krunvm create* [_OPTIONS_] _IMAGE_


DESCRIPTION
-----------
*krunvm create* creates a new microVM from the OCI image specified by
_IMAGE_. Please refer to buildah-from(1) for information about the
format supported by the _IMAGE_ argument.


OPTIONS
-------
*--cpus* _NUM_::
  The number of vCPUs that will be created for this microVM.

*--mem* _NUM_::
  The amount of RAM, in MiB, that will be available to this microVM.
+
The memory configured for the microVM will not be reserved
immediately. Instead, it will be provided as the guest demands it, and
both the guest and libkrun (acting as the Virtual Machine Monitor)
will attempt to return as many pages as possible to the host.

*--name* _NAME_::
  The name to be assigned to this microVM.

*-p, --port* _HOST_PORT:GUEST_PORT_::
  Exposes a port in the guest running in the microVM through a port in the host.
+
This option can be specified multiple times to expose as many guest
ports as desired.

*-v, --volume* _HOST_PATH:GUEST_PATH_::
  Makes _HOST_PATH_ visible in the guest running in the microVM through _GUEST_PATH_.
+
This option can be specified multiple times to make more paths in the
host visible in the guest.

*-w, --workdir* _GUEST_PATH_::
  Configures _GUEST_PATH_ as the working directory for the first
  binary executed in the microVM.
+
An empty string ("") tells krunvm to not set a working directory
explicitly, letting libkrun decide which one should be set.  


SEE ALSO
--------
*buildah(1)*, *buildah-from(1)*, *krunvm(1)*, *krunvm-changevm(1)*
07070100000010000081A4000000000000000000000001636923F10000015D000000000000000000000000000000000000003100000000krunvm-0.2.3+git12dac81/docs/krunvm-delete.1.txtkrunvm-delete(1)
================

NAME
----
krunvm-delete - Deletes an existing microVM


SYNOPSIS
--------
*krunvm delete* _microVM_


DESCRIPTION
-----------
*krunvm delete* deletes an existing microVM configuration and requests
to buildah(1) to unmount and remove the OCI image that was backing it.


SEE ALSO
--------
*buildah(1)*, *krunvm(1)*
07070100000011000081A4000000000000000000000001636923F100000148000000000000000000000000000000000000002F00000000krunvm-0.2.3+git12dac81/docs/krunvm-list.1.txtkrunvm-list(1)
==============

NAME
----
krunvm-list - Lists the existing microVMs


SYNOPSIS
--------
*krunvm list*


DESCRIPTION
-----------
*krunvm list* lists the microVMs created by *krunvm-create(1)* that
have not been removed by *krunvm-delete(1)*.


SEE ALSO
--------
*krunvm(1)*, *krunvm-create(1)*, *krunvm-delete(1)*
07070100000012000081A4000000000000000000000001636923F100000398000000000000000000000000000000000000003000000000krunvm-0.2.3+git12dac81/docs/krunvm-start.1.txtkrunvm-start(1)
===============

NAME
----
krunvm-start - Starts an existing microVM


SYNOPSIS
--------
*krunvm start* [_OPTIONS_] _microVM_ [_COMMAND_] [-- ARGS]


DESCRIPTION
-----------
*krunvm start* starts an existing microVM created by krunvm-create(1)
and attaches stdin/stdout to its virtio-console providing a seamless
experience for interacting with the guest running inside it.

_COMMAND_ is the first binary to be executed in the microVM. If it's
not present in the command line, krunvm-start(1) lets libkrun decide
which binary will be executed.

Additional arguments for _COMMAND_ can be specified in the command
line by appending _--_ followed by _ARGS_.


OPTIONS
-------
*--cpus* _NUM_::
  Override the number of vCPUs configured for this microVM.

*--mem* _NUM_::
  Override amount of RAM, in MiB, configured for this microVM.


SEE ALSO
--------
*krunvm(1)*, *krunvm-create(1)*, *krunvm-changevm(1)*
07070100000013000081A4000000000000000000000001636923F1000005C5000000000000000000000000000000000000002A00000000krunvm-0.2.3+git12dac81/docs/krunvm.1.txtkrunvm(1)
=========

NAME
----
krunvm - Create microVMs from OCI images


SYNOPSIS
--------
*krunvm* [_GLOBAL_OPTIONS_] *command*


DESCRIPTION
-----------
krunvm is a CLI utility to create, manage and start microVMs which are
generated from OCI images, providing an interface that resembles
operating on conventional containers.

krunvm uses buildah(1) to download the OCI image and mount it into a
local directory, and libkrun to launch the microVM.

The local directory where the OCI image has been mounted is used as
the root filesystem for the microVM, serviced by a virtio-fs
device/server bundled into libkrun.

krunvm supports mounting additional local directories into the
microVM and exposing ports from the guest to the host (and the
networks connected to it).

Networking to the guest running in the microVM is provided by
libkrun's TSI (Transparent Socket Impersonation), enabling a seamless
experience that doesn't require network bridges nor other explicit
network configuration.


GLOBAL OPTIONS
--------------
*-v* _NUM_::
  Sets the verbosity level, from the lowest (0) to the highest (5).


COMMANDS
--------
|===
|Command | Description

|krunvm-changevm(1) | Change the configuration of a microVM
|krunvm-config(1) | Configure global values
|krunvm-create(1) | Create a new microVM
|krunvm-delete(1) | Delete an existing microVM
|krunvm-list(1) | List the existing microVMs
|krunvm-start(1) | Start an existing microVM
|===


SEE ALSO
--------
*buildah(1)*
07070100000014000081A4000000000000000000000001636923F100000136000000000000000000000000000000000000002C00000000krunvm-0.2.3+git12dac81/krunvm.entitlements<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.hypervisor</key>
	<true/>
	<key>com.apple.security.cs.disable-library-validationr</key>
	<true/>
</dict>
</plist>
07070100000015000041ED000000000000000000000001636923F100000000000000000000000000000000000000000000001C00000000krunvm-0.2.3+git12dac81/src07070100000016000081A4000000000000000000000001636923F10000036F000000000000000000000000000000000000002800000000krunvm-0.2.3+git12dac81/src/bindings.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

#[link(name = "krun")]
extern "C" {
    pub fn krun_set_log_level(level: u32) -> i32;
    pub fn krun_create_ctx() -> i32;
    pub fn krun_free_ctx(ctx: u32) -> i32;
    pub fn krun_set_vm_config(ctx: u32, num_vcpus: u8, ram_mib: u32) -> i32;
    pub fn krun_set_root(ctx: u32, root_path: *const i8) -> i32;
    pub fn krun_set_mapped_volumes(ctx: u32, mapped_volumes: *const *const i8) -> i32;
    pub fn krun_set_port_map(ctx: u32, port_map: *const *const i8) -> i32;
    pub fn krun_set_workdir(ctx: u32, workdir_path: *const i8) -> i32;
    pub fn krun_set_exec(
        ctx: u32,
        exec_path: *const i8,
        argv: *const *const i8,
        envp: *const *const i8,
    ) -> i32;
    pub fn krun_set_env(ctx: u32, envp: *const *const i8) -> i32;
    pub fn krun_start_enter(ctx: u32) -> i32;
}
07070100000017000081A4000000000000000000000001636923F100000DAB000000000000000000000000000000000000002800000000krunvm-0.2.3+git12dac81/src/changevm.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;

use crate::{ArgMatches, KrunvmConfig, APP_NAME};

use super::list::printvm;
use super::utils::{parse_mapped_ports, parse_mapped_volumes};

pub fn changevm(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
    let mut cfg_changed = false;

    let name = matches.value_of("NAME").unwrap();

    let mut vmcfg = if let Some(new_name) = matches.value_of("new-name") {
        if cfg.vmconfig_map.contains_key(new_name) {
            println!("A VM with name {} already exists", new_name);
            std::process::exit(-1);
        }

        let mut vmcfg = match cfg.vmconfig_map.remove(name) {
            None => {
                println!("No VM found with name {}", name);
                std::process::exit(-1);
            }
            Some(vmcfg) => vmcfg,
        };

        cfg_changed = true;
        let name = new_name.to_string();
        vmcfg.name = name.clone();
        cfg.vmconfig_map.insert(name.clone(), vmcfg);
        cfg.vmconfig_map.get_mut(&name).unwrap()
    } else {
        match cfg.vmconfig_map.get_mut(name) {
            None => {
                println!("No VM found with name {}", name);
                std::process::exit(-1);
            }
            Some(vmcfg) => vmcfg,
        }
    };

    if let Some(cpus_str) = matches.value_of("cpus") {
        match cpus_str.parse::<u32>() {
            Err(_) => println!("Invalid value for \"cpus\""),
            Ok(cpus) => {
                if cpus > 8 {
                    println!("Error: the maximum number of CPUs supported is 8");
                } else {
                    vmcfg.cpus = cpus;
                    cfg_changed = true;
                }
            }
        }
    }

    if let Some(mem_str) = matches.value_of("mem") {
        match mem_str.parse::<u32>() {
            Err(_) => println!("Invalid value for \"mem\""),
            Ok(mem) => {
                if mem > 16384 {
                    println!("Error: the maximum amount of RAM supported is 16384 MiB");
                } else {
                    vmcfg.mem = mem;
                    cfg_changed = true;
                }
            }
        }
    }

    if matches.is_present("remove-volumes") {
        vmcfg.mapped_volumes = HashMap::new();
        cfg_changed = true;
    } else {
        let volume_matches = if matches.is_present("volume") {
            matches.values_of("volume").unwrap().collect()
        } else {
            vec![]
        };
        let mapped_volumes = parse_mapped_volumes(volume_matches);

        if !mapped_volumes.is_empty() {
            vmcfg.mapped_volumes = mapped_volumes;
            cfg_changed = true;
        }
    }

    if matches.is_present("remove-ports") {
        vmcfg.mapped_ports = HashMap::new();
        cfg_changed = true;
    } else {
        let port_matches = if matches.is_present("port") {
            matches.values_of("port").unwrap().collect()
        } else {
            vec![]
        };
        let mapped_ports = parse_mapped_ports(port_matches);

        if !mapped_ports.is_empty() {
            vmcfg.mapped_ports = mapped_ports;
            cfg_changed = true;
        }
    }

    if let Some(workdir) = matches.value_of("workdir") {
        vmcfg.workdir = workdir.to_string();
        cfg_changed = true;
    }

    println!();
    printvm(vmcfg);
    println!();

    if cfg_changed {
        confy::store(APP_NAME, &cfg).unwrap();
    }
}
07070100000018000081A4000000000000000000000001636923F100000699000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/config.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::{ArgMatches, KrunvmConfig, APP_NAME};

pub fn config(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
    let mut cfg_changed = false;

    if let Some(cpus_str) = matches.value_of("cpus") {
        match cpus_str.parse::<u32>() {
            Err(_) => println!("Invalid value for \"cpus\""),
            Ok(cpus) => {
                if cpus > 8 {
                    println!("Error: the maximum number of CPUs supported is 8");
                } else {
                    cfg.default_cpus = cpus;
                    cfg_changed = true;
                }
            }
        }
    }

    if let Some(mem_str) = matches.value_of("mem") {
        match mem_str.parse::<u32>() {
            Err(_) => println!("Invalid value for \"mem\""),
            Ok(mem) => {
                if mem > 16384 {
                    println!("Error: the maximum amount of RAM supported is 16384 MiB");
                } else {
                    cfg.default_mem = mem;
                    cfg_changed = true;
                }
            }
        }
    }

    if let Some(dns) = matches.value_of("dns") {
        cfg.default_dns = dns.to_string();
        cfg_changed = true;
    }

    if cfg_changed {
        confy::store(APP_NAME, &cfg).unwrap();
    }

    println!("Global configuration:");
    println!(
        "Default number of CPUs for newly created VMs: {}",
        cfg.default_cpus
    );
    println!(
        "Default amount of RAM (MiB) for newly created VMs: {}",
        cfg.default_mem
    );
    println!(
        "Default DNS server for newly created VMs: {}",
        cfg.default_dns
    );
}
07070100000019000081A4000000000000000000000001636923F10000191D000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/create.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::fs;
use std::io::Write;
#[cfg(target_os = "macos")]
use std::path::Path;
use std::process::Command;

use super::utils::{
    get_buildah_args, mount_container, parse_mapped_ports, parse_mapped_volumes, umount_container,
    BuildahCommand,
};
use crate::{ArgMatches, KrunvmConfig, VmConfig, APP_NAME};

#[cfg(target_os = "macos")]
const KRUNVM_ROSETTA_FILE: &str = ".krunvm-rosetta";

fn fix_resolv_conf(rootfs: &str, dns: &str) -> Result<(), std::io::Error> {
    let resolvconf_dir = format!("{}/etc/", rootfs);
    fs::create_dir_all(resolvconf_dir)?;
    let resolvconf = format!("{}/etc/resolv.conf", rootfs);
    let mut file = fs::File::create(resolvconf)?;
    file.write_all(b"options use-vc\nnameserver ")?;
    file.write_all(dns.as_bytes())?;
    file.write_all(b"\n")?;
    Ok(())
}

fn export_container_config(
    cfg: &KrunvmConfig,
    rootfs: &str,
    image: &str,
) -> Result<(), std::io::Error> {
    let mut args = get_buildah_args(cfg, BuildahCommand::Inspect);
    args.push(image.to_string());

    let output = match Command::new("buildah")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing buildah: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!(
            "buildah returned an error: {}",
            std::str::from_utf8(&output.stdout).unwrap()
        );
        std::process::exit(-1);
    }

    let mut file = fs::File::create(format!("{}/.krun_config.json", rootfs))?;
    file.write_all(&output.stdout)?;

    Ok(())
}

pub fn create(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
    let mut cpus = match matches.value_of("cpus") {
        Some(c) => match c.parse::<u32>() {
            Err(_) => {
                println!("Invalid value for \"cpus\"");
                std::process::exit(-1);
            }
            Ok(cpus) => cpus,
        },
        None => cfg.default_cpus,
    };
    let mem = match matches.value_of("mem") {
        Some(m) => match m.parse::<u32>() {
            Err(_) => {
                println!("Invalid value for \"mem\"");
                std::process::exit(-1);
            }
            Ok(mem) => mem,
        },
        None => cfg.default_mem,
    };
    let dns = match matches.value_of("dns") {
        Some(d) => d,
        None => &cfg.default_dns,
    };

    let workdir = matches.value_of("workdir").unwrap();

    let volume_matches = if matches.is_present("volume") {
        matches.values_of("volume").unwrap().collect()
    } else {
        vec![]
    };
    let mapped_volumes = parse_mapped_volumes(volume_matches);

    let port_matches = if matches.is_present("port") {
        matches.values_of("port").unwrap().collect()
    } else {
        vec![]
    };
    let mapped_ports = parse_mapped_ports(port_matches);

    let image = matches.value_of("IMAGE").unwrap();

    let name = matches.value_of("name");
    if let Some(name) = name {
        if cfg.vmconfig_map.contains_key(name) {
            println!("A VM with this name already exists");
            std::process::exit(-1);
        }
    }

    let mut args = get_buildah_args(cfg, BuildahCommand::From);

    #[cfg(target_os = "macos")]
    let force_x86 = matches.is_present("x86");

    #[cfg(target_os = "macos")]
    if force_x86 {
        let home = match std::env::var("HOME") {
            Err(e) => {
                println!("Error reading \"HOME\" enviroment variable: {}", e);
                std::process::exit(-1);
            }
            Ok(home) => home,
        };

        let path = format!("{}/{}", home, KRUNVM_ROSETTA_FILE);
        if !Path::new(&path).is_file() {
            println!(
                "
To use Rosetta for Linux you need to create the file...

{}

...with the contents that the \"rosetta\" binary expects to be served from
its specific ioctl.

For more information, please refer to this post:
https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/
",
                path
            );
            std::process::exit(-1);
        }

        if cpus != 1 {
            println!("x86 microVMs on Aarch64 are restricted to 1 CPU");
            cpus = 1;
        }
        args.push("--arch".to_string());
        args.push("x86_64".to_string());
    }

    args.push(image.to_string());

    let output = match Command::new("buildah")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing buildah: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!(
            "buildah returned an error: {}",
            std::str::from_utf8(&output.stdout).unwrap()
        );
        std::process::exit(-1);
    }

    let container = std::str::from_utf8(&output.stdout).unwrap().trim();
    let name = if let Some(name) = name {
        name.to_string()
    } else {
        container.to_string()
    };
    let vmcfg = VmConfig {
        name: name.clone(),
        cpus,
        mem,
        dns: dns.to_string(),
        container: container.to_string(),
        workdir: workdir.to_string(),
        mapped_volumes,
        mapped_ports,
    };

    let rootfs = mount_container(cfg, &vmcfg).unwrap();
    export_container_config(cfg, &rootfs, image).unwrap();
    fix_resolv_conf(&rootfs, dns).unwrap();
    #[cfg(target_os = "macos")]
    if force_x86 {
        _ = fs::create_dir(format!("{}/.rosetta", rootfs));
    }
    umount_container(cfg, &vmcfg).unwrap();

    cfg.vmconfig_map.insert(name.clone(), vmcfg);
    confy::store(APP_NAME, cfg).unwrap();

    println!("microVM created with name: {}", name);
}
0707010000001A000081A4000000000000000000000001636923F10000027A000000000000000000000000000000000000002600000000krunvm-0.2.3+git12dac81/src/delete.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::{ArgMatches, KrunvmConfig, APP_NAME};

use super::utils::{remove_container, umount_container};

pub fn delete(cfg: &mut KrunvmConfig, matches: &ArgMatches) {
    let name = matches.value_of("NAME").unwrap();

    let vmcfg = match cfg.vmconfig_map.remove(name) {
        None => {
            println!("No VM found with that name");
            std::process::exit(-1);
        }
        Some(vmcfg) => vmcfg,
    };

    umount_container(cfg, &vmcfg).unwrap();
    remove_container(cfg, &vmcfg).unwrap();

    confy::store(APP_NAME, &cfg).unwrap();
}
0707010000001B000081A4000000000000000000000001636923F10000031D000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/src/list.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::{ArgMatches, KrunvmConfig, VmConfig};

pub fn printvm(vm: &VmConfig) {
    println!("{}", vm.name);
    println!(" CPUs: {}", vm.cpus);
    println!(" RAM (MiB): {}", vm.mem);
    println!(" DNS server: {}", vm.dns);
    println!(" Buildah container: {}", vm.container);
    println!(" Workdir: {}", vm.workdir);
    println!(" Mapped volumes: {:?}", vm.mapped_volumes);
    println!(" Mapped ports: {:?}", vm.mapped_ports);
}

pub fn list(cfg: &KrunvmConfig, _matches: &ArgMatches) {
    if cfg.vmconfig_map.is_empty() {
        println!("No microVMs found");
    } else {
        for (_name, vm) in cfg.vmconfig_map.iter() {
            println!();
            printvm(vm);
        }
        println!();
    }
}
0707010000001C000081A4000000000000000000000001636923F10000300E000000000000000000000000000000000000002400000000krunvm-0.2.3+git12dac81/src/main.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;
#[cfg(target_os = "macos")]
use std::fs::File;
#[cfg(target_os = "macos")]
use std::io::{self, Read, Write};

use clap::{crate_version, App, Arg, ArgMatches};
use serde_derive::{Deserialize, Serialize};
#[cfg(target_os = "macos")]
use text_io::read;

#[allow(unused)]
mod bindings;
mod changevm;
mod config;
mod create;
mod delete;
mod list;
mod start;
mod utils;

const APP_NAME: &str = "krunvm";

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct VmConfig {
    name: String,
    cpus: u32,
    mem: u32,
    container: String,
    workdir: String,
    dns: String,
    mapped_volumes: HashMap<String, String>,
    mapped_ports: HashMap<String, String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct KrunvmConfig {
    version: u8,
    default_cpus: u32,
    default_mem: u32,
    default_dns: String,
    storage_volume: String,
    vmconfig_map: HashMap<String, VmConfig>,
}

impl Default for KrunvmConfig {
    fn default() -> KrunvmConfig {
        KrunvmConfig {
            version: 1,
            default_cpus: 2,
            default_mem: 1024,
            default_dns: "1.1.1.1".to_string(),
            storage_volume: String::new(),
            vmconfig_map: HashMap::new(),
        }
    }
}

#[cfg(target_os = "macos")]
fn check_case_sensitivity(volume: &str) -> Result<bool, io::Error> {
    let first_path = format!("{}/krunvm_test", volume);
    let second_path = format!("{}/krunVM_test", volume);
    {
        let mut first = File::create(&first_path)?;
        first.write_all(b"first")?;
    }
    {
        let mut second = File::create(&second_path)?;
        second.write_all(b"second")?;
    }
    let mut data = String::new();
    {
        let mut test = File::open(&first_path)?;

        test.read_to_string(&mut data)?;
    }
    if data == "first" {
        let _ = std::fs::remove_file(first_path);
        let _ = std::fs::remove_file(second_path);
        Ok(true)
    } else {
        let _ = std::fs::remove_file(first_path);
        Ok(false)
    }
}

#[cfg(target_os = "macos")]
fn check_volume(cfg: &mut KrunvmConfig) {
    if !cfg.storage_volume.is_empty() {
        return;
    }

    println!(
        "
On macOS, krunvm requires a dedicated, case-sensitive volume.
You can easily create such volume by executing something like
this on another terminal:

diskutil apfs addVolume disk3 \"Case-sensitive APFS\" krunvm

NOTE: APFS volume creation is a non-destructive action that
doesn't require a dedicated disk nor \"sudo\" privileges. The
new volume will share the disk space with the main container
volume.
"
    );
    loop {
        print!("Please enter the mountpoint for this volume [/Volumes/krunvm]: ");
        io::stdout().flush().unwrap();
        let answer: String = read!("{}\n");

        let volume = if answer.is_empty() {
            "/Volumes/krunvm".to_string()
        } else {
            answer.to_string()
        };

        print!("Checking volume... ");
        match check_case_sensitivity(&volume) {
            Ok(res) => {
                if res {
                    println!("success.");
                    println!("The volume has been configured. Please execute krunvm again");
                    cfg.storage_volume = volume;
                    confy::store(APP_NAME, cfg).unwrap();
                    std::process::exit(-1);
                } else {
                    println!("failed.");
                    println!("This volume failed the case sensitivity test.");
                }
            }
            Err(err) => {
                println!("error.");
                println!("There was an error running the test: {}", err);
            }
        }
    }
}

#[cfg(target_os = "linux")]
fn check_unshare() {
    let uid = unsafe { libc::getuid() };
    if uid != 0 && !std::env::vars().any(|(key, _)| key == "BUILDAH_ISOLATION") {
        println!("Please re-run krunvm inside a \"buildah unshare\" session");
        std::process::exit(-1);
    }
}

fn main() {
    let mut cfg: KrunvmConfig = confy::load(APP_NAME).unwrap();

    let mut app = App::new("krunvm")
        .version(crate_version!())
        .author("Sergio Lopez <slp@redhat.com>")
        .about("Manage microVMs created from OCI images")
        .arg(
            Arg::with_name("v")
                .short("v")
                .multiple(true)
                .help("Sets the level of verbosity"),
        )
        .subcommand(
            App::new("changevm")
                .about("Change the configuration of a microVM")
                .arg(
                    Arg::with_name("cpus")
                        .long("cpus")
                        .help("Number of vCPUs")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("mem")
                        .long("mem")
                        .help("Amount of RAM in MiB")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("workdir")
                        .long("workdir")
                        .short("w")
                        .help("Working directory inside the microVM")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("remove-volumes")
                        .long("remove-volumes")
                        .help("Remove all volume mappings"),
                )
                .arg(
                    Arg::with_name("volume")
                        .long("volume")
                        .short("v")
                        .help("Volume in form \"host_path:guest_path\" to be exposed to the guest")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                )
                .arg(
                    Arg::with_name("remove-ports")
                        .long("remove-ports")
                        .help("Remove all port mappings"),
                )
                .arg(
                    Arg::with_name("port")
                        .long("port")
                        .short("p")
                        .help("Port in format \"host_port:guest_port\" to be exposed to the host")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                )
                .arg(
                    Arg::with_name("new-name")
                        .long("name")
                        .help("Assign a new name to the VM")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("NAME")
                        .help("Name of the VM to be modified")
                        .required(true),
                ),
        )
        .subcommand(
            App::new("config")
                .about("Configure global values")
                .arg(
                    Arg::with_name("cpus")
                        .long("cpus")
                        .help("Default number of vCPUs for newly created VMs")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("mem")
                        .long("mem")
                        .help("Default amount of RAM in MiB for newly created VMs")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("dns")
                        .long("dns")
                        .help("DNS server to use in the microVM")
                        .takes_value(true),
                ),
        )
        .subcommand(
            App::new("delete").about("Delete an existing microVM").arg(
                Arg::with_name("NAME")
                    .help("Name of the microVM to be deleted")
                    .required(true)
                    .index(1),
            ),
        )
        .subcommand(
            App::new("list").about("List microVMs").arg(
                Arg::with_name("debug")
                    .short("d")
                    .help("print debug information verbosely"),
            ),
        )
        .subcommand(
            App::new("start")
                .about("Start an existing microVM")
                .arg(Arg::with_name("cpus").long("cpus").help("Number of vCPUs"))
                .arg(
                    Arg::with_name("mem")
                        .long("mem")
                        .help("Amount of RAM in MiB"),
                )
                .arg(
                    Arg::with_name("NAME")
                        .help("Name of the microVM")
                        .required(true)
                        .index(1),
                )
                .arg(
                    Arg::with_name("COMMAND")
                        .help("Command to run inside the VM")
                        .index(2),
                )
                .arg(
                    Arg::with_name("ARGS")
                        .help("Arguments to be passed to the command executed in the VM")
                        .multiple(true)
                        .last(true),
                ),
        );

    let mut create = App::new("create")
        .about("Create a new microVM")
        .arg(
            Arg::with_name("cpus")
                .long("cpus")
                .help("Number of vCPUs")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("mem")
                .long("mem")
                .help("Amount of RAM in MiB")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("dns")
                .long("dns")
                .help("DNS server to use in the microVM")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("workdir")
                .long("workdir")
                .short("w")
                .help("Working directory inside the microVM")
                .takes_value(true)
                .default_value(""),
        )
        .arg(
            Arg::with_name("volume")
                .long("volume")
                .short("v")
                .help("Volume in form \"host_path:guest_path\" to be exposed to the guest")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name("port")
                .long("port")
                .short("p")
                .help("Port in format \"host_port:guest_port\" to be exposed to the host")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1),
        )
        .arg(
            Arg::with_name("name")
                .long("name")
                .help("Assign a name to the VM")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("IMAGE")
                .help("OCI image to use as template")
                .required(true),
        );

    if cfg!(target_os = "macos") {
        create = create.arg(
            Arg::with_name("x86")
                .long("x86")
                .short("x")
                .help("Create a x86_64 microVM even on an Aarch64 host"),
        );
    }

    app = app.subcommand(create);

    let matches = app.clone().get_matches();

    #[cfg(target_os = "macos")]
    check_volume(&mut cfg);
    #[cfg(target_os = "linux")]
    check_unshare();

    if let Some(matches) = matches.subcommand_matches("changevm") {
        changevm::changevm(&mut cfg, matches);
    } else if let Some(matches) = matches.subcommand_matches("config") {
        config::config(&mut cfg, matches);
    } else if let Some(matches) = matches.subcommand_matches("create") {
        create::create(&mut cfg, matches);
    } else if let Some(matches) = matches.subcommand_matches("delete") {
        delete::delete(&mut cfg, matches);
    } else if let Some(matches) = matches.subcommand_matches("list") {
        list::list(&cfg, matches);
    } else if let Some(matches) = matches.subcommand_matches("start") {
        start::start(&cfg, matches);
    } else {
        app.print_long_help().unwrap();
        println!();
    }
}
0707010000001D000081A4000000000000000000000001636923F100001AB0000000000000000000000000000000000000002500000000krunvm-0.2.3+git12dac81/src/start.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::ffi::CString;
use std::fs::File;
#[cfg(target_os = "linux")]
use std::io::{Error, ErrorKind};
use std::os::unix::io::AsRawFd;
#[cfg(target_os = "macos")]
use std::path::Path;

use super::bindings;
use super::utils::{mount_container, umount_container};
use crate::{ArgMatches, KrunvmConfig, VmConfig};

#[cfg(target_os = "linux")]
fn map_volumes(_ctx: u32, vmcfg: &VmConfig, rootfs: &str) {
    for (host_path, guest_path) in vmcfg.mapped_volumes.iter() {
        let host_dir = CString::new(host_path.to_string()).unwrap();
        let guest_dir = CString::new(format!("{}{}", rootfs, guest_path)).unwrap();

        let ret = unsafe { libc::mkdir(guest_dir.as_ptr(), 0o755) };
        if ret < 0 && Error::last_os_error().kind() != ErrorKind::AlreadyExists {
            println!("Error creating directory {:?}", guest_dir);
            std::process::exit(-1);
        }
        unsafe { libc::umount(guest_dir.as_ptr()) };
        let ret = unsafe {
            libc::mount(
                host_dir.as_ptr(),
                guest_dir.as_ptr(),
                std::ptr::null(),
                libc::MS_BIND | libc::MS_REC,
                std::ptr::null(),
            )
        };
        if ret < 0 {
            println!("Error mounting volume {}", guest_path);
            std::process::exit(-1);
        }
    }
}

#[cfg(target_os = "macos")]
fn map_volumes(ctx: u32, vmcfg: &VmConfig, rootfs: &str) {
    let mut volumes = Vec::new();
    for (host_path, guest_path) in vmcfg.mapped_volumes.iter() {
        let full_guest = format!("{}{}", &rootfs, guest_path);
        let full_guest_path = Path::new(&full_guest);
        if !full_guest_path.exists() {
            std::fs::create_dir(full_guest_path)
                .expect("Couldn't create guest_path for mapped volume");
        }
        let map = format!("{}:{}", host_path, guest_path);
        volumes.push(CString::new(map).unwrap());
    }
    let mut vols: Vec<*const i8> = Vec::new();
    for vol in volumes.iter() {
        vols.push(vol.as_ptr());
    }
    vols.push(std::ptr::null());
    let ret = unsafe { bindings::krun_set_mapped_volumes(ctx, vols.as_ptr()) };
    if ret < 0 {
        println!("Error setting VM mapped volumes");
        std::process::exit(-1);
    }
}

unsafe fn exec_vm(vmcfg: &VmConfig, rootfs: &str, cmd: Option<&str>, args: Vec<CString>) {
    //bindings::krun_set_log_level(9);

    let ctx = bindings::krun_create_ctx() as u32;

    let ret = bindings::krun_set_vm_config(ctx, vmcfg.cpus as u8, vmcfg.mem);
    if ret < 0 {
        println!("Error setting VM config");
        std::process::exit(-1);
    }

    let c_rootfs = CString::new(rootfs).unwrap();
    let ret = bindings::krun_set_root(ctx, c_rootfs.as_ptr() as *const i8);
    if ret < 0 {
        println!("Error setting VM rootfs");
        std::process::exit(-1);
    }

    map_volumes(ctx, vmcfg, rootfs);

    let mut ports = Vec::new();
    for (host_port, guest_port) in vmcfg.mapped_ports.iter() {
        let map = format!("{}:{}", host_port, guest_port);
        ports.push(CString::new(map).unwrap());
    }
    let mut ps: Vec<*const i8> = Vec::new();
    for port in ports.iter() {
        ps.push(port.as_ptr() as *const i8);
    }
    ps.push(std::ptr::null());
    let ret = bindings::krun_set_port_map(ctx, ps.as_ptr());
    if ret < 0 {
        println!("Error setting VM port map");
        std::process::exit(-1);
    }

    if !vmcfg.workdir.is_empty() {
        let c_workdir = CString::new(vmcfg.workdir.clone()).unwrap();
        let ret = bindings::krun_set_workdir(ctx, c_workdir.as_ptr() as *const i8);
        if ret < 0 {
            println!("Error setting VM workdir");
            std::process::exit(-1);
        }
    }

    let hostname = CString::new(format!("HOSTNAME={}", vmcfg.name)).unwrap();
    let home = CString::new("HOME=/root").unwrap();
    let env: [*const i8; 3] = [
        hostname.as_ptr() as *const i8,
        home.as_ptr() as *const i8,
        std::ptr::null(),
    ];

    if let Some(cmd) = cmd {
        let mut argv: Vec<*const i8> = Vec::new();
        for a in args.iter() {
            argv.push(a.as_ptr() as *const i8);
        }
        argv.push(std::ptr::null());

        let c_cmd = CString::new(cmd).unwrap();
        let ret = bindings::krun_set_exec(
            ctx,
            c_cmd.as_ptr() as *const i8,
            argv.as_ptr() as *const *const i8,
            env.as_ptr() as *const *const i8,
        );
        if ret < 0 {
            println!("Error setting VM config");
            std::process::exit(-1);
        }
    } else {
        let ret = bindings::krun_set_env(ctx, env.as_ptr() as *const *const i8);
        if ret < 0 {
            println!("Error setting VM environment variables");
            std::process::exit(-1);
        }
    }

    let ret = bindings::krun_start_enter(ctx);
    if ret < 0 {
        println!("Error starting VM");
        std::process::exit(-1);
    }
}

fn set_rlimits() {
    let mut limit = libc::rlimit {
        rlim_cur: 0,
        rlim_max: 0,
    };

    let ret = unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut limit) };
    if ret < 0 {
        panic!("Couldn't get RLIMIT_NOFILE value");
    }

    limit.rlim_cur = limit.rlim_max;
    let ret = unsafe { libc::setrlimit(libc::RLIMIT_NOFILE, &limit) };
    if ret < 0 {
        panic!("Couldn't set RLIMIT_NOFILE value");
    }
}

fn set_lock(rootfs: &str) -> File {
    let lock_path = format!("{}/.krunvm.lock", rootfs);
    let file = File::create(lock_path).expect("Couldn't create lock file");

    let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
    if ret < 0 {
        println!("Couldn't acquire lock file. Is another instance of this VM already running?");
        std::process::exit(-1);
    }

    file
}

pub fn start(cfg: &KrunvmConfig, matches: &ArgMatches) {
    let cmd = matches.value_of("COMMAND");
    let name = matches.value_of("NAME").unwrap();

    let vmcfg = match cfg.vmconfig_map.get(name) {
        None => {
            println!("No VM found with name {}", name);
            std::process::exit(-1);
        }
        Some(vmcfg) => vmcfg,
    };

    umount_container(cfg, vmcfg).expect("Error unmounting container");
    let rootfs = mount_container(cfg, vmcfg).expect("Error mounting container");

    let args: Vec<CString> = if cmd.is_some() {
        match matches.values_of("ARGS") {
            Some(a) => a.map(|val| CString::new(val).unwrap()).collect(),
            None => Vec::new(),
        }
    } else {
        Vec::new()
    };

    set_rlimits();

    let _file = set_lock(&rootfs);

    unsafe { exec_vm(vmcfg, &rootfs, cmd, args) };

    umount_container(cfg, vmcfg).expect("Error unmounting container");
}
0707010000001E000081A4000000000000000000000001636923F1000020EF000000000000000000000000000000000000002500000000krunvm-0.2.3+git12dac81/src/utils.rs// Copyright 2021 Red Hat, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;
use std::path::Path;
use std::process::Command;

use crate::{KrunvmConfig, VmConfig, APP_NAME};

pub enum BuildahCommand {
    From,
    Inspect,
    Mount,
    Unmount,
    Remove,
}

#[cfg(target_os = "linux")]
pub fn get_buildah_args(_cfg: &KrunvmConfig, cmd: BuildahCommand) -> Vec<String> {
    match cmd {
        BuildahCommand::From => vec!["from".to_string()],
        BuildahCommand::Inspect => vec!["inspect".to_string()],
        BuildahCommand::Mount => vec!["mount".to_string()],
        BuildahCommand::Unmount => vec!["umount".to_string()],
        BuildahCommand::Remove => vec!["rm".to_string()],
    }
}

#[cfg(target_os = "macos")]
pub fn get_buildah_args(cfg: &KrunvmConfig, cmd: BuildahCommand) -> Vec<String> {
    let mut hbpath = std::env::current_exe().unwrap();
    hbpath.pop();
    hbpath.pop();
    let hbpath = hbpath.as_path().display();
    let policy_json = format!("{}/etc/containers/policy.json", hbpath);
    let registries_json = format!("{}/etc/containers/registries.conf", hbpath);
    let storage_root = format!("{}/root", cfg.storage_volume);
    let storage_runroot = format!("{}/runroot", cfg.storage_volume);

    let mut args = vec![
        "--root".to_string(),
        storage_root,
        "--runroot".to_string(),
        storage_runroot,
    ];

    match cmd {
        BuildahCommand::From => {
            args.push("--signature-policy".to_string());
            args.push(policy_json);
            args.push("--registries-conf".to_string());
            args.push(registries_json);

            args.push("from".to_string());
            args.push("--os".to_string());
            args.push("linux".to_string());
        }
        BuildahCommand::Inspect => {
            args.push("inspect".to_string());
        }
        BuildahCommand::Mount => {
            args.push("mount".to_string());
        }
        BuildahCommand::Unmount => {
            args.push("umount".to_string());
        }
        BuildahCommand::Remove => {
            args.push("rm".to_string());
        }
    }
    args
}

pub fn parse_mapped_ports(port_matches: Vec<&str>) -> HashMap<String, String> {
    let mut mapped_ports = HashMap::new();
    for port in port_matches.iter() {
        let vtuple: Vec<&str> = port.split(':').collect();
        if vtuple.len() != 2 {
            println!("Invalid value for \"port\"");
            std::process::exit(-1);
        }
        let host_port: u16 = match vtuple[0].parse() {
            Ok(p) => p,
            Err(_) => {
                println!("Invalid host port");
                std::process::exit(-1);
            }
        };
        let guest_port: u16 = match vtuple[1].parse() {
            Ok(p) => p,
            Err(_) => {
                println!("Invalid guest port");
                std::process::exit(-1);
            }
        };

        mapped_ports.insert(host_port.to_string(), guest_port.to_string());
    }

    mapped_ports
}

pub fn parse_mapped_volumes(volume_matches: Vec<&str>) -> HashMap<String, String> {
    let mut mapped_volumes = HashMap::new();
    for volume in volume_matches.iter() {
        let vtuple: Vec<&str> = volume.split(':').collect();
        if vtuple.len() != 2 {
            println!("Invalid value for \"volume\"");
            std::process::exit(-1);
        }
        let host_path = Path::new(vtuple[0]);
        if !host_path.is_absolute() {
            println!("Invalid volume, host_path is not an absolute path");
            std::process::exit(-1);
        }
        if !host_path.exists() {
            println!("Invalid volume, host_path does not exists");
            std::process::exit(-1);
        }
        let guest_path = Path::new(vtuple[1]);
        if !guest_path.is_absolute() {
            println!("Invalid volume, guest_path is not an absolute path");
            std::process::exit(-1);
        }
        if guest_path.components().count() != 2 {
            println!(
                "Invalid volume, only single direct root children are supported as guest_path"
            );
            std::process::exit(-1);
        }
        mapped_volumes.insert(
            host_path.to_str().unwrap().to_string(),
            guest_path.to_str().unwrap().to_string(),
        );
    }

    mapped_volumes
}

#[cfg(target_os = "macos")]
fn fix_root_mode(rootfs: &str) {
    let mut args = vec!["-w", "user.containers.override_stat", "0:0:0555"];
    args.push(rootfs);

    let output = match Command::new("xattr")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires xattr to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing xattr: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!("xattr returned an error: {}", exit_code);
        std::process::exit(-1);
    }
}

#[allow(unused_variables)]
pub fn mount_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<String, std::io::Error> {
    let mut args = get_buildah_args(cfg, BuildahCommand::Mount);
    args.push(vmcfg.container.clone());

    let output = match Command::new("buildah")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing buildah: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!(
            "buildah returned an error: {}",
            std::str::from_utf8(&output.stdout).unwrap()
        );
        std::process::exit(-1);
    }

    let rootfs = std::str::from_utf8(&output.stdout).unwrap().trim();

    #[cfg(target_os = "macos")]
    fix_root_mode(&rootfs);

    Ok(rootfs.to_string())
}

#[allow(unused_variables)]
pub fn umount_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<(), std::io::Error> {
    let mut args = get_buildah_args(cfg, BuildahCommand::Unmount);
    args.push(vmcfg.container.clone());

    let output = match Command::new("buildah")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing buildah: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!(
            "buildah returned an error: {}",
            std::str::from_utf8(&output.stdout).unwrap()
        );
        std::process::exit(-1);
    }

    Ok(())
}

#[allow(unused_variables)]
pub fn remove_container(cfg: &KrunvmConfig, vmcfg: &VmConfig) -> Result<(), std::io::Error> {
    let mut args = get_buildah_args(cfg, BuildahCommand::Remove);
    args.push(vmcfg.container.clone());

    let output = match Command::new("buildah")
        .args(&args)
        .stderr(std::process::Stdio::inherit())
        .output()
    {
        Ok(output) => output,
        Err(err) => {
            if err.kind() == std::io::ErrorKind::NotFound {
                println!("{} requires buildah to manage the OCI images, and it wasn't found on this system.", APP_NAME);
            } else {
                println!("Error executing buildah: {}", err);
            }
            std::process::exit(-1);
        }
    };

    let exit_code = output.status.code().unwrap_or(-1);
    if exit_code != 0 {
        println!(
            "buildah returned an error: {}",
            std::str::from_utf8(&output.stdout).unwrap()
        );
        std::process::exit(-1);
    }

    Ok(())
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!155 blocks
openSUSE Build Service is sponsored by