#!/bin/sh
#  This file is part of cc-oci-runtime.
#
#  Copyright (C) 2016 Intel Corporation
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

# Description: Script to create a bundle directory that can be made
#   into a full OCI bundle when a "config.json" file is created within it.
#
# On success, this script will create the directory specified as a
# bundle directory. This directory can be used as an OCI bundle once it
# has had a "config.json" file added to it. The directory created will
# contain a sub-directory called "rootfs" (which is the canonical path to
# the rootfs specified by an OCI bundle).
#
# See the following for further details:
#
# - https://github.com/opencontainers/runtime-spec/blob/master/bundle.md

# Name of a small docker image that create_rootfs() uses
# to make a chroot directory.
docker_image="busybox"

program_name=${0##*/}

# Display a warning message.
#
# Parameters:
#
# $1 .. $n: Message to display.
#
# Note that the message is sent to stdout since some build systems treat
# any stderr output as a hard failure.
warn()
{
	local msg="$*"
	echo "WARNING: $program_name: $msg"
}

# Display an error message and exit.
#
# Parameters:
#
# $1 .. $n: Message to display.
#
die()
{
	local msg="$*"
	echo >&2 "ERROR: $program_name: $msg"
	exit 1
}

# Create an OCI bundle directory containing a rootfs sub-directory
# containing a "rootfs" directory.
#
# The rootfs is generated by docker from $docker_image.
#
# Parameters:
#
# $1: Name of directory to create as the bundle directory.
#
# Returns: 0 on success, 1 on error.
create_bundle_dir()
{
	local bundle_dir="$1"
	local rootfs_dir="${bundle_dir}/rootfs"

	docker info >/dev/null 2>&1 || { warn "cannot connect to docker"; return 1; }

	mkdir -p "$rootfs_dir"
	tmp=$(mktemp -d)

	# create a small container
	container=$(docker create "${docker_image}" 2>/dev/null)
	[ -z "$container" ] && { warn "cannot create docker image"; return 1; }

	# flatten the just-created container
	name=$(docker export "$container" |\
		docker import - 2>/dev/null)
	[ -z "$name" ] && { warn "cannot flatten docker image"; return 1; }

	tar="${tmp}/${name}.tar"

	# export the container as a tar file
	docker save "$name" > "$tar"
	[ $? -eq 0 ] || { warn "cannot save docker image"; return 1; }

	docker rmi "$name" >/dev/null 2>&1
	[ $? -eq 0 ] || { warn "cannot remove temporary docker image"; return 1; }

	# extract the container files
	tar -C "$tmp" -xf "$tar" >/dev/null 2>&1
	[ $? -eq 0 ] || { warn "cannot extract docker container"; return 1; }

	# find the filesystem layer
	# (only 1 layer as the image has been flattened)
	fs=$(find "$tmp" -name layer.tar || true)
	[ -n "$fs" ] || { warn "cannot find filesystem layer"; return 1; }

	# unpack
	tar -C "${rootfs_dir}" -xf "$fs" >/dev/null 2>&1
	[ $? -eq 0 ] || { warn "cannot unpack filesystem layer"; return 1; }

	# clean up
	rm -rf "$tmp"

	# success
	return 0
}

[ -n "$1" ] || die "need directory to create bundle in"

create_bundle_dir "$1"
