Recovery library implements an API that allows you to configure the different supported recovery commands and the reboot into recovery mode. This library is installed in the toolchain provided by Digi Embedded Yocto, so you can use it to develop your own custom application with support to trigger recovery commands. See Application development.

Using the library

To use the library you need to:

  1. Include the recovery header file in your application.

    #include <recovery.h>
  2. Link against the recovery static library already included in the pre-compiled toolchain. The library provides a pkg-config file recovery.pc, installed in the toolchain. To configure the proper compilation flags and linked libraries, add the following lines into your makefile:

    [...]
    
    CFLAGS += $(shell pkg-config --cflags recovery)
    LDLIBS += $(shell pkg-config --libs --static recovery)
    
    [...]

Implemented functions

These are the functions implemented on the current release:

Function Description

int encrypt_partitions(char *to_encrypt, char *to_unencrypt, unsigned char force)

Configures recovery commands to encrypt/un-encrypt provided partitions If force is different than 0, the library won’t ask for confirmation before configuring the commands. It returns 0 on success, -1 on failure, and 1 on success with no recovery command set.

To finalize the (un)encryption process you must call the reboot_recovery() function after this one. If the function returns 1, it means the commands haven’t been configured either because the user cancelled the operation or because the inputs don’t change the partitions' current state.

int update_firmware(const char *swu_path)

Configures recovery commands to update the firmware using the package specified in swu_path. It returns 0 on success, -1 on failure.

To start the update process you must call the reboot_recovery() function after this one.

int set_encryption_key(const char *key, unsigned char force)

Configures recovery commands to set a new file system encryption key. If key is empty or NULL, a random key will be generated. If force is different than 0, the library won’t ask for confirmation before configuring the commands. It returns 0 on success, -1 on failure, and 1 on success with no recovery command set.

To set the new configured encryption key you must call the reboot_recovery() function after this one. If the function returns 1, it means the commands haven’t been configured because the user cancelled the operation.

int reboot_recovery(unsigned int reboot_timeout)

Reboots into recovery mode after reboot_timeout seconds. It returns -1 on failure, otherwise it does not return, the system reboots.

The configured recovery commands will be applied after booting in recovery mode.

int wipe_update_partition(void)

Configures recovery commands to wipe and format the update partition. It returns 0 on success, -1 on failure.

To start the wipe process you must call reboot_recovery() function after this one.

Example code

The following excerpt (not directly compilable) demonstrates how to use the library:

#include <recovery.h>

int main(int argc, char *argv[])
{
    int ret = 0;
    unsigned char need_reboot = 0;

    /* Read and parse command line */
    parse_options(argc, argv);

    /*
     * Variables after parsing command line:
     *
     * swu_package:    path to the software update package
     * key_set:        boolean flag to set a new encryption key
     * key:            new encryption key
     * to_encrypt:     comma-separated list of partitions that need to be encrypted
     * to_unencrypt:   comma-separated list of partitions that need to be unencrypted
     * wipe_update:    boolean flag to wipe or not the `update` partition
     * reboot_timeout: time to wait to perform the reboot
     */

    if (set_key) {
        /* Configure recovery commands to set a fs encryption key */
        ret = set_encryption_key(key, force);
        if (ret < 0) {
            printf("Error: set_encryption_key\n");
            goto out;
        } else if (ret == 0) {
            /*
             * Only reboot if strictly necessary, since the function
             * might succeed without setting a recovery command
             * (for example, if a user cancels the operation).
             */
            need_reboot++;
        } else {
            ret = 0;
        }
    }

    if (swu_package) {
        /* Configure recovery commands to update the firmware */
        ret = update_firmware(swu_package);
        if (ret) {
            printf("Error: update_firmware\n");
            goto out;
        }
            need_reboot++;
    }

    if (wipe_update) {
        /* Configure recovery commands to format 'update' partition */
        ret = wipe_update_partition();
        if (ret) {
            printf("Error: wipe_update_partition\n");
            goto out;
        }
            need_reboot++;
    }

    if (to_encrypt || to_unencrypt) {
        /* Configure recovery commands to encrypt/unencrypt partitions */
        ret = encrypt_partitions(to_encrypt, to_unencrypt, force);
        if (ret < 0) {
            printf("Error: encrypt_partitions\n");
            goto out;
        } else if (ret == 0) {
            /*
             * Only reboot if strictly necessary, since the function
             * might succeed without setting a recovery command
             * (for example, if you try to encrypt partitions that
             * are already encrypted).
             */
            need_reboot++;
        } else {
            ret = 0;
        }
    }

    if (need_reboot > 0) {
        /* Reboot to recovery */
        ret = reboot_recovery(reboot_timeout);
        if (ret) {
            printf("Error: reboot_recovery\n");
            goto out;
        }
    }

    printf("\nNo recovery commands configured.\n");
out:
    return ret;
}