[LEDE-DEV] [PATCH] Mountd: Add sysupgrade functionality.

Zaolin zaolin at das-labor.org
Thu Jul 7 04:40:13 PDT 2016


Hey,

thanks for all your answers!

On 07/07/2016 07:52 AM, Olivier Hardouin wrote:
> Though I like the idea of being able to upgrade using a usb stick, I
> wonder if mountd is the correct place to implement this.
> Indeed mountd is sending events via hotplug, so some other subsystems
> could listen to these ones and decide whether the upgrade should be
> based on some file of an attached usb disk or some other place (in the
> network).
> I think mountd should only do what it is good at, meaning detecting
> disk, finding partition, mounting filesystem and inform other
> subsystems.
Yes, good point. But then we should rewrite/redesign the whole update
process
including the sysupgrade binary in my opinion. For example writing a
small library and a daemon
which does the updates for us. A daemon which executes a sysupgrade tool
doesn't
make more sense for me as the mountd solution.
>
> On Wed, Jul 6, 2016 at 12:34 PM, Wang Linetkux <chinawrj at gmail.com> wrote:
>> Another possible solution is to record the HASH of system image after
>> system upgrade is done. Next time when we try to do the system
>> upgrade, we can compare the recorded HASH value and the compute value
>> from system upgrade file?
Also a good idea but normally this should be done by the sysupgrade util
itself.
Building upgrade logic into the mountd is not the way we should go. See
above.
>>
>> 2016-07-06 18:18 GMT+08:00 Bruno Randolf <br1 at einfach.org>:
>>> On 06/07/16 06:58, John Crispin wrote:
>>>> Hi Philipp
>>>>
>>>> the thing that i am worried about is this process
>>>>
>>>> 1) plug a stick
>>>> 2) mountd detects the upgrade file
>>>> 3) mountd triggers sysupgrade
>>>> 4) system reboots
>>>> 5) goto 1)
>>>>
>>>> there is no way to know at what point between 3 and 4 we need to unplug
>>>> the usb stick
Yep, I totally agree. A better solution based on this patch would be
copying the update to tmp
and execute it after the storage device is removed.
>>> One possible solution is to write a file, something like
>>> ".sysupgrade-applied" or remove the upgrade file before actually doing
>>> the upgrade, or during first boot.
>>>
>>> bruno
I think this solution is lacking the feature "batch update" on for
example 20 devices in row.
>>>>       John
>>>>
>>>> On 04/07/2016 18:56, Philipp Deppenwiese wrote:
>>>>> Extend the mountd with the ability to apply sysupgrades from mounted devices.
>>>>> Upgrade files are identified by filename and executed through the
>>>>> commandline sysupgrade utility of LEDE.
>>>>>
>>>>> Option List:
>>>>>
>>>>> config mountd 'sysupgrade'
>>>>>      option  check_filename  firmware.bin (required)
>>>>>      option  save_config     1       (optional, default disabled)
>>>>>      option  delay           10      (optional, default disabled)
>>>>>      option  preserve_part   1       (optional, default disabled)
>>>>>      option  enabled         1
>>>>>
>>>>> The so called "filesearch" is done only in the root of a mounted
>>>>> devices.
>>>>>
>>>>> Signed-off-by: Philipp Deppenwiese <zaolin at das-labor.org>
>>>>> ---
>>>>>  CMakeLists.txt    |   2 +-
>>>>>  autofs.c          |  19 ++++++-
>>>>>  include/upgrade.h |   6 ++
>>>>>  mount.c           |   2 +
>>>>>  upgrade.c         | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  5 files changed, 189 insertions(+), 2 deletions(-)
>>>>>  create mode 100644 include/upgrade.h
>>>>>  create mode 100644 upgrade.c
>>>>>
>>>>> diff --git a/CMakeLists.txt b/CMakeLists.txt
>>>>> index 2e712cd..ed3602e 100644
>>>>> --- a/CMakeLists.txt
>>>>> +++ b/CMakeLists.txt
>>>>> @@ -5,7 +5,7 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations)
>>>>>
>>>>>  SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
>>>>>
>>>>> -ADD_EXECUTABLE(mountd main.c log.c sys.c autofs.c mount.c timer.c signal.c ucix.c led.c fs.c ucix.c)
>>>>> +ADD_EXECUTABLE(mountd main.c log.c sys.c autofs.c mount.c timer.c signal.c ucix.c led.c fs.c ucix.c upgrade.c)
>>>>>  TARGET_LINK_LIBRARIES(mountd uci ubox)
>>>>>
>>>>>  INSTALL(TARGETS mountd
>>>>> diff --git a/autofs.c b/autofs.c
>>>>> index 4ad782d..79a3e97 100644
>>>>> --- a/autofs.c
>>>>> +++ b/autofs.c
>>>>> @@ -37,6 +37,13 @@ dev_t dev;
>>>>>  time_t uci_timeout;
>>>>>  char uci_path[32];
>>>>>
>>>>> +// Sysupgrade uci options
>>>>> +char uci_upgrade_filename[255];
>>>>> +int uci_upgrade_backup;
>>>>> +int uci_upgrade_delay;
>>>>> +int uci_upgrade_enabled;
>>>>> +int uci_upgrade_preserve_partition;
>>>>> +
>>>>>  static void umount_autofs(void)
>>>>>  {
>>>>>      system_printf("umount %s 2> /dev/null", "/tmp/run/mountd/");
>>>>> @@ -186,18 +193,28 @@ static void autofs_cleanup_handler(void)
>>>>>  static void autofs_init(void)
>>>>>  {
>>>>>      int kproto_version;
>>>>> -    char *p;
>>>>> +    char *p, *filename = NULL;
>>>>>      struct uci_context *ctx;
>>>>>      signal_init(autofs_cleanup_handler);
>>>>>      ctx = ucix_init("mountd");
>>>>>      uci_timeout = ucix_get_option_int(ctx, "mountd", "mountd", "timeout", 60);
>>>>>      p = ucix_get_option(ctx, "mountd", "mountd", "path");
>>>>> +    filename = ucix_get_option(ctx, "mountd", "sysupgrade", "check_filename");
>>>>> +    uci_upgrade_backup = ucix_get_option_int(ctx, "mountd", "sysupgrade", "save_config", 0);
>>>>> +    uci_upgrade_delay = ucix_get_option_int(ctx, "mountd", "sysupgrade", "delay", 0);
>>>>> +    uci_upgrade_enabled = ucix_get_option_int(ctx, "mountd", "sysupgrade", "enabled", 0);
>>>>> +    uci_upgrade_preserve_partition = ucix_get_option_int(ctx, "mountd", "sysupgrade", "preserve_part", 0);
>>>>>      ucix_cleanup(ctx);
>>>>>      if(p)
>>>>>              snprintf(uci_path, 31, "%s", p);
>>>>>      else
>>>>>              snprintf(uci_path, 31, "/tmp/mounts/");
>>>>>      uci_path[31] = '\0';
>>>>> +
>>>>> +    if(filename) {
>>>>> +            snprintf(uci_upgrade_filename, 255, "%s", filename);
>>>>> +    }
>>>>> +
>>>>>      mkdir("/tmp/run/", 0555);
>>>>>      mkdir("/tmp/mounts", 0555);
>>>>>      system_printf("rm -rf %s*", uci_path);
>>>>> diff --git a/include/upgrade.h b/include/upgrade.h
>>>>> new file mode 100644
>>>>> index 0000000..6b5ace9
>>>>> --- /dev/null
>>>>> +++ b/include/upgrade.h
>>>>> @@ -0,0 +1,6 @@
>>>>> +#ifndef _UPGRADE_H__
>>>>> +#define _UPGRADE_H__
>>>>> +
>>>>> +int sysupgrade_scan(const char *mount_path);
>>>>> +
>>>>> +#endif
>>>>> diff --git a/mount.c b/mount.c
>>>>> index 7cbb8ff..0bec25e 100644
>>>>> --- a/mount.c
>>>>> +++ b/mount.c
>>>>> @@ -28,6 +28,7 @@
>>>>>  #include "include/ucix.h"
>>>>>  #include "include/fs.h"
>>>>>  #include "include/mount.h"
>>>>> +#include "include/upgrade.h"
>>>>>
>>>>>  int mount_new(char *path, char *dev);
>>>>>
>>>>> @@ -300,6 +301,7 @@ int mount_new(char *path, char *dev)
>>>>>      {
>>>>>              mount->mounted = 1;
>>>>>              mount_dump_uci_state();
>>>>> +            sysupgrade_scan(tmp);
>>>>>      } else return -1;
>>>>>      return 0;
>>>>>  }
>>>>> diff --git a/upgrade.c b/upgrade.c
>>>>> new file mode 100644
>>>>> index 0000000..6992e65
>>>>> --- /dev/null
>>>>> +++ b/upgrade.c
>>>>> @@ -0,0 +1,162 @@
>>>>> +/*
>>>>> + *   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.
>>>>> + *
>>>>> + *   Provided by 9elements GmbH
>>>>> + *   Copyright (C) 2016 Philipp Deppenwiese <philipp.deppenwiese at 9elements.com>
>>>>> + */
>>>>> +
>>>>> +#include <errno.h>
>>>>> +#include <linux/limits.h>
>>>>> +#include <stdio.h>
>>>>> +#include <stdlib.h>
>>>>> +#include <stdarg.h>
>>>>> +#include <string.h>
>>>>> +#include <sys/stat.h>
>>>>> +#include <sys/types.h>
>>>>> +#include <sys/wait.h>
>>>>> +#include <unistd.h>
>>>>> +
>>>>> +#include "include/upgrade.h"
>>>>> +#include "include/log.h"
>>>>> +
>>>>> +#define SYSUPGRADE_CMD "/sbin/sysupgrade"
>>>>> +
>>>>> +extern char uci_upgrade_filename[255];
>>>>> +extern int uci_upgrade_backup;
>>>>> +extern int uci_upgrade_delay;
>>>>> +extern int uci_upgrade_enabled;
>>>>> +extern int uci_upgrade_preserve_partition;
>>>>> +
>>>>> +static unsigned option_index = 0;
>>>>> +static char **parameters = NULL;
>>>>> +
>>>>> +static int execute_sysupgrade()
>>>>> +{
>>>>> +    pid_t pid;
>>>>> +    int status;
>>>>> +    char * const envp[] = { NULL };
>>>>> +
>>>>> +    if (!parameters) {
>>>>> +            return 1;
>>>>> +    }
>>>>> +
>>>>> +    if ((pid = fork()) < 0) {
>>>>> +            perror("Can't fork child process for command invocation!");
>>>>> +            return 1;
>>>>> +    } else if (pid == 0) {
>>>>> +            if (execve(SYSUPGRADE_CMD, parameters, envp) < 0) {
>>>>> +                    log_printf("Error was reported on sysupgrade: %s\n", strerror(errno));
>>>>> +                    return 1;
>>>>> +            }
>>>>> +    } else {
>>>>> +            waitpid(pid, &status, 0);
>>>>> +    }
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static int find_upgrade_filepath(const char *mount_path, char *update_file)
>>>>> +{
>>>>> +    struct stat file;
>>>>> +
>>>>> +    if (snprintf(update_file, PATH_MAX, "%s/%s", mount_path,
>>>>> +                 uci_upgrade_filename) < 0) {
>>>>> +            perror(NULL);
>>>>> +            return 1;
>>>>> +    }
>>>>> +
>>>>> +    if (stat(update_file, &file) < 0) {
>>>>> +            log_printf("No upgrade file found for device path: %s! \n", mount_path);
>>>>> +            return 1;
>>>>> +    }
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static void add_sysupgrade_option(const char *parameter, ...)
>>>>> +{
>>>>> +    va_list arguments;
>>>>> +    char *option = NULL;
>>>>> +
>>>>> +    parameters = realloc(parameters, ++option_index * sizeof(char*));
>>>>> +
>>>>> +    if (parameter) {
>>>>> +            option = (char*)calloc(PATH_MAX, sizeof(char));
>>>>> +
>>>>> +            va_start(arguments, parameter);
>>>>> +            vsnprintf(option, PATH_MAX, parameter, arguments);
>>>>> +            va_end(arguments);
>>>>> +    }
>>>>> +
>>>>> +    parameters[option_index - 1] = option;
>>>>> +}
>>>>> +
>>>>> +static void free_all()
>>>>> +{
>>>>> +    unsigned i;
>>>>> +
>>>>> +    if (!parameters) {
>>>>> +            return;
>>>>> +    }
>>>>> +
>>>>> +    for (i = 0; i < option_index; i++) {
>>>>> +            if (parameters[i]) {
>>>>> +                    free(parameters[i]);
>>>>> +            }
>>>>> +    }
>>>>> +
>>>>> +    free(parameters);
>>>>> +    parameters = NULL;
>>>>> +    option_index = 0;
>>>>> +}
>>>>> +
>>>>> +int sysupgrade_scan(const char *mount_path)
>>>>> +{
>>>>> +    char update_file[PATH_MAX];
>>>>> +
>>>>> +    if (!uci_upgrade_enabled) {
>>>>> +            log_printf("Sysupgrade via usb device is disabled..\n");
>>>>> +            return 0;
>>>>> +    }
>>>>> +
>>>>> +    if (find_upgrade_filepath(mount_path, update_file)) {
>>>>> +            log_printf("No upgrade file could be found..\n");
>>>>> +            return 0;
>>>>> +    }
>>>>> +
>>>>> +    log_printf("Starting sysupgrade routine..\n");
>>>>> +
>>>>> +    add_sysupgrade_option("%s", SYSUPGRADE_CMD);
>>>>> +
>>>>> +    if (uci_upgrade_delay) {
>>>>> +            add_sysupgrade_option("-d %i", uci_upgrade_delay);
>>>>> +    }
>>>>> +
>>>>> +    if (uci_upgrade_backup) {
>>>>> +            add_sysupgrade_option("-c");
>>>>> +    } else {
>>>>> +            add_sysupgrade_option("-n");
>>>>> +    }
>>>>> +
>>>>> +    if (uci_upgrade_preserve_partition) {
>>>>> +            add_sysupgrade_option("-p");
>>>>> +    }
>>>>> +
>>>>> +    add_sysupgrade_option("%s", update_file);
>>>>> +    add_sysupgrade_option(NULL);
>>>>> +
>>>>> +    if (execute_sysupgrade()) {
>>>>> +            free_all();
>>>>> +            log_printf("Try to start sysupgrade but it failed! \n");
>>>>> +            return 1;
>>>>> +    }
>>>>> +
>>>>> +    free_all();
>>>>> +    return 0;
>>>>> +}
>>>>>
>>>> _______________________________________________
>>>> Lede-dev mailing list
>>>> Lede-dev at lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>>>
>>>
>>> _______________________________________________
>>> Lede-dev mailing list
>>> Lede-dev at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>> _______________________________________________
>> Lede-dev mailing list
>> Lede-dev at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/lede-dev
> _______________________________________________
> Lede-dev mailing list
> Lede-dev at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/lede-dev/attachments/20160707/eb2fdbe6/attachment-0001.sig>


More information about the Lede-dev mailing list