# Single File

**URL:** <https://hub.mender.io/t/single-file/486>\
**Category:** Update Modules\
**Created:** [April 16, 2019, 1:55pm UTC](https://hub.mender.io/t/single-file/486 "2019-04-16T13:55:59Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![lluiscampos](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/lluiscampos/32/112_2.png) [@lluiscampos](https://hub.mender.io/u/lluiscampos)\
**Post date:** [April 16, 2019, 1:55pm UTC](https://hub.mender.io/t/single-file/486/1 "2019-04-16T13:55:59Z")

</div>

### Description

The Single File Update Module installs a user defined file into a given destination directory on the device.

If the file already exists in the destination folder on the device, the Update Module will take a backup copy of it. This allows the Mender client to rollback if something goes wrong.

Example use-cases:

- Updating a single-binary application
- Updating a operating system-wide configuration file

### Specification

| | |
| --- | --- |
| Module name | single-file |
| Supports rollback | yes |
| Requires restart | no |
| Artifact generation script | yes |
| Full operating system updater | no |
| Source code | [Update Module](https://github.com/mendersoftware/mender/blob/master/support/modules/single-file), [Artifact Generator](https://github.com/mendersoftware/mender/blob/master/support/modules-artifact-gen/single-file-artifact-gen) |
| Maintainer | Northern.tech |

**It is not recommended to install a Mender Artifact on your workstation**

## Prepare the device

This section describes how to setup your target device, i.e. the device to be updated. This will also be referred to as the device environment.

All commands outlined in this section should be run in the device environment.

### Prerequisites

This update module has the following prerequisites for the device environment:

- [Install the Mender client](https://docs.mender.io/client-installation/install-with-debian-package), version 2.0 or later

### Install the Update Module

Download the latest version of this Update Module by running:

```bash
mkdir -p /usr/share/mender/modules/v3 && wget -N -P /usr/share/mender/modules/v3 https://raw.githubusercontent.com/mendersoftware/mender/master/support/modules/single-file

```

## Prepare the development environment on your workstation

This section describes how to set up your development environment on your workstation.

All commands outlined in this section should be run in the development environment.

### Prerequisites

This Update Modules has the following prerequisites for the development environment:

- [Install mender-artifact](https://docs.mender.io/downloads), version 3.1.0 or later

### Create Mender Artifacts

For convenience, an Artifact generator tool `single-file-artifact-gen` is provided with the Update Module. This tool will generate [Mender Artifacts](https://docs.mender.io/overview/artifact) in the same format that the Update Module expects them.

Download `single-file-artifact-gen`, by running the following command:

```bash
wget https://raw.githubusercontent.com/mendersoftware/mender/master/support/modules-artifact-gen/single-file-artifact-gen

```

Make it executable:

```bash
chmod +x single-file-artifact-gen

```

Create example file to deploy:

```bash
echo "File created by Mender single-file Update Module!" > my_file.txt

```

Now generate a Mender Artifact using the following command:

```bash
ARTIFACT_NAME="my-update-1.0"
DEVICE_TYPE="my-device-type"
OUTPUT_PATH="my-update-1.0.mender"
DEST_DIR="/opt/installed-by-single-file/"
FILE="my_file.txt"
./single-file-artifact-gen -n ${ARTIFACT_NAME} -t ${DEVICE_TYPE} -d ${DEST_DIR} -o ${OUTPUT_PATH} ${FILE}

```

- `ARTIFACT_NAME` - The name of the Mender Artifact
- `DEVICE_TYPE` - The compatible device type of this Mender Artifact
- `OUTPUT_PATH` - The path where to place the output Mender Artifact. This should always have a `.mender` suffix
- `DEST_DIR` - The path on target device where `FILE` will be installed.
- `FILE` - The path to the file to be sent to the device in the update.

You can either deploy this Artifact in managed mode with the Mender server (upload it under Releases in the server UI) or by using the Mender client only in [Standalone deployments](https://docs.mender.io/artifact-creation/standalone-deployment).

### Artifact technical details

The Mender Artifact used by this Update Module has three payload files: a regular file with the `DEST_DIR` in plain text, a regular file with the filename of the user file in plain text, and the user file itself.

The Mender Artifact contents will look like:

```bash
Updates:
    0:
    Type: single-file
    Provides: Nothing
    Depends: Nothing
    Metadata: Nothing
    Files:
        name: dest_dir
        size: 39
        modified: 2019-04-16 15:29:40 +0200 CEST
        checksum: 58581d50870f179e80a73844f96ab3ef7dd7335aefb21562521674310fb72856
    Files:
        name: filename
        size: 12
        modified: 2019-04-16 15:29:40 +0200 CEST
        checksum: 0d6b8085d25a0eb9862ec0642f2d1e1aacbeb85d826cdeb570f19ba2719507a9
    Files:
        name: my_file.txt
        size: 60
        modified: 2019-04-16 15:29:16 +0200 CEST
        checksum: 5e93fe626d6ff553736b48c343b2d1b258960aab24b1b38496c3cf7a1fe5df51

```

---

<div class="post-metadata">

**Author:** ![ajithpv](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/ajithpv/32/728_2.png) [@ajithpv](https://hub.mender.io/u/ajithpv)\
**Post date:** [April 29, 2019, 12:28pm UTC](https://hub.mender.io/t/single-file/486/2 "2019-04-29T12:28:05Z")

</div>

@lluiscampos Thank you for providing the single file update module.

There is already one file-install script present as below while build and run the mender 2.0.0 beta:

> cat /usr/share/mender/modules/v3/file-install  
> #!/bin/bash
> 
> set -e
> 
> STATE=“$1”  
> FILES=“$2”
> 
> prev\_files\_tar=“$FILES”/tmp/prev\_files.tar  
> update\_files\_tar=“$FILES”/files/update.tar  
> dest\_dir\_file=“$FILES”/files/dest\_dir
> 
> case “$STATE” in
> 
> ```
> NeedsArtifactReboot)
> echo "No"
> ;;
> 
> SupportsRollback)
> echo "Yes"
> ;;
> 
> ArtifactInstall)
> dest_dir=$(cat $dest_dir_file)
> [[-d $dest_dir]] || install -d $dest_dir
> tar -cf ${prev_files_tar} -C ${dest_dir} .
> rm -rf ${dest_dir}
> mkdir -p ${dest_dir}
> tar -xf ${update_files_tar} -C ${dest_dir}
> ;;
> 
> ArtifactRollback)
> dest_dir=$(cat $dest_dir_file)
> [[-f $prev_files_tar]] || exit 0
> [[-n "$dest_dir"]] || exit 1
> rm -rf ${dest_dir}
> mkdir -p ${dest_dir}
> tar -xf ${prev_files_tar} -C ${dest_dir}
> ;;
> 
> ```
> 
> esac
> 
> exit 0

Whether the already present script supports both file and directory update with the same script? Any document for the provided script (file-install) available? How to generate and pass the below identities?

> prev\_files\_tar=“$FILES”/tmp/prev\_files.tar  
> update\_files\_tar=“$FILES”/files/update.tar  
> dest\_dir\_file=“$FILES”/files/dest\_dir

May I know which is better (already provided one (i.e. file-install) or single-file/directory update script from mender hub)?

---

<div class="post-metadata">

**Author:** ![lluiscampos](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/lluiscampos/32/112_2.png) [@lluiscampos](https://hub.mender.io/u/lluiscampos)\
**Post date:** [April 29, 2019, 12:44pm UTC](https://hub.mender.io/t/single-file/486/3 "2019-04-29T12:44:41Z")

</div>

Hi @ajithpv,

The `file-install` Update Module from the 2.0.0 beta is going to be deprecated in the final release and instead we are providing two independent ones: `single-file` and `directory`.

As you have noticed, the old one supported both use cases, and we thought it we be clearer to just split them in two simpler ones.

Please use the new ones.

---

<div class="post-metadata">

**Author:** ![speeltronics](https://avatars.discourse-cdn.com/v4/letter/s/6f9a4e/32.png) [@speeltronics](https://hub.mender.io/u/speeltronics)\
**Post date:** [May 8, 2019, 10:37pm UTC](https://hub.mender.io/t/single-file/486/4 "2019-05-08T22:37:23Z")

</div>

Hi, I have an integrated build with u-boot that has worked great since version 1.6 with full updates. I updated my device to 2.0 to test out this new module feature. I did not mess with any u-boot integration this timeso it is still at the changes for 1.6, because I am just trying to do the module updates and didn’t figure I would need to make changes to u-boot for the modules. I have also updated my server to 2.0. I created an update as per this page and my device keeps giving me an error that I am not sure about.

“level=error msg=“Fetching Artifact headers failed: installer: failed to read Artifact: readHeaderV3: handleHeaderReads: Cannot load handler for unknown Payload type ‘single-file’” module=state”

Then it waits and tries again in a min and keeps giving that same error.

Any idea what I am doing wrong?

Thanks!

---

<div class="post-metadata">

**Author:** ![eystein](https://avatars.discourse-cdn.com/v4/letter/e/e5b9ba/32.png) [@eystein](https://hub.mender.io/u/eystein)\
**Post date:** [May 8, 2019, 10:48pm UTC](https://hub.mender.io/t/single-file/486/5 "2019-05-08T22:48:19Z")

</div>

Hi @speeltronics and welcome to Mender Hub! 🙂

This error indicates that the Single File Update Module is not installed on the device where you are trying to install an Artifact Payload of this type.

To verify, run this command on your device:

```auto
mkdir -p /usr/share/mender/modules/v3 && wget -N -P /usr/share/mender/modules/v3 https://raw.githubusercontent.com/mendersoftware/mender/master/support/modules/single-file

```

Then re-try the deployment.

If this works then you need to simply make sure that this Update Module (single-file script) is present at this location in your image builds.

---

<div class="post-metadata">

**Author:** ![speeltronics](https://avatars.discourse-cdn.com/v4/letter/s/6f9a4e/32.png) [@speeltronics](https://hub.mender.io/u/speeltronics)\
**Post date:** [May 9, 2019, 12:58pm UTC](https://hub.mender.io/t/single-file/486/6 "2019-05-09T12:58:10Z")

</div>

Oh I see now! Thanks! It would be really great if the modules could be sent with the updates, so that a rootfs update wouldn’t be needed to use the modules on already deployed devices… Anyways, thanks again!

---

<div class="post-metadata">

**Author:** ![kacf](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/kacf/32/146_2.png) [@kacf](https://hub.mender.io/u/kacf)\
**Post date:** [May 9, 2019, 1:19pm UTC](https://hub.mender.io/t/single-file/486/7 "2019-05-09T13:19:15Z")

</div>

Unfortunately this can’t be done because it is a chicken and egg problem. The module is needed before the artifact is fully downloaded, but if the module is inside the artifact, then it needs to be downloaded first…

Once the `single-file` module is installed though, you can use it to install other modules. (\*)

(\*) Well, almost, except that there is a bug in it right now which doesn’t preserve permissions, like execute permission. I’m in the process of fixing this right now, so this issue should be gone soon.

---

<div class="post-metadata">

**Author:** ![speeltronics](https://avatars.discourse-cdn.com/v4/letter/s/6f9a4e/32.png) [@speeltronics](https://hub.mender.io/u/speeltronics)\
**Post date:** [May 9, 2019, 4:42pm UTC](https://hub.mender.io/t/single-file/486/8 "2019-05-09T16:42:31Z")

</div>

Understood! So, how do we know what version the modules are at or when it was last updated?

---

<div class="post-metadata">

**Author:** ![kacf](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/kacf/32/146_2.png) [@kacf](https://hub.mender.io/u/kacf)\
**Post date:** [May 13, 2019, 12:46pm UTC](https://hub.mender.io/t/single-file/486/9 "2019-05-13T12:46:38Z")

</div>

> there is a bug in it right now which doesn’t preserve permissions, like execute permission. I’m in the process of fixing this right now, so this issue should be gone soon.

FYI: [Update modules fixes by kacf · Pull Request #396 · mendersoftware/mender · GitHub](https://github.com/mendersoftware/mender/pull/396)

> Understood! So, how do we know what version the modules are at or when it was last updated?

There is no versioning embedded in the update modules. They are just binaries or scripts, like other binaries on the system.

You can use an inventory script to list the contents of `/usr/share/mender/modules/v3`, perhaps with a `md5sum` to figure out the version. This will show up in the UI. See [inventory scripts](https://docs.mender.io/2.0/client-configuration/inventory) for more information.

---

<div class="post-metadata">

**Author:** ![ster](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/ster/32/282_2.png) [@ster](https://hub.mender.io/u/ster)\
**Post date:** [July 19, 2019, 3:43pm UTC](https://hub.mender.io/t/single-file/486/10 "2019-07-19T15:43:30Z")

</div>

Is it possible to include state scripts in the artifacts for update modules?  
Is it possible to use LZMA compression for update modules?

---

<div class="post-metadata">

**Author:** ![kacf](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/kacf/32/146_2.png) [@kacf](https://hub.mender.io/u/kacf)\
**Post date:** [July 23, 2019, 6:51am UTC](https://hub.mender.io/t/single-file/486/11 "2019-07-23T06:51:46Z")

</div>

Yes and yes!

---

<div class="post-metadata">

**Author:** ![ster](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/ster/32/282_2.png) [@ster](https://hub.mender.io/u/ster)\
**Post date:** [July 23, 2019, 11:00am UTC](https://hub.mender.io/t/single-file/486/12 "2019-07-23T11:00:13Z")

</div>

And here how it is possible 🙂 :

1. To add state scripts or sign the artifact, you can provide `--key` and `--script` as passthrough arguments, for example:

2. But `--compression lzma` can’t be passed like this as this argument should be passed to `mender-artifact` and not to `mender-artifact write module-image`. So to use lzma, you have to change the artifact generator script so it calls mender-artifact with this argument:

`mender-artifact --compression lzma write module-image \ ...`

I’ll try to prepare a PR to improve this.

---

<div class="post-metadata">

**Author:** ![dYalib](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/dyalib/32/1241_2.png) [@dYalib](https://hub.mender.io/u/dYalib)\
**Post date:** [October 7, 2019, 4:01pm UTC](https://hub.mender.io/t/single-file/486/13 "2019-10-07T16:01:55Z")

</div>

Hi,

thank you for this update module!  
It’s possible to perform a device reboot after the new file has been installed?  
I like to update a configuration file and a reboot is required to take effect. What is the preferred way to do this?

---

<div class="post-metadata">

**Author:** ![mEK](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/mek/32/377_2.png) [@mEK](https://hub.mender.io/u/mEK)\
**Post date:** [October 8, 2019, 6:26am UTC](https://hub.mender.io/t/single-file/486/14 "2019-10-08T06:26:10Z")

</div>

Hello @dYalib  
I’m not quite sure, but there is no reboot activity in the script update module. You can try full system update for this. For more detailed information about the update modules, see here:  
[https://docs.mender.io/2.1/devices/update-modules](https://docs.mender.io/2.1/devices/update-modules)

---

<div class="post-metadata">

**Author:** ![mirzak](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/mirzak/32/2056_2.png) [@mirzak](https://hub.mender.io/u/mirzak)\
**Post date:** [October 8, 2019, 7:42am UTC](https://hub.mender.io/t/single-file/486/15 "2019-10-08T07:42:02Z")

</div>

You will need to modify the module to support reboot.

And the change required would be, changing:

```auto
    NeedsArtifactReboot)
        echo "No"
    ;;

```

to

```auto
    NeedsArtifactReboot)
        echo "Automatic"
    ;;

```

You can reed more about the Update Module API’s here,

> <https://github.com/mendersoftware/mender/blob/2.1.0/Documentation/update-modules-v3-file-api.md>

---

<div class="post-metadata">

**Author:** ![freibrun](https://avatars.discourse-cdn.com/v4/letter/f/5e9695/32.png) [@freibrun](https://hub.mender.io/u/freibrun)\
**Post date:** [December 16, 2019, 12:57pm UTC](https://hub.mender.io/t/single-file/486/16 "2019-12-16T12:57:06Z")

</div>

I tried to include a state script in an artifact with the name **ArtifactInstall\_Leave\_00** with this command:

> ./single-file-artifact-gen -n ${ARTIFACT\_NAME} -t ${DEVICE\_TYPE} -d ${DEST\_DIR} -o ${OUTPUT\_PATH} ${FILE} – --script ${SCRIPT}

However, the file seems not to be included in the artifact. This is the error I get on the target:

> ‘ArtifactInstall\_Leave\_00’: -1 : fork/exec /var/lib/mender/scripts/ArtifactInstall\_Leave\_00: no such file or directory

According to the manual Artifact state scripts should be included in the generated artifact: [State scripts | Mender documentation](https://docs.mender.io/2.2/artifacts/state-scripts#root-file-system-and-artifact-scripts)

But when I check the content of the artifact file, the state script is not included. I also tried to include the state script with the -f parameter which does indeed include the state script as payload but it’s still not working (since it probably does not put the state script to the above specified path).

What else do I need to specify to successfully include a state script file in an artifact?

**Update** : I now see that the script is actually correctly installed on the device in the following directory:  
 ![image](https://canada1.discourse-cdn.com/flex036/uploads/mender/original/1X/c6f6b07162d47f0047ddb2c3deb162e14a5d1f04.png)

However, the script is somehow not executed as we can see in the error log:

> 2019-12-16 12:41:34 +0000 UTC error: transient error: error executing leave script for update-install state: error running leave state script(s) for ArtifactInstall state: statescript: error executing ‘ArtifactInstall\_Leave\_00’: -1 : fork/exec /var/lib/mender/scripts/ArtifactInstall\_Leave\_00: no such file or directory

Any idea why the script is not executed?

**Solved** : Found the problem. The script was actually correctly executed - but there was a problem INSIDE the script. So the error message was a bit misleading 😃

---

<div class="post-metadata">

**Author:** ![lluiscampos](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/lluiscampos/32/112_2.png) [@lluiscampos](https://hub.mender.io/u/lluiscampos)\
**Post date:** [December 16, 2019, 3:02pm UTC](https://hub.mender.io/t/single-file/486/17 "2019-12-16T15:02:24Z")

</div>

Hehe. Good that you figured out yourself 😉

It is quite limited the debug info that Mender client can take from the state script itslef. A good tip (that I always use at least while developing) is adding verbosity to the script itself with `set -x`. This way if the update fails inside the script, Mender will capture the output and send to the Mender server.

---

<div class="post-metadata">

**Author:** ![gerardostola](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/gerardostola/32/540_2.png) [@gerardostola](https://hub.mender.io/u/gerardostola)\
**Post date:** [March 23, 2020, 11:18pm UTC](https://hub.mender.io/t/single-file/486/18 "2020-03-23T23:18:42Z")

</div>

Hi,  
I’ve created and deployed the artifact as documented.  
I’ve compiled and run the client from an Ubuntu box.  
I’ve deployed the artifact on the server, which moved from Active to Finished.  
The client was run with the -debug modifier. There I could read  
DEBU[0001] Received response:204 No Content  
DEBU[0001] No update available  
DEBU[0001] no updates available

For there is something missconfigured, I couldn´t figure out.

---

<div class="post-metadata">

**Author:** ![kacf](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/kacf/32/146_2.png) [@kacf](https://hub.mender.io/u/kacf)\
**Post date:** [March 24, 2020, 7:27am UTC](https://hub.mender.io/t/single-file/486/19 "2020-03-24T07:27:15Z")

</div>

Are you sure you are not trying to install an Artifact with the same name as the already installed Artifact on the device? Each new Artifact being deployed needs to have a different name.

---

<div class="post-metadata">

**Author:** ![gerardostola](https://yyz2.discourse-cdn.com/flex036/user_avatar/hub.mender.io/gerardostola/32/540_2.png) [@gerardostola](https://hub.mender.io/u/gerardostola)\
**Post date:** [March 25, 2020, 1:02am UTC](https://hub.mender.io/t/single-file/486/20 "2020-03-25T01:02:32Z")

</div>

Hi, thank you for your answer. What I had missed was to define the device type on the client, so there was no match.

Now we could download a single file successfully, using the demo server. By the way, it can only send the domain [s3.docker.mender.io](http://s3.docker.mender.io), we could not change it and that could be nice, given that clients and servers live on different networks. The only workaround we found was to resolve that domain through the client´s /etc/hosts file, which is somewhat dirty.

[Next page](https://hub.mender.io/t/single-file/486.md?page=2)
