2023-02-01 21:33:44 +00:00
package mount
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/containerd/containerd/mount"
2023-02-09 09:12:11 +00:00
internalUtils "github.com/kairos-io/immucore/internal/utils"
2023-02-01 21:33:44 +00:00
"github.com/moby/sys/mountinfo"
)
// https://github.com/kairos-io/packages/blob/94aa3bef3d1330cb6c6905ae164f5004b6a58b8c/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L129
2023-02-06 14:28:22 +00:00
func baseOverlay ( overlay Overlay ) ( mountOperation , error ) {
2023-02-01 21:33:44 +00:00
if err := os . MkdirAll ( overlay . Base , 0700 ) ; err != nil {
return mountOperation { } , err
}
dat := strings . Split ( overlay . BackingBase , ":" )
if len ( dat ) != 2 {
return mountOperation { } , fmt . Errorf ( "invalid backing base. must be a tmpfs with a size or a block device. e.g. tmpfs:30%%, block:/dev/sda1. Input: %s" , overlay . BackingBase )
}
t := dat [ 0 ]
switch t {
case "tmpfs" :
2023-02-06 15:20:18 +00:00
tmpMount := mount . Mount { Type : "tmpfs" , Source : "tmpfs" , Options : [ ] string { fmt . Sprintf ( "size=%s" , dat [ 1 ] ) } }
2023-02-01 21:33:44 +00:00
err := mount . All ( [ ] mount . Mount { tmpMount } , overlay . Base )
2023-02-09 09:12:11 +00:00
tmpFstab := internalUtils . MountToFstab ( tmpMount )
2023-02-09 09:29:26 +00:00
// TODO: Fix this
// Currently stores it wrongly the the fstab as `tmpfs tmpfs:20% tmpfs size=20% 0 0`
// Correct format should be `tmpfs /run/overlay tmpfs defaults,size=20% 0 0`
2023-02-09 09:34:43 +00:00
tmpFstab . File = internalUtils . CleanSysrootForFstab ( overlay . Base )
2023-02-01 21:33:44 +00:00
return mountOperation {
MountOption : tmpMount ,
2023-02-06 15:20:18 +00:00
FstabEntry : * tmpFstab ,
2023-02-01 21:33:44 +00:00
Target : overlay . Base ,
} , err
case "block" :
blockMount := mount . Mount { Type : "auto" , Source : dat [ 1 ] }
err := mount . All ( [ ] mount . Mount { blockMount } , overlay . Base )
2023-02-09 09:12:11 +00:00
tmpFstab := internalUtils . MountToFstab ( blockMount )
2023-02-09 09:29:26 +00:00
// TODO: Check if this is properly written to fstab, currently have no examples
2023-02-09 09:34:43 +00:00
tmpFstab . File = internalUtils . CleanSysrootForFstab ( overlay . Base )
2023-02-06 15:20:18 +00:00
tmpFstab . MntOps [ "default" ] = ""
2023-02-01 21:33:44 +00:00
return mountOperation {
MountOption : blockMount ,
2023-02-06 15:20:18 +00:00
FstabEntry : * tmpFstab ,
2023-02-01 21:33:44 +00:00
Target : overlay . Base ,
} , err
default :
return mountOperation { } , fmt . Errorf ( "invalid overlay backing base type" )
}
}
// https://github.com/kairos-io/packages/blob/94aa3bef3d1330cb6c6905ae164f5004b6a58b8c/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L183
2023-02-08 13:43:58 +00:00
func mountBind ( mountpoint , root , stateTarget string ) mountOperation {
2023-02-01 21:33:44 +00:00
mountpoint = strings . TrimLeft ( mountpoint , "/" ) // normalize, remove / upfront as we are going to re-use it in subdirs
rootMount := filepath . Join ( root , mountpoint )
bindMountPath := strings . ReplaceAll ( mountpoint , "/" , "-" )
stateDir := filepath . Join ( root , stateTarget , fmt . Sprintf ( "%s.bind" , bindMountPath ) )
2023-02-08 13:43:58 +00:00
tmpMount := mount . Mount {
Type : "overlay" ,
Source : stateDir ,
Options : [ ] string {
//"defaults",
"bind" ,
} ,
}
2023-02-01 21:33:44 +00:00
2023-02-09 09:12:11 +00:00
tmpFstab := internalUtils . MountToFstab ( tmpMount )
2023-02-09 09:29:26 +00:00
tmpFstab . File = internalUtils . CleanSysrootForFstab ( fmt . Sprintf ( "/%s" , mountpoint ) )
2023-02-08 13:43:58 +00:00
tmpFstab . Spec = strings . ReplaceAll ( tmpFstab . Spec , root , "" )
return mountOperation {
MountOption : tmpMount ,
FstabEntry : * tmpFstab ,
Target : rootMount ,
PrepareCallback : func ( ) error {
2023-02-09 09:12:11 +00:00
if err := internalUtils . CreateIfNotExists ( rootMount ) ; err != nil {
2023-02-08 13:43:58 +00:00
return err
}
2023-02-09 09:12:11 +00:00
if err := internalUtils . CreateIfNotExists ( stateDir ) ; err != nil {
2023-02-08 13:43:58 +00:00
return err
}
2023-02-09 09:12:11 +00:00
return internalUtils . SyncState ( internalUtils . AppendSlash ( rootMount ) , internalUtils . AppendSlash ( stateDir ) )
2023-02-08 13:43:58 +00:00
} ,
2023-02-01 21:33:44 +00:00
}
}
// https://github.com/kairos-io/packages/blob/94aa3bef3d1330cb6c6905ae164f5004b6a58b8c/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L145
func mountWithBaseOverlay ( mountpoint , root , base string ) ( mountOperation , error ) {
mountpoint = strings . TrimLeft ( mountpoint , "/" ) // normalize, remove / upfront as we are going to re-use it in subdirs
rootMount := filepath . Join ( root , mountpoint )
bindMountPath := strings . ReplaceAll ( mountpoint , "/" , "-" )
2023-02-09 09:12:11 +00:00
// TODO: Should we error out if we cant create the target to mount to?
_ = internalUtils . CreateIfNotExists ( rootMount )
2023-02-01 21:33:44 +00:00
if mounted , _ := mountinfo . Mounted ( rootMount ) ; ! mounted {
upperdir := filepath . Join ( base , bindMountPath , ".overlay" , "upper" )
workdir := filepath . Join ( base , bindMountPath , ".overlay" , "work" )
tmpMount := mount . Mount {
Type : "overlay" ,
Source : "overlay" ,
Options : [ ] string {
2023-02-08 07:45:52 +00:00
//"defaults",
2023-02-01 21:33:44 +00:00
fmt . Sprintf ( "lowerdir=%s" , rootMount ) ,
fmt . Sprintf ( "upperdir=%s" , upperdir ) ,
fmt . Sprintf ( "workdir=%s" , workdir ) ,
} ,
}
2023-02-09 09:12:11 +00:00
tmpFstab := internalUtils . MountToFstab ( tmpMount )
2023-02-09 09:29:26 +00:00
tmpFstab . File = internalUtils . CleanSysrootForFstab ( rootMount )
2023-02-01 21:33:44 +00:00
// TODO: update fstab with x-systemd info
// https://github.com/kairos-io/packages/blob/94aa3bef3d1330cb6c6905ae164f5004b6a58b8c/packages/system/dracut/immutable-rootfs/30cos-immutable-rootfs/cos-mount-layout.sh#L170
return mountOperation {
MountOption : tmpMount ,
2023-02-06 15:20:18 +00:00
FstabEntry : * tmpFstab ,
2023-02-01 21:33:44 +00:00
Target : rootMount ,
PrepareCallback : func ( ) error {
// Make sure workdir and/or upper exists
os . MkdirAll ( upperdir , os . ModePerm )
os . MkdirAll ( workdir , os . ModePerm )
return nil
} ,
} , nil
}
return mountOperation { } , fmt . Errorf ( "already mounted" )
}