diff --git a/emhttp/plugins/dynamix/BootParameters.page b/emhttp/plugins/dynamix/BootParameters.page index f8dd65a87..acdc9abc0 100644 --- a/emhttp/plugins/dynamix/BootParameters.page +++ b/emhttp/plugins/dynamix/BootParameters.page @@ -65,7 +65,7 @@ $csrf_token = $var['csrf_token'] ?? '';
_(PCIe ACS Override)_ _(details)_:
- @@ -86,7 +86,7 @@ $csrf_token = $var['csrf_token'] ?? '';
_(VFIO Allow Unsafe Interrupts)_ _(details)_:
- +
vfio_iommu_type1.allow_unsafe_interrupts=1
@@ -665,10 +665,29 @@ function bootParamsTabFocus() { } // Update configuration preview -function updateConfig() { +function ensureApplyTogglesEnabled(labels) { + if (!Array.isArray(labels) || labels.length === 0) { + return; + } + + $('.boot-entry-apply-toggle').each(function() { + const toggle = $(this); + const label = toggle.attr('data-label'); + + if (labels.indexOf(label) !== -1 && !toggle.prop('checked')) { + toggle.switchButton('option', 'checked', true); + } + }); +} + +function updateConfig(changedFieldId) { // Handle mutual exclusivity for sysfb_blacklist toggle handleFramebufferMutualExclusivity(); + if (changedFieldId === 'acs-dropdown' || changedFieldId === 'vfio-toggle') { + ensureApplyTogglesEnabled(['Unraid OS', 'Unraid OS GUI Mode']); + } + markFormModified(); updatePreview(); } @@ -1044,7 +1063,7 @@ function updatePreview() { if (bootloaderType === 'grub') { html = 'linux /bzimage '; } else { - html = 'append initrd=/bzroot '; + html = 'append ' + getPreviewSyslinuxInitrd() + ' '; } // Add all proposed parameters in bright green with bold weight for visibility @@ -1203,11 +1222,47 @@ function stripSystemParams(line) { return indent + rest; } +function normalizeDisplayLineForComparison(line) { + if (!line) return ''; + return stripSystemParams(line).trim().replace(/\s+/g, ' '); +} + +function getSyslinuxInitrdForEntryLabel(label) { + return /GUI Mode|GUI Safe Mode/i.test(label || '') ? 'initrd=/bzroot,/bzroot-gui' : 'initrd=/bzroot'; +} + +function getPreviewSyslinuxInitrd() { + const appliedLabels = []; + $('.boot-entry-apply-toggle:checked').each(function() { + appliedLabels.push($(this).attr('data-label') || ''); + }); + + if (appliedLabels.length > 0 && appliedLabels.every(function(label) { + return /GUI Mode|GUI Safe Mode/i.test(label); + })) { + return 'initrd=/bzroot,/bzroot-gui'; + } + + return 'initrd=/bzroot'; +} + +function getSelectedDefaultEntryLabel() { + const selected = $('input[name="default-boot"]:checked').attr('data-label'); + return selected || ''; +} + /** * Helper function to create boot entry content with optional diff display */ function createEntryContent(entry, showApply) { const content = $('
').addClass('boot-entry-content');
+    const selectedDefaultLabel = getSelectedDefaultEntryLabel();
+    const shouldShowMenuDefault = bootloaderType === 'syslinux'
+        ? (selectedDefaultLabel ? entry.label === selectedDefaultLabel : entry.isDefault)
+        : entry.isDefault;
+    const originalHasMenuDefault = bootloaderType === 'syslinux' && entry.lines.some(function(entryLine) {
+        return entryLine.trim() === 'menu default';
+    });
 
     // Find the line index to update (append for syslinux, linux for GRUB)
     let appendLineIndex = -1;
@@ -1227,6 +1282,25 @@ function createEntryContent(entry, showApply) {
     // Build the content
     let contentHtml = '';
     entry.lines.forEach((line, idx) => {
+        const trimmed = line.trim();
+
+        if (bootloaderType === 'syslinux' && trimmed.startsWith('label ')) {
+            contentHtml += stripSystemParams(line) + '\n';
+            if (shouldShowMenuDefault && !originalHasMenuDefault) {
+                contentHtml += '  menu default\n';
+            }
+            return;
+        }
+
+        if (bootloaderType === 'syslinux' && trimmed === 'menu default') {
+            if (shouldShowMenuDefault) {
+                contentHtml += stripSystemParams(line) + '\n';
+            } else {
+                contentHtml += '' + stripSystemParams(line) + '\n';
+            }
+            return;
+        }
+
         if (idx === appendLineIndex && showApply) {
             // Show diff: removed line (original) and added line (with parameters)
             const originalAppend = stripSystemParams(line);
@@ -1257,10 +1331,12 @@ function createEntryContent(entry, showApply) {
                 const args = mergedArgs.length > 0 ? ' ' + mergedArgs.join(' ') : '';
                 newAppend = indent + cmd + ' ' + kernel + args;
             } else {
-                newAppend = '  append initrd=/bzroot' + (proposedParams.length > 0 ? ' ' + proposedParams.join(' ') : '');
+                const indentMatch = line.match(/^(\s*)append\b/);
+                const indent = indentMatch ? indentMatch[1] : '  ';
+                newAppend = indent + 'append ' + getSyslinuxInitrdForEntryLabel(entry.label) + (proposedParams.length > 0 ? ' ' + proposedParams.join(' ') : '');
             }
             const newAppendDisplay = stripSystemParams(newAppend);
-            if (originalAppend === newAppendDisplay) {
+            if (normalizeDisplayLineForComparison(originalAppend) === normalizeDisplayLineForComparison(newAppendDisplay)) {
                 contentHtml += originalAppend + '\n';
             } else {
                 contentHtml += '' + originalAppend + '\n';
@@ -1302,6 +1378,28 @@ function updateAllAppliedEntryDiffs() {
     });
 }
 
+function updateDefaultEntryDisplay() {
+    const selectedDefaultLabel = getSelectedDefaultEntryLabel();
+
+    $('.boot-entry').each(function() {
+        const entryDiv = $(this);
+        const entry = entryDiv.data('entry');
+        if (!entry) return;
+
+        const toggle = entryDiv.find('.boot-entry-apply-toggle');
+        if (toggle.length > 0 && selectedDefaultLabel && entry.label === selectedDefaultLabel && !toggle.prop('checked')) {
+            toggle.switchButton('option', 'checked', true);
+        }
+
+        entryDiv.toggleClass('default', !!selectedDefaultLabel && entry.label === selectedDefaultLabel);
+
+        const showApply = toggle.length > 0 && toggle.prop('checked');
+        updateEntryDiff(entryDiv, entry, showApply);
+    });
+
+    updatePreview();
+}
+
 /**
  * Render menu view from parsed configuration
  */
@@ -1443,6 +1541,7 @@ function renderMenuView(parsed) {
                 .prop('checked', entry.isDefault)
                 .on('change', function() {
                     markFormModified();
+                    updateDefaultEntryDisplay();
                 });
             header.append(radio);
         }
diff --git a/emhttp/plugins/dynamix/scripts/manage_boot_params.sh b/emhttp/plugins/dynamix/scripts/manage_boot_params.sh
index c6aeaf9f7..a64582a0f 100755
--- a/emhttp/plugins/dynamix/scripts/manage_boot_params.sh
+++ b/emhttp/plugins/dynamix/scripts/manage_boot_params.sh
@@ -39,6 +39,14 @@ detect_bootloader() {
 
 BOOTLOADER_TYPE="${BOOTLOADER_TYPE:-$(detect_bootloader)}"
 
+normalize_file_to_crlf() {
+    local file_path="$1"
+    local normalized_file="${file_path}.crlf"
+
+    awk '{ sub(/\r$/, ""); printf "%s\r\n", $0 }' "$file_path" > "$normalized_file"
+    mv "$normalized_file" "$file_path"
+}
+
 #############################################
 # JSON Escaping Function
 #############################################
@@ -265,17 +273,26 @@ parse_append_line() {
     # Matches from "label $label" to the next "label" or end of file
     # Normalize CRLF to LF for parsing (DOS-edited syslinux.cfg)
     tr -d '\r' < "$cfg_file" | awk -v label="$label" '
-        BEGIN { label=tolower(label) }
-        /^label / {
+        BEGIN {
+            label=tolower(label)
+            gsub(/^[[:space:]]+|[[:space:]]+$/, "", label)
+            gsub(/[[:space:]]+/, " ", label)
+        }
+        {
+            sub(/\r$/, "")
+        }
+        /^label[[:space:]]+/ {
             line=tolower($0)
-            if (line ~ "^label " label "$") {
+            gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
+            gsub(/[[:space:]]+/, " ", line)
+            if (line ~ "^label[[:space:]]+" label "$") {
                 in_section=1
             } else {
                 in_section=0
             }
         }
-        in_section && /^  append/ {
-            sub(/^  append /, "")
+        in_section && /^[[:space:]]*append([[:space:]]|$)/ {
+            sub(/^[[:space:]]*append[[:space:]]+/, "")
             print
             exit
         }
@@ -662,7 +679,7 @@ build_append_line() {
 # 4. Power Management (usbcore.autosuspend, nvme_core, pcie_aspm, pcie_port_pm)
 # 5. Custom Parameters (in array order, excluding pci=)
 build_append_line_gui_safe() {
-    local params="initrd=/bzroot"
+    local params="initrd=/bzroot,/bzroot-gui"
 
     # 1. VM Passthrough (safe for GUI mode)
     [[ -n "${ACS_OVERRIDE}" ]] && params="$params pcie_acs_override=${ACS_OVERRIDE}"
@@ -735,7 +752,7 @@ build_kernel_args() {
 }
 
 build_kernel_args_gui_safe() {
-    echo "$(build_append_line_gui_safe | sed 's/^initrd=\/bzroot[ ]*//')"
+    echo "$(build_append_line_gui_safe | sed 's/^initrd=\/bzroot,\/bzroot-gui[ ]*//')"
 }
 
 #############################################
@@ -794,32 +811,74 @@ update_default_boot() {
     awk '!/^  menu default$/' "$temp_file" > "${temp_file}.default"
     mv "${temp_file}.default" "$temp_file"
 
-    # Now add "menu default" to the target label
+    # Now add "menu default" immediately after the target label
     awk -v label="$target_label" '
         /^label / {
             current_label = $0
             sub(/^label /, "", current_label)
-            in_target = (current_label == label)
+            print
+            if (current_label == label) {
+                print "  menu default"
+            }
+            next
         }
         {
             print
-            # After printing the label line, check if we need to add menu default
-            if (in_target && /^label /) {
-                # Check if next line exists and is not menu default
-                getline next_line
-                if (next_line !~ /^  menu default$/) {
-                    print "  menu default"
-                    print next_line
-                } else {
-                    print next_line
-                }
-                in_target = 0
-            }
         }
     ' "$temp_file" > "${temp_file}.default"
     mv "${temp_file}.default" "$temp_file"
 }
 
+update_syslinux_label_append() {
+    local target_label="$1"
+    local append_args="$2"
+    local cfg_file="$3"
+
+    awk -v label="$target_label" -v append_args="$append_args" '
+        BEGIN {
+            normalized_label = label
+            gsub(/^[[:space:]]+|[[:space:]]+$/, "", normalized_label)
+            gsub(/[[:space:]]+/, " ", normalized_label)
+        }
+        /^[[:space:]]*label[[:space:]]+/ {
+            if (in_section && !replaced) {
+                print section_indent "append " append_args
+            }
+
+            current_label = $0
+            sub(/^[[:space:]]*label[[:space:]]+/, "", current_label)
+            gsub(/^[[:space:]]+|[[:space:]]+$/, "", current_label)
+            gsub(/[[:space:]]+/, " ", current_label)
+            in_section = (current_label == normalized_label)
+            replaced = 0
+            section_indent = "  "
+        }
+        {
+            if (in_section && $0 ~ /^[[:space:]]*append([[:space:]]|$)/) {
+                if (!replaced) {
+                    match($0, /^[[:space:]]*/)
+                    section_indent = substr($0, RSTART, RLENGTH)
+                    if (section_indent == "") {
+                        section_indent = "  "
+                    }
+                    print section_indent "append " append_args
+                    replaced = 1
+                }
+                next
+            }
+
+            print
+        }
+        END {
+            if (in_section && !replaced) {
+                print section_indent "append " append_args
+            }
+        }
+    ' "$cfg_file" > "${cfg_file}.append"
+
+    mv "${cfg_file}.append" "$cfg_file"
+}
+
 #############################################
 # Write new configuration to syslinux.cfg
 #############################################
@@ -863,100 +922,46 @@ write_config() {
     local temp_file=$(mktemp -p "$(dirname "$SYSLINUX_CFG")")
     cp "$SYSLINUX_CFG" "$temp_file"
 
+    # Strip CR from CRLF so awk/grep/sed-based syslinux updates match Unix line endings.
+    local temp_lf="${temp_file}.lf"
+    tr -d '\r' < "$temp_file" > "$temp_lf" && mv "$temp_lf" "$temp_file"
+
     # Update "Unraid OS" label if enabled in UI
     if [[ "${APPLY_TO_UNRAID_OS}" == "1" ]]; then
-        awk -v new_append="  append $new_append" '
-            /^label Unraid OS$/ {
-                in_section=1
-            }
-            /^label / && !/^label Unraid OS$/ {
-                in_section=0
-            }
-            {
-                if (in_section && /^  append/) {
-                    print new_append
-                } else {
-                    print
-                }
-            }
-        ' "$temp_file" > "${temp_file}.1"
-        mv "${temp_file}.1" "$temp_file"
+        update_syslinux_label_append "Unraid OS" "$new_append" "$temp_file"
     fi
 
     # Update "Unraid OS GUI Mode" label if enabled in UI
     if [[ "${APPLY_TO_GUI_MODE}" == "1" ]]; then
 
         # Optionally exclude framebuffer parameters for GUI mode entries
+        local gui_append
         if [[ "${EXCLUDE_FRAMEBUFFER_FROM_GUI}" == "1" ]]; then
-            local gui_append="  append $(build_append_line_gui_safe)"
+            gui_append="$(build_append_line_gui_safe)"
         else
-            local gui_append="  append $new_append"
+            gui_append="$(echo "$new_append" | sed 's/^initrd=\/bzroot\([ ]\|$\)/initrd=\/bzroot,\/bzroot-gui\1/')"
         fi
 
-        awk -v new_append="$gui_append" '
-            /^label Unraid OS GUI Mode$/ {
-                in_section=1
-            }
-            /^label / && !/^label Unraid OS GUI Mode$/ {
-                in_section=0
-            }
-            {
-                if (in_section && /^  append/) {
-                    print new_append
-                } else {
-                    print
-                }
-            }
-        ' "$temp_file" > "${temp_file}.2"
-        mv "${temp_file}.2" "$temp_file"
+        update_syslinux_label_append "Unraid OS GUI Mode" "$gui_append" "$temp_file"
     fi
 
     # Update "Unraid OS Safe Mode" label if enabled in UI
     if [[ "${APPLY_TO_SAFE_MODE}" == "1" ]]; then
-        awk -v new_append="  append $new_append" '
-            /^label Unraid OS Safe Mode/ {
-                in_section=1
-            }
-            /^label / && !/^label Unraid OS Safe Mode/ {
-                in_section=0
-            }
-            {
-                if (in_section && /^  append/) {
-                    print new_append
-                } else {
-                    print
-                }
-            }
-        ' "$temp_file" > "${temp_file}.3"
-        mv "${temp_file}.3" "$temp_file"
+        update_syslinux_label_append "Unraid OS Safe Mode (no plugins, no GUI)" "$new_append" "$temp_file"
     fi
 
     # Update "Unraid OS GUI Safe Mode" label if enabled in UI
     if [[ "${APPLY_TO_GUI_SAFE_MODE}" == "1" ]]; then
 
         # Optionally exclude framebuffer parameters for GUI mode entries
+        local gui_safe_append
         if [[ "${EXCLUDE_FRAMEBUFFER_FROM_GUI}" == "1" ]]; then
-            local gui_safe_append="  append $(build_append_line_gui_safe)"
+            gui_safe_append="$(build_append_line_gui_safe)"
         else
-            local gui_safe_append="  append $new_append"
+            gui_safe_append="$(echo "$new_append" | sed 's/^initrd=\/bzroot\([ ]\|$\)/initrd=\/bzroot,\/bzroot-gui\1/')"
         fi
 
-        awk -v new_append="$gui_safe_append" '
-            /^label Unraid OS GUI Safe Mode/ {
-                in_section=1
-            }
-            /^label / && !/^label Unraid OS GUI Safe Mode/ {
-                in_section=0
-            }
-            {
-                if (in_section && /^  append/) {
-                    print new_append
-                } else {
-                    print
-                }
-            }
-        ' "$temp_file" > "${temp_file}.4"
-        mv "${temp_file}.4" "$temp_file"
+        update_syslinux_label_append "Unraid OS GUI Safe Mode (no plugins)" "$gui_safe_append" "$temp_file"
     fi
 
     # Update default boot entry if requested
@@ -970,6 +975,8 @@ write_config() {
         rm -f "${temp_file}.timeout"
     fi
 
+    normalize_file_to_crlf "$temp_file"
+
     # Validate the modified config
     if validate_config "$temp_file"; then
         # Move temp file to actual config
@@ -1141,6 +1148,8 @@ write_config_grub() {
         fi
     fi
 
+    normalize_file_to_crlf "$temp_file"
+
     # Basic validation: ensure the config is non-empty and has at least one menuentry
     if [[ ! -s "$temp_file" ]] || ! grep -q '^menuentry ' "$temp_file"; then
         rm -f "$temp_file"
@@ -1192,6 +1201,8 @@ write_raw_config() {
     # Write raw config to temp file
     echo "$RAW_CONFIG" > "$temp_file"
 
+    normalize_file_to_crlf "$temp_file"
+
     # Validate the raw config (syslinux only)
     if [[ "$BOOTLOADER_TYPE" == "grub" ]] || validate_config "$temp_file"; then
         # Move temp file to actual config
diff --git a/emhttp/plugins/dynamix/scripts/system_information b/emhttp/plugins/dynamix/scripts/system_information
index ed91c8f18..2447f72b7 100755
--- a/emhttp/plugins/dynamix/scripts/system_information
+++ b/emhttp/plugins/dynamix/scripts/system_information
@@ -28,6 +28,7 @@ function port_get_contents($port) {
 $var      = (array)@parse_ini_file('state/var.ini');
 $model    = _var($var,'SYS_MODEL',_('N/A'));
 $board    = dmidecode('Base Board Information',2,0);
+$chassis  = dmidecode('Chassis Information',3,0);
 $bios     = dmidecode('BIOS Information',0,0);
 $cpu      = dmidecode('Processor Information',4,0);
 $cpumodel = str_ireplace(["Processor","(C)","(R)","(TM)"],["","©","®","™"],exec("grep -Pom1 '^model name\s+:\s*\K.+' /proc/cpuinfo") ?: $cpu['Version']);
@@ -38,6 +39,7 @@ $board['Manufacturer']  = (empty($board['Manufacturer']))  ? _('Unknown') : $boa
 $board['Product Name']  = (empty($board['Product Name']))  ? "" : $board['Product Name'];
 $board['Version']       = (empty($board['Version']))       ? "" : _('Version')." ".$board['Version'];
 $board['Serial Number'] = (empty($board['Serial Number'])) ? "" : _('s/n')." ".$board['Serial Number'];
+$chassis['Serial Number'] = (empty($chassis['Serial Number'])) ? "" : _('s/n')." ".$chassis['Serial Number'];
 $bios['Vendor']         = (empty($bios['Vendor']))         ? "" : $bios['Vendor'];
 $bios['Version']        = (empty($bios['Version']))        ? "" : _('Version')." ".$bios['Version'];
 $bios['Release Date']   = (empty($bios['Release Date']))   ? "" : _('Dated')." ".$bios['Release Date'];
@@ -162,6 +164,9 @@ span.link{text-decoration:underline;cursor:pointer}
 
+
+
+
:
:
:
:
:
: