@@ -14,7 +14,6 @@ import (
1414 "strings"
1515
1616 "github.com/kairos-io/AuroraBoot/internal"
17-
1817 "github.com/kairos-io/AuroraBoot/pkg/constants"
1918 "github.com/kairos-io/AuroraBoot/pkg/ops"
2019 "github.com/kairos-io/AuroraBoot/pkg/utils"
@@ -141,6 +140,11 @@ var BuildUKICmd = cli.Command{
141140 Name : "splash" ,
142141 Usage : "Path to the custom logo splash BMP file." ,
143142 },
143+ & cli.BoolFlag {
144+ Name : "cmd-lines-v2" ,
145+ Value : false ,
146+ Usage : "Use the new cmdline v2 format to generate a multiprofile efi with all the extra cmdlines. This requires systemd-boot 257 or newer." ,
147+ },
144148 },
145149 Before : func (ctx * cli.Context ) error {
146150 // // Mark flags as mutually exclusive
@@ -327,9 +331,10 @@ var BuildUKICmd = cli.Command{
327331 boodBranding := ctx .String ("boot-branding" )
328332 extraCmdlines := ctx .StringSlice ("extra-cmdline" )
329333 singleEfiCmdlines := ctx .StringSlice ("single-efi-cmdline" )
334+ cmdLinesV2 := ctx .Bool ("cmd-lines-v2" )
330335
331336 entries := append (
332- GetUkiCmdline (extendCmdline , boodBranding , extraCmdlines ),
337+ GetUkiCmdline (extendCmdline , boodBranding , extraCmdlines , cmdLinesV2 ),
333338 GetUkiSingleCmdlines (boodBranding , singleEfiCmdlines , logger )... )
334339
335340 for _ , entry := range entries {
@@ -376,6 +381,17 @@ var BuildUKICmd = cli.Command{
376381 Splash : ctx .String ("splash" ),
377382 }
378383
384+ // If we are using cmdLinesV2 we need to pass the extra cmdlines to generate a multiprofile efi
385+ if cmdLinesV2 {
386+ // extra cmdlines expand the base one, not substitute it completely
387+ // so we need to expand the entry.Cmdline with the extra cmdlines
388+
389+ for _ , cmd := range extraCmdlines {
390+ slog .Debug ("Expanding extra cmdline with base" , "cmdline" , cmd , "base" , entry .Cmdline )
391+ builder .ExtraCmdlines = append (builder .ExtraCmdlines , fmt .Sprintf ("%s %s" , entry .Cmdline , cmd ))
392+ }
393+ }
394+
379395 if err := os .Chdir (sourceDir ); err != nil {
380396 return fmt .Errorf ("changing to %s directory: %w" , sourceDir , err )
381397 }
@@ -385,9 +401,27 @@ var BuildUKICmd = cli.Command{
385401 }
386402
387403 logger .Info ("Creating kairos and loader conf files" )
388- if err := createConfFiles (sourceDir , entry .Cmdline , entry .Title , entry .FileName , kairosVersion , ctx .Bool ("include-version-in-config" ), ctx .Bool ("include-cmdline-in-config" )); err != nil {
404+
405+ // Always create the base config with profile 0
406+ logger .Info ("Creating base config file with profile 0" )
407+ if err := createConfFiles (sourceDir , entry .Cmdline , entry .Title , entry .FileName , kairosVersion , "0" , ctx .Bool ("include-version-in-config" ), ctx .Bool ("include-cmdline-in-config" )); err != nil {
389408 return err
390409 }
410+ // If cmdLinesV2 is set, we need to create the extra config files with the corresponding profile number
411+ // Profile number is the index + 1 (0 is the base config)
412+ if cmdLinesV2 {
413+ for i , cmd := range extraCmdlines {
414+ logger .Info ("Creating extra config file for cmdline" , "cmdline" , cmd )
415+ profile := fmt .Sprintf ("%d" , i + 1 )
416+ // I hoped that we should not set this and systemd-boot would automatically get it from the .profile section
417+ // as that can include the ID and title, but seems like it doesnt in neither type 1 or 2 entries :(
418+ title := fmt .Sprintf ("%s (%s)" , entry .Title , cmd )
419+
420+ if err := createConfFiles (sourceDir , fmt .Sprintf ("%s %s" , entry .Cmdline , cmd ), title , entry .FileName , kairosVersion , profile , ctx .Bool ("include-version-in-config" ), ctx .Bool ("include-cmdline-in-config" )); err != nil {
421+ return err
422+ }
423+ }
424+ }
391425 }
392426
393427 if err := createSystemdConf (sourceDir , ctx .String ("default-entry" ), ctx .String ("secure-boot-enroll" )); err != nil {
@@ -676,7 +710,13 @@ func getEfiStub(arch string) (string, error) {
676710 }
677711}
678712
679- func createConfFiles (sourceDir , cmdline , title , finalEfiName , version string , includeVersion , includeCmdline bool ) error {
713+ func createConfFiles (sourceDir , cmdline , title , finalEfiName , version , profile string , includeVersion , includeCmdline bool ) error {
714+ if _ , err := os .Stat (filepath .Join (sourceDir , "entries" )); os .IsNotExist (err ) {
715+ if err := os .Mkdir (filepath .Join (sourceDir , "entries" ), os .ModePerm ); err != nil {
716+ return fmt .Errorf ("error creating entries directory: %w" , err )
717+ }
718+ }
719+
680720 // This is stored in the config
681721 var extraCmdline string
682722 // For the config title we get only the extra cmdline we added, no replacement of spaces with underscores needed
@@ -688,8 +728,7 @@ func createConfFiles(sourceDir, cmdline, title, finalEfiName, version string, in
688728
689729 // You can add entries into the config files, they will be ignored by systemd-boot
690730 // So we store the cmdline in a key cmdline for easy tracking of what was added to the uki cmdline
691-
692- configData := fmt .Sprintf ("title %s\n efi /EFI/kairos/%s.efi\n " , title , finalEfiName )
731+ configData := fmt .Sprintf ("title %s\n sort-key %s-%s\n efi /EFI/kairos/%s.efi\n profile %s\n " , title , finalEfiName , profile , finalEfiName , profile )
693732
694733 if includeVersion {
695734 configData = fmt .Sprintf ("%sversion %s\n " , configData , version )
@@ -699,7 +738,13 @@ func createConfFiles(sourceDir, cmdline, title, finalEfiName, version string, in
699738 configData = fmt .Sprintf ("%scmdline %s\n " , configData , strings .Trim (extraCmdline , " " ))
700739 }
701740
702- err := os .WriteFile (filepath .Join (sourceDir , finalEfiName + ".conf" ), []byte (configData ), os .ModePerm )
741+ confName := finalEfiName + ".conf"
742+
743+ if profile != "0" {
744+ // For profiles different than 0 we add the profile number to the conf name so we can have multiple confs for the same efi
745+ confName = fmt .Sprintf ("%s-profile%s.conf" , finalEfiName , profile )
746+ }
747+ err := os .WriteFile (filepath .Join (sourceDir , "entries" , confName ), []byte (configData ), os .ModePerm )
703748 if err != nil {
704749 return fmt .Errorf ("creating the %s.conf file" , finalEfiName )
705750 }
@@ -826,7 +871,16 @@ func imageFiles(sourceDir, keysDir string, entries []utils.BootEntry) (map[strin
826871 // Add the kairos efi files and the loader conf files for each cmdline
827872 for _ , entry := range entries {
828873 data ["EFI/kairos" ] = append (data ["EFI/kairos" ], filepath .Join (sourceDir , entry .FileName + ".efi" ))
829- data ["loader/entries" ] = append (data ["loader/entries" ], filepath .Join (sourceDir , entry .FileName + ".conf" ))
874+ }
875+ // add any conf files that are in the sourceDir+entries dir
876+ files , err := os .ReadDir (filepath .Join (sourceDir , "entries" ))
877+ if err != nil {
878+ return data , fmt .Errorf ("reading source dir: %w" , err )
879+ }
880+ for _ , f := range files {
881+ if strings .HasSuffix (f .Name (), ".conf" ) {
882+ data ["loader/entries" ] = append (data ["loader/entries" ], filepath .Join (sourceDir , "entries" , f .Name ()))
883+ }
830884 }
831885 return data , nil
832886}
@@ -983,7 +1037,7 @@ func createContainer(sourceDir, outputDir, artifactName, outputName string, logg
9831037// For each cmdline passed, we generate a uki file with that cmdline
9841038// extend-cmdline will just extend the default cmdline so we only create one efi file. Artifact name is the default one
9851039// extra-cmdline will create a new efi file for each cmdline passed. artifact name is generated from the cmdline
986- func GetUkiCmdline (cmdlineExtend , bootBranding string , extraCmdlines []string ) []utils.BootEntry {
1040+ func GetUkiCmdline (cmdlineExtend , bootBranding string , extraCmdlines []string , cmdLinesV2 bool ) []utils.BootEntry {
9871041 defaultCmdLine := constants .UkiCmdline + " " + constants .UkiCmdlineInstall
9881042
9891043 // Override the default cmdline if the user passed one
@@ -1002,14 +1056,16 @@ func GetUkiCmdline(cmdlineExtend, bootBranding string, extraCmdlines []string) [
10021056 FileName : constants .ArtifactBaseName ,
10031057 }}
10041058
1005- // extra
1006- for _ , extra := range extraCmdlines {
1007- cmdline := defaultCmdLine + " " + extra
1008- result = append (result , utils.BootEntry {
1009- Cmdline : cmdline ,
1010- Title : bootBranding ,
1011- FileName : NameFromCmdline (constants .ArtifactBaseName , cmdline ),
1012- })
1059+ // if we are using the old style cmdlines, we add the extra ones
1060+ if ! cmdLinesV2 {
1061+ for _ , extra := range extraCmdlines {
1062+ cmdline := defaultCmdLine + " " + extra
1063+ result = append (result , utils.BootEntry {
1064+ Cmdline : cmdline ,
1065+ Title : bootBranding ,
1066+ FileName : NameFromCmdline (constants .ArtifactBaseName , cmdline ),
1067+ })
1068+ }
10131069 }
10141070
10151071 return result
0 commit comments