Subject: [bug#69090] [PATCH] gnu: services: Add resize-fs-service.

From: Gabriel Wicki <[email-masked]>
Date: Tue, 13 Feb 2024 00:21:02 +0100

Aloha and hello

As promised a while back here is my patch adding a resize filesystem
service that would typically be used either when flashing images onto an
SD card or using an uploadable image on a VPS.

Thanks for review and merge in advance,

gabber

>From 9b44e851252445bc628d70eb9e26574455620caf Mon Sep 17 00:00:00 2001
Message-ID: <[email-masked]>
From: Gabriel Wicki <[email-masked]>
Date: Tue, 13 Feb 2024 00:07:24 +0100
Subject: [PATCH] gnu: services: Add resize-fs-service.

* gnu/services/admin.scm (resize-fs-configuration): New configuration
type.
(resize-fs-script, resize-fs-shepherd-service): New procedures.
resize-fs-service-type): New variable.
* doc/guix.texi (Miscallaneous Services): Document it.

Change-Id: Ib80c1af99ff62b68a79d7c463a5173f530514227
---
 doc/guix.texi          | 41 +++++++++++++++++++
 gnu/services/admin.scm | 89 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 04119a5955..093a35a331 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -40746,6 +40746,47 @@ Miscellaneous Services
 
 @c End of auto-generated fail2ban documentation.
 
+@cindex resize-fs
+@subsubheading Resize Filesystem service
+
+This service type lets you resize a live file-system during boot, which
+can be convenient if you flashed Guix on an SD Card (e.g. for an
+embedded device) or uploaded the image to a VPS.  In both cases the
+medium the image will reside upon may be larger than the image you want
+to produce.
+For an embedded device booting from an SD card you may use something like:
+@lisp
+(service resize-fs-service-type
+  (resize-fs-configuration
+    (device "/dev/mmcblk0")
+    (partition 2)))
+@end lisp
+
+Be extra cautious to use the correct device, partiion and end value, for
+the service will circumvent parted's safety checks - wrong use could end
+in loss of data or the corruption of your operating system.
+
+@table @asis
+
+@item @code{parted} (default: @code{parted}) (type: file-like)
+The parted package to use.
+
+@item @code{e2fsprogs} (default: @code{e2fsprogs}) (type: file-like)
+The e2fsprogs package to use.
+
+@item @code{device} (default: @code{"/dev/sdZ"}) (type: string)
+The device containing the file-system that shall be resized.
+
+@item @code{partition} (default: @code{-1}) (type: number)
+The partition number of the file-system that shall be resized.
+
+@item @code{end} (default: @code{"100%"}) (type: string)
+The end position of the resized partition as understood by the parted
+utility (e.g. "100%", "500M" or "16GiB").
+
+@end table
+
+
 @node Setuid Programs
 @section Setuid Programs
 
diff --git a/gnu/services/admin.scm b/gnu/services/admin.scm
index 0b325fddb1..acd7cacd3e 100644
--- a/gnu/services/admin.scm
+++ b/gnu/services/admin.scm
@@ -23,8 +23,11 @@ (define-module (gnu services admin)
   #:use-module (gnu packages admin)
   #:use-module ((gnu packages base)
                 #:select (canonical-package findutils coreutils sed))
+  #:use-module (gnu packages bash)
   #:use-module (gnu packages certs)
+  #:use-module (gnu packages disk)
   #:use-module (gnu packages package-management)
+  #:use-module (gnu packages linux)
   #:use-module (gnu services)
   #:use-module (gnu services configuration)
   #:use-module (gnu services mcron)
@@ -93,7 +96,16 @@ (define-module (gnu services admin)
             unattended-upgrade-configuration-services-to-restart
             unattended-upgrade-configuration-system-expiration
             unattended-upgrade-configuration-maximum-duration
-            unattended-upgrade-configuration-log-file))
+            unattended-upgrade-configuration-log-file
+
+            resize-fs-configuration
+            resize-fs-configuration?
+            resize-fs-configuration-parted
+            resize-fs-configuration-e2fsprogs
+            resize-fs-configuration-device
+            resize-fs-configuration-partition
+            resize-fs-configuration-end
+            resize-fs-service-type))
 
 ;;; Commentary:
 ;;;
@@ -537,4 +549,79 @@ (define unattended-upgrade-service-type
     "Periodically upgrade the system from the current configuration.")
    (default-value (unattended-upgrade-configuration))))
 
+
+;;;
+;;; Resize filesystem.
+;;;
+
+(define-configuration/no-serialization resize-fs-configuration
+  (parted
+   (file-like parted)
+   "The parted package to use.")
+  (e2fsprogs
+   (file-like e2fsprogs)
+   "The e2fsprogs package providing the resize2fs utility.")
+  (device
+   (string "/dev/sdZ")
+   "The device containing the partition to be resized.")
+  (partition
+   (number -1)
+   "The partition number that is to be resized.")
+  (end
+   (string "100%")
+   "The end position of the resized partition as understood by the parted \
+utility (e.g. \"100%\", \"500M\" or \"16GiB\")."))
+
+(define (resize-fs-script config)
+  (match-record
+      config <resize-fs-configuration> (parted e2fsprogs device partition end)
+    (let ((parted-bin (file-append parted "/sbin/parted"))
+          (resize2fs  (file-append e2fsprogs "/sbin/resize2fs"))
+          (device+partition (string-append device "p" (number->string partition))))
+      (mixed-text-file "resize-fs.sh"
+                       "#!/bin/sh
+echoerr() { printf \"$*\\n\" >&2 ; }
+
+cmd() {
+    " parted-bin " " device " ---pretend-input-tty <<EOF && " resize2fs " " device+partition "
+resizepart
+" (number->string partition) "
+Yes
+" end "
+EOF
+}
+
+set -o errexit
+set -o pipefail
+
+if cmd; then
+  echoerr \"Resizing successful\"
+else
+  echoerr \"resize-script returned $?\"
+fi
+"))))
+
+(define (resize-fs-shepherd-service config)
+  "Return a list of <shepherd-service> for resize-fs-service for CONFIG."
+  (let ((resize-script (resize-fs-script config)))
+    (shepherd-service
+     (documentation "Resize a file-system.  Intended for Guix Systems that are \
+booted from a system image flashed onto a larger medium.")
+     (provision '(resize-fs))
+     (requirement '(user-processes))
+     (one-shot? #t)
+     (respawn? #f)
+     (start #~(make-forkexec-constructor
+               (list #$(file-append bash "/bin/sh") #$resize-script))))))
+
+(define resize-fs-service-type
+  (service-type
+   (name 'resize-fs)
+   (description "Resize a partition during boot.")
+   (extensions
+    (list
+     (service-extension shepherd-root-service-type
+                        (compose list resize-fs-shepherd-service))))
+   (default-value (resize-fs-configuration))))
+
 ;;; admin.scm ends here

base-commit: bb4f0509b7cce750fc944e604aa919ea89910ea7
-- 
2.41.0