# Runtime boot pre-generated UnionFS image

Generally, every Occlum instance has to pass the `Occlum build` process.
In some scenarios, mount and boot a pre-generated UnionFS image without `Occlum build` is a good feature. This demo introduces a way to runtime boot a BASH demo.

## Flow

### First, build a [`BASH`](../bash) Occlum instance

The later step will use the image content to generate UnionFS image.

### Build and start a [`gen_rootfs`](./gen_rootfs) Occlum instance

This `gen_rootfs` mounts a empty **sefs** (uses the lower path as mount target dir), copy the BASH Occlum image content to the mount point, unmount the **sefs**. It generates an encrypted **sefs** image containing the BASH image content. The **key** used in this demo is `"c7-32-b3-ed-44-df-ec-7b-25-2d-9a-32-38-8d-58-61"`.

### Build customized [`init`](./init)

Occlum [`default init`](../../tools/init) calls syscall (363) `MountRootFS` to mount and boot Occlum instance generated by normal `occlum build`.
```
(MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, rootfs_config: *const user_rootfs_config)
```
The first parameter `key_ptr` is optional.
The second parameter `rootfs_config` needs to be set as NULL.

But for runtime booting pre-generated image, The first parameter `key_ptr` is must to have, the second parameter `rootfs_config` needs have valid members.
```
struct user_rootfs_config {
    // length of the struct
    len: usize,
    // UnionFS type rootfs upper layer, read-write layer
    upper_layer_path: *const i8,
    // UnionFS type rootfs lower layer, read-only layer
    lower_layer_path: *const i8,
    entry_point: *const i8,
    // HostFS source path
    hostfs_source: *const i8,
    // HostFS target path, default value is "/host"
    hostfs_target: *const i8,
    // An array of pointers to null-terminated strings
    // and must be terminated by a null pointer
    envp: *const *const i8,
}
```

In this demo, parameters values are provided as below.

* **len**
The length of the struct which should be the value of `size_of(user_rootfs_config)`.
It is helpful for possible future extension.

* **rootfs_key**
The key to encrypt/decrypt the rootfs, here it is `"c7-32-b3-ed-44-df-ec-7b-25-2d-9a-32-38-8d-58-61".

* **rootfs_upper_layer**
The upper layer path of the unionfs type rootfs. In this case, it is relative path `"../gen_rootfs_instance/mnt_unionfs/upper"`.

* **rootfs_lower_layer**
The lower layer path of the unionfs type rootfs. In this case, it is relative path `"../gen_rootfs_instance/mnt_unionfs/lower"`.

* **rootfs_entry**
The entry point of the rootfs. In his case, it is `"/bin"`.

* **hostfs_source**
It is set to be `/tmp` in this case.

* **envp**
An array of pointers to null-terminated strings and must be terminated by a null pointer.
For example, set it to the address of ["TEST=1234", "TEST2=4567", NULL].

In this example customized init, the above parameters are declared in the source [`main.rs`](./init/src/main.rs). In real case, they could be acquired by LA/RA or by modifying the PAL api `pal_run_init_process`.

### Build a boot template Occlum instance

This template uses the customized init. The RootFS image is not important, which will be replaced during boot.

All above steps could be done with one [`script`](./build_content.sh).
```
./build_content.sh
```

After running the script, runtime boot BASH could be done as below even if the default RootFS image has no BASH function.
```
# cd boot_instance
# occlum run /bin/occlum_bash_test.sh
```

Also, the runtime environment passed by **envp** could be verified by
```
# occlum run /bin/busybox env
```
