# % Options Settings: https://orgmode.org/manual/Export-Settings.html
#+OPTIONS: timestamp:nil ^:nil <:nil p:t prop:t tags:t tasks:t todo:t
#+LATEX_CLASS: article
#+LaTeX_CLASS_OPTIONS: [a4paper,12pt]
#+LATEX_HEADER: \usepackage{booktabs}
# % to include pdf/eps/png files
#+LATEX_HEADER: \usepackage{indentfirst}
#+LATEX_HEADER: \usepackage{graphicx}
# % useful to add 'todo' markers
#+LaTeX_HEADER: \usepackage{todonotes}
#+LaTeX_HEADER: \setlength{\marginparwidth}{2cm} % fix todonotes warning
# % hyperrefs
#+LaTeX_HEADER: \usepackage{hyperref}
# % ----------------- Code blocks ----------------
# % Dependencies: pip install pygments
# % nice source code formatting
#+LaTeX_HEADER: \usepackage{xcolor}
#+LaTeX_HEADER: \definecolor{bg}{rgb}{0.98,0.98,0.98}
#+LaTeX_HEADER: \usepackage[cache=false]{minted}
#+LaTeX_HEADER: \setminted{
#+LaTeX_HEADER:   fontsize=\small,
#+LaTeX_HEADER:   baselinestretch=1,
#+LaTeX_HEADER:   xleftmargin=4em,
#+LaTeX_HEADER:   breaklines,
#+LaTeX_HEADER:   mathescape,
#+LaTeX_HEADER:   linenos,
#+LaTeX_HEADER:   numbersep=5pt,
#+LaTeX_HEADER:   frame=leftline,
#+LaTeX_HEADER:   framesep=2mm,
#+LaTeX_HEADER:   autogobble,
#+LaTeX_HEADER:   style=tango,
#+LaTeX_HEADER:   bgcolor=bg
#+LaTeX_HEADER: }
# % change style of section headings
#+LaTeX_HEADER: \usepackage{sectsty}
#+LaTeX_HEADER: \allsectionsfont{\sffamily}
# % only required for orgmode ticked TODO items, can remove
#+LaTeX_HEADER: \usepackage{amssymb}
# % only required for underlining text
#+LaTeX_HEADER: \usepackage[normalem]{ulem}
# % often use this in differential operators:
#+LaTeX_HEADER: \renewcommand{\d}{\ensuremath{\mathrm{d}}}
# % allow more reasonable text width for most documents than LaTeX default
#+LaTeX_HEADER: \setlength{\textheight}{21cm}
#+LaTeX_HEADER: \setlength{\textwidth}{16cm}
# % reduce left and right margins accordingly
#+LaTeX_HEADER: \setlength{\evensidemargin}{-0cm}
#+LaTeX_HEADER: \setlength{\oddsidemargin}{-0cm}
# % reduce top margin
#+LaTeX_HEADER: \setlength{\topmargin}{0cm}
# % references formats
#+LaTeX_HEADER: \usepackage[round]{natbib}
# % Chinese supported
#+LATEX_HEADER: \usepackage{ctex}
# % Increase default line spacing a little
#+LATEX_HEADER: \usepackage{setspace}
#+LATEX_HEADER: \renewcommand{\baselinestretch}{1.5}
#+LATEX_HEADER: \setlength{\parskip}{0.8em}
# % Line & paragraph space end
# % item list margin
#+LATEX_HEADER: \usepackage{enumitem}
# % Breaking Page Between Title and Toc
#+LATEX_HEADER: \makeatletter \def\@maketitle{\null \begin{center} {\vskip 5em \Huge \@title} \vskip 30em {\LARGE \@author} \vskip 3em {\LARGE \@date} \end{center} \newpage} \makeatother
# % End of Breaking Page Between Title and Toc
#+LATEX_HEADER: \renewcommand\contentsname{目录}
# Generate Tex File: C-c C-e l l; then replace verbatim with minted, and must special the code language
#+LATEX_HEADER: % Generate PDF: xelatex -shell-escape <tex file>
#+AUTHOR: jouyouyun
#+EMAIL: yanbowen717@gmail.com

#+latex: \newpage
* deepin 原子更新管理程序
** 前言
deepin 是一个开放的操作系统，用户可通过多种方式更新系统。若某一次的更新与系统不兼容或是更新过程被意外中断，可能会导致重启后系统无法正常运行，影响用户使用。

deepin 为了处理此类更新引发的问题，从 v20 开始，设计实现了 AB 双系统分区的方案。即在系统安装时创建两个等大的系统分区，标记为 A 和 B 。
如当前系统是在 A ，系统更新时先将 A 中内容增量同步到 B ，同步完成后，生成对于 B 的引导，然后开始更新 A 。更新完成后重启，若更新存在问题，用户可回退到 B 中的系统。

在实际的使用中，AB 双系统分区的方案面临空间占用多、不支持命令行的问题。

因此需要重新设计一套更新管理程序，实现以下目标：
+ 系统状态变更(软件安装、更新、卸载)前备份当前状态，并支持命令行
+ 能够回滚到前一个系统状态
+ 合并双系统分区为一个系统分区
+ 备份的系统存储在数据分区

** 用法
*** 编译依赖
+ golang

*** 运行依赖
+ ostree
+ mount

*** 构建
~make~

*** 安装
~make install~

*** 使用
使用之前需先编写好配置文件，若无特殊要求，配置文件需安装到 =/persistent/osroot/config.json= 。

+ 初始化
  - ~sudo deepin-upgrade-manager --action=init~
  - ~sudo deepin-upgrade-manager --action=list~

    获取初始化版本号，假定为 =v23.0.0.20220218=
  - ~sudo deepin-upgrade-manager --action=rollback --version=v23.0.0.20220218~
+ 提交新版本
  - ~sudo update-grub~
  - ~sudo deepin-upgrade-manager --action=commit~
+ 回滚到指定版本

  需先询问用户是否保存当前系统状态，若需要保存则按照 *提交新版本* 的步骤进行操作。
  假定要回滚到 =v23.0.0.20220218= ，使用命令：

  ~sudo deepin-upgrade-manager --action=rollback --version=v23.0.0.20220218~

** 设计
*** 约束
**** 编程语言
+ 解释性语言优先选择 shell
+ 编译性语言优先选择 golang ， C 次之，后期考虑更换为 rust

  当前优先实现功能，所以 golang 优先
+ 依赖最小化

  因为需要在 initrd 阶段运行，尽可能的不要引入外部依赖

*** 方案
本方案采用 ostree 构建系统文件的本地 repo ，根据配置文件中的订阅目录，将数据提交到此 repo 中。
+而系统文件则由每个版本的快照通过 hardlink 生成，以节省空间使用。+

每次系统变更前，都对当前系统状态进行提交，生成新版本。版本回滚时，则使用对应版本的快照重新生成系统文件目录。

详细介绍请见概要设计文档。

*** TODO
**** 更新管理程序
+ [ ] 实现更新程序的单例检测

  在执行 =init、commit、rollback、snapshot= 命令时，需检测当前是否有更新程序正在执行这些操作，若存在则直接退出。
+ [ ] 回滚前需检查 fstab 中的分区是否都已经挂载

  系统文件并不都是在系统分区中，有一部分在数据分区，因此需要检查相关的分区是否都已经挂载。
  特别是在 initrd 中，因为在 initrd 中只会挂载系统分区，所以需要检查并挂载需要的分区。
+ [ ] apt/dpkg 执行前的 hook 添加

  系统在启动后，在执行 apt/dpkg 安装、更新、卸载软件前，需要使用更新程序提交当前系统状态，需要注意的是在一次系统运行周期内(未重启)，更新程序只应执行一次版本提交。
+ [ ] 更新结果自检程序

  系统状态变更完成重启后，需要对启动阶段每个关键阶段进行检测，记录状态是否正常。若不正常则在用户登录后，提示用户是否回滚。若无法正常进入系统，则标记未失败，重启后自动回滚到上一版本。
+ [ ] 版本数据清理功能

  默认本地 repo 中只保留 3 个版本，多余的版本需要清理，清理时版本对应的数据也应清理，过程如下：
  - 查询版本对应的提交： ~ostree --repo=/persistent/osroot/os/repo log <version>~
  - 删除版本： ~ostree --repo=/persistent/osroot/os/repo refs --delete <version>~
  - 删除数据： ~ostree --repo=/persistent/osroot/os/repo prune --delete-commit=<commit>~

  但需保留初始安装版本。
+ [ ] DBus 接口

  添加必要的 DBus 接口，供控制中心等调用者使用。
+ [ ] 确定订阅目录列表
+ [ ] 更新/回滚前检查空间是否充足
+ [ ] 优化提交/回滚效率
  - 可在操作之前计算差异，针对差异数据进行操作
+ [ ] 支持从 =/persistent/osroot/snapshot/<version>= 启动系统
+ [ ] 配置文件自动生成功能
  - 根据不同的分区挂载方式，生成相应的配置文件
+ [ ] =/vendor= 合并支持

**** initramfs
+ [ ] 实现版本回滚功能

  添加版本获取并回滚。

**** 安装器
+ [ ] 按照分区要求分区，并创建目录结构
+ [ ] 初始化本地 repo ，并提交初始数据

**** 控制中心
+ [ ] 添加版本回滚管理界面

**** V20 兼容
+ [ ] AB 分区处理

*** 远期目标
**** 更新管理程序
+ [ ] OTA 更新支持

**** 文件恢复
从 snapshot 恢复，若 snapshot 也被损坏，则从 repo 中恢复，repo 也被损坏则放弃。

+ [ ] 文件篡改修复
+ [ ] 文件丢失修复

**** initramfs 模块化
+ [ ] 确定基础 img
+ [ ] 确定模块格式及生成工具
+ [ ] 确定模块加载方式
