From 33a73b2fb5d56e6ddd2a29be3b5adc90edad0878 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Fri, 2 Aug 2024 10:33:34 -0700 Subject: [PATCH 001/174] Forcibly kill samba if needed --- etc/rc.d/rc.samba | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/rc.samba b/etc/rc.d/rc.samba index 32c9bd18a..884fa6f69 100755 --- a/etc/rc.d/rc.samba +++ b/etc/rc.d/rc.samba @@ -37,6 +37,13 @@ samba_running(){ [[ $(pgrep -cf $SMBD) -gt 0 ]] } +samba_waitfor_shutdown(){ + for i in {1..5}; do + if ! samba_running; then break; fi + sleep 1 + done +} + samba_settings(){ [[ -z $COMMENT ]] && COMMENT="" [[ -z $SECURITY ]] && SECURITY="user" @@ -145,9 +152,17 @@ samba_stop(){ if ! samba_running; then REPLY="Already stopped" else + REPLY="Stopped" + # stop gracefully with SIGTERM run killall smbd nmbd wsdd2 winbindd + samba_waitfor_shutdown + if samba_running; then + REPLY="Killed" + # stop forcibly with SIGKILL + run killall -SIGKILL smbd nmbd wsdd2 winbindd + samba_waitfor_shutdown + fi if ! samba_running; then - REPLY="Stopped" # save samba 'secrets' file if changed if [[ -e $PRIVATE/secrets.tdb ]]; then rm -f /tmp/emhttp/secrets.tdb From 6a15afa2a8f6bd77c5cabc6836589824f2480e2e Mon Sep 17 00:00:00 2001 From: Squidly271 Date: Sun, 1 Sep 2024 15:57:02 -0400 Subject: [PATCH 002/174] Update Apps.page --- emhttp/plugins/dynamix/Apps.page | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/Apps.page b/emhttp/plugins/dynamix/Apps.page index 50826bfad..7e4d064cc 100644 --- a/emhttp/plugins/dynamix/Apps.page +++ b/emhttp/plugins/dynamix/Apps.page @@ -23,7 +23,7 @@ function installPlugin(file) {
_(Click **Install** to download and install the **Community Applications** plugin)_
- +   : From ceb97ab39288f2d536128492f76349d3ba5516a6 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:17:05 +0100 Subject: [PATCH 003/174] Disable dataset processing. --- emhttp/plugins/dynamix/include/Helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index d91e48566..8c9033bb6 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -358,7 +358,7 @@ function my_rmdir($dirname) { case "zfs": $zfsoutput = array(); $zfsdataset = trim(shell_exec("zfs list -H -o name \"$dirname\"")) ; - exec("zfs destroy \"$zfsdataset\"",$zfsoutput,$rtncode); + #exec("zfs destroy \"$zfsdataset\"",$zfsoutput,$rtncode); break; case "btrfs": default: From 07d02f579f427b02337e5a78e157c01aec559b47 Mon Sep 17 00:00:00 2001 From: Christoph Hummer Date: Mon, 2 Sep 2024 17:48:25 +0200 Subject: [PATCH 004/174] Add files via upload --- .../include/DockerClient.php | 3 + .../include/DockerContainers.php | 60 ++++++++++++++----- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php index f380d6121..b985c1be5 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php @@ -929,6 +929,9 @@ class DockerClient { $c['Created'] = $this->humanTiming($ct['Created']); $c['NetworkMode'] = $ct['HostConfig']['NetworkMode']; $c['Manager'] = $info['Config']['Labels']['net.unraid.docker.managed'] ?? false; + if ($c['Manager'] == 'composeman') { + $c['ComposeProject'] = $info['Config']['Labels']['com.docker.compose.project']; + } [$net, $id] = array_pad(explode(':',$c['NetworkMode']),2,''); $c['CPUset'] = $info['HostConfig']['CpusetCpus']; $c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false; diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php index 55a326dd6..172bc8f1c 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php @@ -69,7 +69,8 @@ foreach ($containers as $ct) { $running = $info['running'] ? 1 : 0; $paused = $info['paused'] ? 1 : 0; $is_autostart = $info['autostart'] ? 'true':'false'; - $updateStatus = substr($ct['NetworkMode'],-4)==':???' ? 2 : ($info['updated']=='true' ? 0 : ($info['updated']=='false' ? 1 : 3)); + $composestack = isset($ct['ComposeProject']) ? $ct['ComposeProject'] : ''; + $updateStatus = substr($ct['NetworkMode'], -4) == ':???' ? 2 : ($info['updated'] == 'true' ? 0 : ($info['updated'] == 'false' ? 1 : 3)); $template = $info['template']??''; $shell = $info['shell']??''; $webGui = html_entity_decode($info['url']??''); @@ -83,7 +84,7 @@ foreach ($containers as $ct) { $shape = $running ? ($paused ? 'pause' : 'play') : 'square'; $status = $running ? ($paused ? 'paused' : 'started') : 'stopped'; $color = $status=='started' ? 'green-text' : ($status=='paused' ? 'orange-text' : 'red-text'); - $update = $updateStatus==1 ? 'blue-text' : ''; + $update = $updateStatus==1 && !empty($compose) ? 'blue-text' : ''; $icon = $info['icon'] ?: '/plugins/dynamix.docker.manager/images/question.png'; $image = substr($icon,-4)=='.png' ? "" : (substr($icon,0,5)=='icon-' ? "" : ""); $wait = var_split($autostart[array_search($name,$names)]??'',1); @@ -119,12 +120,12 @@ foreach ($containers as $ct) { $paths[] = sprintf('%s%s', htmlspecialchars($container_path), $access_mode=='ro'?'long-arrow-left':'arrows-h', htmlspecialchars($host_path)); } echo ""; - if ($template) { + if ($template && empty($composestack)) { $appname = "".htmlspecialchars($name).""; } else { $appname = htmlspecialchars($name); } - echo "$image$appname
"._($status)."
"; + echo "$image$appname
"._($status).(!empty($composestack) ? '
Compose Stack: ' . $composestack : '')."
"; echo "
"._('Container ID').": $id
"; if ($ct['BaseImage']) echo "".htmlspecialchars($ct['BaseImage'])."
"; echo _('By').": "; @@ -137,28 +138,47 @@ foreach ($containers as $ct) { } echo "
"; switch ($updateStatus) { - case 0: - echo " "._('up-to-date').""; - if ($ct['Manager'] == "dockerman") - echo ""; - break; + case 0: + if ($ct['Manager'] == "dockerman") { + echo " "._('up-to-date').""; + echo ""; + } elseif (!empty($composestack)) { + echo "
Compose
"; + echo " "._('up-to-date').""; + } else { + echo "
3rd Party
"; + echo " "._('up-to-date').""; + } + break; case 1: echo "
"._('update ready')."
"; - if ($ct['Manager'] == "dockerman") - echo " "._('apply update').""; - else + if ($ct['Manager'] == "dockerman") { + echo " "._('apply update').""; + } elseif (!empty($composestack)) { + echo "
Compose
"; echo " "._('update available').""; + } else { + echo "
3rd Party
"; + echo " "._('update available').""; + } break; case 2: echo "
"._('rebuild ready')."
"; echo " "._('rebuilding').""; break; default: - echo " "._('not available').""; - if ($ct['Manager'] == "dockerman") + if ($ct['Manager'] == "dockerman") { + echo " "._('not available').""; echo ""; + } elseif (!empty($composestack)) { + echo "
Compose
"; + echo " "._('not available').""; + } else { + echo "
3rd Party
"; + echo " "._('not available').""; + } break; - } + } echo "
".compress(_($version),12,0)."
"; echo " ".implode('
',$networks)."
"; echo " ".implode('
',$network_ips)."
"; @@ -167,7 +187,15 @@ foreach ($containers as $ct) { echo "".implode('
',$paths)."
"; echo "0%
"; echo "
0 / 0"; - echo ""; + if (empty($composestack)) { + if ($ct['Manager'] == "dockerman") { + echo ""; + } else { + echo " 3rd Party"; + } + } else { + echo " Compose"; + } echo ""; echo "
".htmlspecialchars(str_replace('Up',_('Uptime').':',my_lang_log($ct['Status'])))."
"._('Created').": ".htmlspecialchars(my_lang_time($ct['Created']))."
"; } From 753d87c6903d6ef94a60038ce5760c5a06acf09f Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:03:10 +0100 Subject: [PATCH 005/174] Additional VM ZFS delete fixes --- .../dynamix.vm.manager/include/libvirt.php | 13 ++++++-- emhttp/plugins/dynamix/include/Helpers.php | 31 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 33e224e98..824d110b2 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -2004,8 +2004,17 @@ if (is_file($cfg)) unlink($cfg); if (is_file($xml)) unlink($xml); if (is_dir($dir) && $this->is_dir_empty($dir)) { - $error = my_rmdir($dir); - qemu_log("$domain","delete empty $dir $error"); + $result= my_rmdir($dir); + if ($result['type'] == "zfs") { + qemu_log("$domain","delete empty zfs $dir {$result['rtncode']}"); + if (isset($result['dataset'])) qemu_log("$domain","dataset {$result['dataset']} "); + if (isset($result['cmd'])) qemu_log("$domain","Command {$result['cmd']} "); + if (isset($result['output'])) { + $outputlogs = implode(" ",$result['output']); + qemu_log("$domain","Output $outputlogs end"); + } + } + else qemu_log("$domain","delete empty $dir {$result['rtncode']}"); } } diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 8c9033bb6..f64ba2f2d 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -345,27 +345,46 @@ function my_mkdir($dirname,$permissions = 0777,$recursive = false,$own = "nobody return($rtncode); } function my_rmdir($dirname) { - if (!is_dir($dirname)) return(false); + if (!is_dir("$dirname")) { + $return = [ + 'rtncode' => "false", + 'type' => "NoDir", + ]; + return($return); + } if (strpos($dirname,'/mnt/user/')===0) { $realdisk = trim(shell_exec("getfattr --absolute-names --only-values -n system.LOCATION ".escapeshellarg($dirname)." 2>/dev/null")); if (!empty($realdisk)) { - $dirname = str_replace('/mnt/user/', "/mnt/$realdisk/", $dirname); + $dirname = str_replace('/mnt/user/', "/mnt/$realdisk/", "$dirname"); } } - $fstype = trim(shell_exec(" stat -f -c '%T' $dirname")); + $fstype = trim(shell_exec(" stat -f -c '%T' ".escapeshellarg($dirname))); $rtncode = false; switch ($fstype) { case "zfs": $zfsoutput = array(); - $zfsdataset = trim(shell_exec("zfs list -H -o name \"$dirname\"")) ; - #exec("zfs destroy \"$zfsdataset\"",$zfsoutput,$rtncode); + $zfsdataset = trim(shell_exec("zfs list -H -o name ".escapeshellarg($dirname))) ; + $cmdstr = "zfs destroy \"$zfsdataset\" 2>&1 "; + $error = exec($cmdstr,$zfsoutput,$rtncode); + $return = [ + 'rtncode' => $rtncode, + 'output' => $zfsoutput, + 'dataset' => $zfsdataset, + 'type' => $fstype, + 'cmd' => $cmdstr, + 'error' => $error, + ]; break; case "btrfs": default: $rtncode = rmdir($dirname); + $return = [ + 'rtncode' => $rtncode, + 'type' => $fstype, + ]; break; } - return($rtncode); + return($return); } function get_realvolume($path) { if (strpos($path,"/mnt/user/",0) === 0) From 24bdc5169d737a961a0d9cb53dd4ea0f69b0981c Mon Sep 17 00:00:00 2001 From: dlandon Date: Tue, 3 Sep 2024 15:36:12 -0500 Subject: [PATCH 006/174] Parity check wrong again. --- emhttp/plugins/dynamix/nchan/parity_list | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/emhttp/plugins/dynamix/nchan/parity_list b/emhttp/plugins/dynamix/nchan/parity_list index e6d2210d6..9e8727efe 100755 --- a/emhttp/plugins/dynamix/nchan/parity_list +++ b/emhttp/plugins/dynamix/nchan/parity_list @@ -18,6 +18,7 @@ $log = '/boot/config/parity-checks.log'; $stamps = '/var/tmp/stamps.ini'; $resync = '/var/tmp/resync.ini'; $md5_old = $spot_old = $fs_old = $proc_old = -1; +$remove_resync_files = false; require_once "$docroot/webGui/include/Helpers.php"; require_once "$docroot/webGui/include/publish.php"; @@ -50,13 +51,13 @@ function update_translation($locale) { $text = "$docroot/languages/$locale/translations.txt"; if (file_exists($text)) { $store = "$docroot/languages/$locale/translations.dot"; - if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); + if (!file_exists($store)) file_put_contents_atomic($store,serialize(parse_lang_file($text))); $language = unserialize(file_get_contents($store)); } $text = "$docroot/languages/$locale/main.txt"; if (file_exists($text)) { $store = "$docroot/languages/$locale/main.dot"; - if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); + if (!file_exists($store)) file_put_contents_atomic($store,serialize(parse_lang_file($text))); $language = array_merge($language,unserialize(file_get_contents($store))); } } @@ -65,7 +66,7 @@ function create_sync($file) { return file_exists($file) ? explode(',',file_get_contents($file)) : []; } function create_file($file,...$data) { - if (!file_exists($file)) file_put_contents($file,implode(',',$data)); + if (!file_exists($file)) file_put_contents_atomic($file,implode(',',$data)); } while (true) { @@ -106,10 +107,15 @@ while (true) { /* Save the result in the parity history log. */ file_put_contents($log, "$timestamp|$duration|$speed|$status|$error|$action|$size\n", FILE_APPEND); - delete_file($stamps, $resync); + /* Remove the resync files after the history file has been updated. */ + $remove_resync_files = true; /* Parity check is completed. */ $echo = ""; + } elseif ($remove_resync_files) { + delete_file($stamps, $resync); + + $remove_resync_files = false; } } @@ -155,6 +161,6 @@ while (true) { $proc_old = publish('mymonitor', $process) !== false ? $process : -1; } - sleep(1); + sleep(3); } ?> From 4ea425411ad3212883ef7f42f27d605703b664d3 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Tue, 3 Sep 2024 21:45:50 +0100 Subject: [PATCH 007/174] Add disable rename if snapshots found. --- .../templates/Custom.form.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php index 58452f19e..54c0e3c15 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php @@ -317,6 +317,18 @@ } if ($usertemplate == 1) unset($arrConfig['domain']['uuid']); $xml2 = build_xml_templates($strXML); + #disable rename if snapshots exist + $snapshots = getvmsnapshots($arrConfig['domain']['name']) ; + if ($snapshots != null && count($snapshots) && !$boolNew) + { + $snaprenamehidden = ""; + $namedisable = "disabled"; + $snapcount = count($snapshots); + } else { + $snaprenamehidden = "hidden"; + $namedisable = ""; + $snapcount = "0"; + }; ?> @@ -336,10 +348,12 @@ - + - +
+ id="snap-rename" class="orange-text"> _(Rename disabled, snapshot(s) exists.)_ +
_(Name)_: type="text" name="domain[name]" id="domain_name" oninput="checkName(this.value)" class="textTemplate" title="_(Name of virtual machine)_" placeholder="_(e.g.)_ _(My Workstation)_" value="" required />
From ef5067584b4bf7275a2877c227c5d07f3224b1b9 Mon Sep 17 00:00:00 2001 From: dlandon Date: Wed, 4 Sep 2024 12:34:23 -0500 Subject: [PATCH 008/174] Change file_put_contents_atomic() back to file_put_contents() since it is liable to change. --- emhttp/plugins/dynamix/nchan/parity_list | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix/nchan/parity_list b/emhttp/plugins/dynamix/nchan/parity_list index 9e8727efe..f51db87e6 100755 --- a/emhttp/plugins/dynamix/nchan/parity_list +++ b/emhttp/plugins/dynamix/nchan/parity_list @@ -51,13 +51,13 @@ function update_translation($locale) { $text = "$docroot/languages/$locale/translations.txt"; if (file_exists($text)) { $store = "$docroot/languages/$locale/translations.dot"; - if (!file_exists($store)) file_put_contents_atomic($store,serialize(parse_lang_file($text))); + if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); $language = unserialize(file_get_contents($store)); } $text = "$docroot/languages/$locale/main.txt"; if (file_exists($text)) { $store = "$docroot/languages/$locale/main.dot"; - if (!file_exists($store)) file_put_contents_atomic($store,serialize(parse_lang_file($text))); + if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text))); $language = array_merge($language,unserialize(file_get_contents($store))); } } @@ -66,7 +66,7 @@ function create_sync($file) { return file_exists($file) ? explode(',',file_get_contents($file)) : []; } function create_file($file,...$data) { - if (!file_exists($file)) file_put_contents_atomic($file,implode(',',$data)); + if (!file_exists($file)) file_put_contents($file,implode(',',$data)); } while (true) { From c27e018fdbd5a32d5881adfdb4dcc620e7cbdf35 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Wed, 4 Sep 2024 21:11:44 +0100 Subject: [PATCH 009/174] Reduce Multifunction starting bus. --- emhttp/plugins/dynamix.vm.manager/include/libvirt.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 824d110b2..042a17ae0 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -910,9 +910,9 @@ } if ($gpu['multi'] == "on"){ - $newgpu_bus= 0x10; + $newgpu_bus= 0x07; if (!isset($multibus[$newgpu_bus])) { - $multibus[$newgpu_bus] = 0x10; + $multibus[$newgpu_bus] = 0x07; } else { #Get next bus $newgpu_bus = end($multibus) + 0x01; From 9b1081d2e1ab6980c1d9f06e60e07bc3e65f6da9 Mon Sep 17 00:00:00 2001 From: ljm42 Date: Wed, 4 Sep 2024 21:37:08 -0700 Subject: [PATCH 010/174] Add support for Tailscale certs in the webgui --- emhttp/languages/en_US/helptext.txt | 8 + emhttp/plugins/dynamix/ManagementAccess.page | 197 ++++++++++++++----- etc/rc.d/rc.nginx | 40 ++++ 3 files changed, 201 insertions(+), 44 deletions(-) diff --git a/emhttp/languages/en_US/helptext.txt b/emhttp/languages/en_US/helptext.txt index 33d9f9b77..0d6fc26a9 100644 --- a/emhttp/languages/en_US/helptext.txt +++ b/emhttp/languages/en_US/helptext.txt @@ -1283,6 +1283,14 @@ The Local Access URLs shown above are based on your current settings. To adjust URLs or redirects, see the help text for "Use SSL/TLS". :end +:mgmt_wg_access_urls_help: +These URLs will only work when connected via the appropriate WireGuard tunnel as configured on ***Settings > VPN Manager*** +:end + +:mgmt_tailscale_access_urls_help: +These URLs will only work when connected to the appropriate Tailscale Tailnet. +:end + :mgmt_certificate_expiration_help: **Provision** may be used to install a *free* myunraid.net SSL Certificate from [Let's Encrypt](https://letsencrypt.org/). diff --git a/emhttp/plugins/dynamix/ManagementAccess.page b/emhttp/plugins/dynamix/ManagementAccess.page index 00387791f..de094a7fc 100644 --- a/emhttp/plugins/dynamix/ManagementAccess.page +++ b/emhttp/plugins/dynamix/ManagementAccess.page @@ -117,51 +117,122 @@ if ($cert2Present) { } } +// Tailscale LE cert +$cert3File = "/boot/config/ssl/certs/ts_bundle.pem"; +$cert3Present = file_exists("$cert3File"); +if ($cert3Present) { + $cert3Subject = exec("/usr/bin/openssl x509 -in $cert3File -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'"); + $cert3Issuer = exec("/usr/bin/openssl x509 -in $cert3File -noout -text | sed -n -e 's/^.*Issuer: //p'"); + $cert3Expires = exec("/usr/bin/openssl x509 -in $cert3File -noout -text | sed -n -e 's/^.*Not After : //p'"); +} + +// Note: this disables FQDN6 urls since they are not supported by myunraid.net DNS currently +if (!empty($nginx['NGINX_LANFQDN6'])) unset($nginx['NGINX_LANFQDN6']); + $http_port = _var($var,'PORT','80') != '80' ? ":{$var['PORT']}" : ''; $https_port = _var($var,'PORTSSL','443') != '443' ? ":{$var['PORTSSL']}" : ''; -$http_ip_url = "http://"._var($nginx,'NGINX_LANIP')."{$http_port}/"; -$https_ip_url = "https://"._var($nginx,'NGINX_LANIP')."{$https_port}/"; -$http_ip6_url = "http://["._var($nginx,'NGINX_LANIP6')."]{$http_port}/"; -$https_ip6_url = "https://["._var($nginx,'NGINX_LANIP6')."]{$https_port}/"; -$http_mdns_url = "http://"._var($nginx,'NGINX_LANMDNS')."{$http_port}/"; -$https_mdns_url = "https://"._var($nginx,'NGINX_LANMDNS')."{$https_port}/"; -$https_fqdn_url = "https://"._var($nginx,'NGINX_LANFQDN')."{$https_port}/"; -$https_fqdn6_url = "https://"._var($nginx,'NGINX_LANFQDN6')."{$https_port}/"; +$http_ip_url = 'http://'._var($nginx,'NGINX_LANIP').$http_port.'/'; +$https_ip_url = 'https://'._var($nginx,'NGINX_LANIP').$https_port.'/'; +// bare IPv6 addresses need to be surrounded in brackets +$http_ip6_url = 'http://'.'['._var($nginx,'NGINX_LANIP6').']'.$http_port.'/'; +$https_ip6_url = 'https://'.'['._var($nginx,'NGINX_LANIP6').']'.$https_port.'/'; +$http_mdns_url = 'http://'._var($nginx,'NGINX_LANMDNS').$http_port.'/'; +$https_mdns_url = 'https://'._var($nginx,'NGINX_LANMDNS').$https_port.'/'; +$https_fqdn_url = 'https://'._var($nginx,'NGINX_LANFQDN').$https_port.'/'; +$https_fqdn6_url = 'https://'._var($nginx,'NGINX_LANFQDN6').$https_port.'/'; $urls = []; -// push an array of four values into the $urls array: -// 0 - the url -// 1 - the url it redirects to, or null -// 2 - the certificate file used, or null -// 3 - self-signed certificate, or false +// push an array of five values into the $urls array: +// 0 - type of url ['LAN','WAN','WG','TAILSCALE'] +// 1 - the url +// 3 - the url it redirects to, or null +// 4 - the certificate file used, or null +// 5 - self-signed certificate, or false +// define LAN access urls and redirects that change based on USE_SSL setting switch(_var($var,'USE_SSL','no')) { case 'no': - if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, null, null, false]; - if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, null, null, false]; - if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, null, null, false]; - if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false]; - if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false]; + if (!empty($nginx['NGINX_LANIP'])) $urls[] = ['LAN', $http_ip_url, null, null, false]; + if (!empty($nginx['NGINX_LANIP6'])) $urls[] = ['LAN', $http_ip6_url, null, null, false]; + if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = ['LAN', $http_mdns_url, null, null, false]; break; case 'yes': - if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, $https_ip_url, null, false]; - if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$https_ip_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; - if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, $https_ip6_url, null, false]; - if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$https_ip6_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; - if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, $https_mdns_url, null, false]; - if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$https_mdns_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; - if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false]; - if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false]; + if (!empty($nginx['NGINX_LANIP'])) $urls[] = ['LAN', $http_ip_url, $https_ip_url, null, false]; + if (!empty($nginx['NGINX_LANIP'])) $urls[] = ['LAN', $https_ip_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; + if (!empty($nginx['NGINX_LANIP6'])) $urls[] = ['LAN', $http_ip6_url, $https_ip6_url, null, false]; + if (!empty($nginx['NGINX_LANIP6'])) $urls[] = ['LAN', $https_ip6_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; + if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = ['LAN', $http_mdns_url, $https_mdns_url, null, false]; + if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = ['LAN', $https_mdns_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned]; break; case 'auto': // aka strict - if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, $https_fqdn_url, null, false]; - if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, $https_fqdn6_url, null, false]; - if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, $https_fqdn_url, null, false]; - if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false]; - if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false]; + if (!empty($nginx['NGINX_LANIP']) && !empty($nginx['NGINX_LANFQDN'])) $urls[] = ['LAN', $http_ip_url, $https_fqdn_url, null, false]; + if (!empty($nginx['NGINX_LANIP6']) && !empty($nginx['NGINX_LANFQDN6'])) $urls[] = ['LAN', $http_ip6_url, $https_fqdn6_url, null, false]; + if (!empty($nginx['NGINX_LANMDNS']) && !empty($nginx['NGINX_LANFQDN'])) $urls[] = ['LAN', $http_mdns_url, $https_fqdn_url, null, false]; break; } +// define FQDN urls for each interface +// when multiple FQDN urls are available for a given interface, make sure they are sorted +asort($nginx); +foreach ($nginx as $key => $host) { + if (!$host) continue; + // Only process keys that include 'FQDN' + if (strpos($key, 'FQDN') === false) continue; + // Extract the interface from the key, e.g., 'NGINX_LANFQDN' -> 'LAN', 'NGINX_WANFQDN' -> 'WAN', NGINX_WG0FQDN -> WG, NGINX_TAILSCALE1FQDN -> TAILSCALE + // Note: this specifically excludes FQDN6 urls since they are not supported by myunraid.net DNS currently + if (preg_match('/^NGINX_([A-Z]+)(\d*)FQDN$/', $key, $matches)) { + $interface = $matches[1]; // Interface type (LAN, WAN, WG, TAILSCALE, etc.) + // ignore the WAN interface because we don't have access to the WANPORT here + if ($interface == "WAN") continue; + $pem = null; + if (str_ends_with($host, '.myunraid.net')) $pem = 'certificate_bundle.pem'; + elseif (str_ends_with($host, '.ts.net')) $pem = 'ts_bundle.pem'; + $url = 'https://'.$host.$https_port."/"; + $urls[] = [$interface, $url, null, $pem, false]; + } +} + +// determine whether there are urls for a given interface +function has_urls($interface) { + global $urls; + foreach($urls as $url) { + if ($url[0] == $interface) return true; + } + return false; +} + +// show all urls for a given interface +function show_urls($interface) { + global $urls; + // 0 - type of url ['LAN','WAN','WG','TAILSCALE'] + // 1 - the url + // 3 - the url it redirects to, or null + // 4 - the certificate file used, or null + // 5 - self-signed certificate, or false + $output = ""; + $linestart = "
 
"; + $lineend = "
\n"; + $first = true; + foreach($urls as $url) { + if ($url[0] == $interface) { + $msg = "$url[1]"; + if ($url[2]) $msg .= " "._("redirects to")." $url[2]"; + if ($url[3]) $msg .= " "._("uses")." ".$url[3]; + if ($url[4]) $msg .= " "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI").""; + // 2nd+ urls need leading $linestart + $output .= ($first ? "" : $linestart).$msg.$lineend; + $first = false; + } + } + if ($first) { + $output = "none"; + } else { + // strip final trailing $lineend as it will be added by markdown + $output = substr($output, 0, strlen($lineend)*-1); + } + echo $output; +} + $cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replace(['%M','%R'],['%M:%S','%R:%S'],$display['time']):''); $provisionlabel = $isWildcardCert ? _('Renew') : _('Provision'); $disabled_provision = $keyfile===false || ($isWildcardCert && $retval_expired===0) || !$addr ? 'disabled' : ''; @@ -334,24 +405,34 @@ _(Local TLD)_: +
+ _(Local access URLs)_: -: $url[1]"; - if ($url[2]) $msg .= " "._("uses")." ".$url[2]; - if ($url[3]) $msg .= " "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI").""; - echo ($n ? "
 
" : ""),"$url[0]$msg",($n++ ? "
" : ""); -}?> +: :mgmt_local_access_urls_help: + + +_(WireGuard URLs)_: +: + +:mgmt_wg_access_urls_help: + + + + + +_(Tailscale URLs)_: +: + +:mgmt_tailscale_access_urls_help: + + + +
+ _(Self-signed or user-provided certificate)_: : @@ -386,6 +467,9 @@ _(Self-signed certificate file)_: "> + +
+ _(Unraid Let's Encrypt certificate)_: : @@ -415,6 +499,31 @@ _(CA-signed certificate file)_:   : + + + +
+ +_(Tailscale Let's Encrypt certificate)_: +: + +_(Certificate URL)_: +: $cert3Subject"?> + +_(Certificate issuer)_: +: + +_(Certificate expiration)_: +: + + + :mgmt_certificate_expiration_help: + + + +"WireGuard" and the "WireGuard" logo are registered trademarks of Jason A. Donenfeld + + diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index be1d7fc03..8a527cd07 100755 --- a/etc/rc.d/rc.nginx +++ b/etc/rc.d/rc.nginx @@ -18,6 +18,7 @@ DAEMON="Nginx server daemon" CALLER="nginx" NGINX="/usr/sbin/nginx" +TS="/usr/local/sbin/tailscale" PID="/var/run/nginx.pid" SSL="/boot/config/ssl" CONF="/etc/nginx/nginx.conf" @@ -26,6 +27,7 @@ SERVERS="/etc/nginx/conf.d/servers.conf" LOCATIONS="/etc/nginx/conf.d/locations.conf" INI="/var/local/emhttp/nginx.ini.new" CERTPATH="$SSL/certs/certificate_bundle.pem" +TSCERTPATH="$SSL/certs/ts_bundle.pem" MYSERVERS="/boot/config/plugins/dynamix.my.servers/myservers.cfg" # hold server names @@ -285,6 +287,29 @@ build_servers(){ EOF fi fi + if [[ -n $TSFQDN ]]; then + cat <<- EOF >>$SERVERS + # + # Port settings for https using Tailscale cert + # ex: https://tower.magicDNS.ts.net + # + server { + $(listen $PORTSSL ssl http2) + server_name $TSFQDN; + # Ok to use concatenated pem files; nginx will do the right thing. + ssl_certificate $TSCERTPATH; + ssl_certificate_key $TSCERTPATH; + ssl_trusted_certificate $TSCERTPATH; + # + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + # + location ~ /wsproxy/$PORTSSL/ { return 403; } + include /etc/nginx/conf.d/locations.conf; + } + EOF + fi } # build our locations @@ -534,6 +559,19 @@ build_ssl(){ [[ -n $(openssl x509 -noout -ocsp_uri -in "$CERTPATH") ]] && CERTSTAPLE=on || CERTSTAPLE=off fi + # handle TS cert if present + if [[ -f "$TSCERTPATH" ]]; then + # confirm TS is intalled and running + if [[ -x $TS ]] && $TS status &>/dev/null; then + # extract common name from cert + TSFQDN1=$(openssl x509 -noout -subject -nameopt multiline -in "$TSCERTPATH" | sed -n 's/ *commonName *= //p') + # get tailscale domain + TSFQDN2=$($TS status -json | jq ' .Self.DNSName' | tr -d '"' | sed 's/.$//') + # if they are equal and not empty, the cert is valid, use it + [[ -n "$TSFQDN1" ]] && [[ "$TSFQDN1" == "$TSFQDN2" ]] && TSFQDN=$TSFQDN1 + fi + fi + # build servers configuration file build_servers # build locations configuration file @@ -570,6 +608,8 @@ build_ssl(){ echo "NGINX_WANIP6=\"$WANIP6\"" >>$INI echo "NGINX_WANFQDN=\"$WANFQDN\"" >>$INI echo "NGINX_WANFQDN6=\"$WANFQDN6\"" >>$INI + # defined if ts_bundle.pem present: + echo "NGINX_TAILSCALEFQDN=\"$TSFQDN\"" >>$INI # add included interfaces for NET in ${!NET_FQDN[@]}; do echo "NGINX_${NET^^}FQDN=\"${NET_FQDN[$NET]}\"" >>$INI From 1e43abc785fb1b6cbadbea362c7d836aee90d3a8 Mon Sep 17 00:00:00 2001 From: Christoph Hummer Date: Thu, 5 Sep 2024 10:16:51 +0200 Subject: [PATCH 011/174] Fix issue with plugin icons - make sure the maximum icon size for a plugin is 18x18px --- emhttp/plugins/dynamix/include/PageBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/PageBuilder.php b/emhttp/plugins/dynamix/include/PageBuilder.php index 19bdc1fbc..40f56778c 100644 --- a/emhttp/plugins/dynamix/include/PageBuilder.php +++ b/emhttp/plugins/dynamix/include/PageBuilder.php @@ -78,7 +78,7 @@ function tab_title($title,$path,$tag) { if (!$tag || substr($tag,-4)=='.png') { $file = "$path/icons/".($tag ?: strtolower(str_replace(' ','',$title)).".png"); if (file_exists("$docroot/$file")) { - return "$title"; + return "$title"; } else { return "$title"; } From 039c798b43207d2465d0c189da23846ad593d727 Mon Sep 17 00:00:00 2001 From: Derek Kaser <11674153+dkaser@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:00:20 +0000 Subject: [PATCH 012/174] Add fastcgi_path_info to default nginx configuration --- etc/rc.d/rc.nginx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etc/rc.d/rc.nginx b/etc/rc.d/rc.nginx index be1d7fc03..7a86d0a22 100755 --- a/etc/rc.d/rc.nginx +++ b/etc/rc.d/rc.nginx @@ -386,7 +386,9 @@ build_locations(){ # # pass PHP scripts to FastCGI server listening on unix:/var/run/php-fpm.sock # - location ~ \.php$ { + location ~ ^(.+\.php)(.*)$ { + fastcgi_split_path_info ^(.+\.php)(.*)$; + fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; } # From 6b31532688c6288760d687217587829b1e8b7af3 Mon Sep 17 00:00:00 2001 From: Robin Kluth Date: Fri, 6 Sep 2024 15:46:06 +0200 Subject: [PATCH 013/174] Add a log line noting how long we wait currently for a VM action. --- etc/rc.d/rc.libvirt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/rc.d/rc.libvirt b/etc/rc.d/rc.libvirt index 6299cd411..cd4ce5cef 100755 --- a/etc/rc.d/rc.libvirt +++ b/etc/rc.d/rc.libvirt @@ -60,6 +60,9 @@ vmlist(){ waitfor(){ local C=0 while [[ $C -lt $TIMEOUT && $(virsh list --state-$1 | awk "NR>2 && /${2:-^.+$}/" | wc -l) -gt 0 ]]; do + if [ $C -eq 0 ]; then # echo Timeout info just one time and only if virsh returned something + log "Waiting $TIMEOUT seconds for VMs with state: $1" + fi ((C++)) sleep 1 done From 73705b71fab865020acbd8a480868cf39239731b Mon Sep 17 00:00:00 2001 From: desertwitch <24509509+desertwitch@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:21:18 +0200 Subject: [PATCH 014/174] dynamix/include/SysDevs.php: fix PHP warnings test for exec-returned variable existence before usage --- emhttp/plugins/dynamix/include/SysDevs.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/emhttp/plugins/dynamix/include/SysDevs.php b/emhttp/plugins/dynamix/include/SysDevs.php index cf5d90905..32fbddb22 100644 --- a/emhttp/plugins/dynamix/include/SysDevs.php +++ b/emhttp/plugins/dynamix/include/SysDevs.php @@ -75,9 +75,11 @@ case 't1': foreach ($devicelist as $line) { if (!empty($line)) { exec('udevadm info --path=$(udevadm info -q path /dev/'.$line.' | cut -d / -f 1-7) --query=path',$linereturn); - preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse); - foreach ($inuse[0] as $line) { - $lines[] = $line; + if(isset($linereturn[0])) { + preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse); + foreach ($inuse[0] as $line) { + $lines[] = $line; + } } unset($inuse); unset($linereturn); @@ -92,9 +94,11 @@ case 't1': foreach ($nics as $line) { if (!empty($line)) { exec('readlink /sys/class/net/'.$line,$linereturn); - preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse); - foreach ($inuse[0] as $line) { - $lines[] = $line; + if(isset($linereturn[0])) { + preg_match_all($DBDF_PARTIAL_REGEX, $linereturn[0], $inuse); + foreach ($inuse[0] as $line) { + $lines[] = $line; + } } unset($inuse); unset($linereturn); From 16823d07b117f0284b45101f6339357a908298a8 Mon Sep 17 00:00:00 2001 From: Rysz <24509509+desertwitch@users.noreply.github.com> Date: Mon, 9 Sep 2024 06:56:35 +0200 Subject: [PATCH 015/174] en_US/helptext.txt: Fix broken link --- emhttp/languages/en_US/helptext.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/languages/en_US/helptext.txt b/emhttp/languages/en_US/helptext.txt index 33d9f9b77..016d9d9ae 100644 --- a/emhttp/languages/en_US/helptext.txt +++ b/emhttp/languages/en_US/helptext.txt @@ -256,7 +256,7 @@ Unraid OS uses these default options when creating a multiple-device pool: `-dconvert=raid1 -mconvert=raid1` -For more complete documentation, please refer to the btrfs-balance [Manpage](https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-balance) +For more complete documentation, please refer to the btrfs-balance [Manpage](https://man7.org/linux/man-pages/man8/btrfs-balance.8.html) *Note: raid5 and raid6 are generally still considered **experimental** by the Linux community* :end From e9faee0d27f93ca0cd9fb35fe58137b75686afc4 Mon Sep 17 00:00:00 2001 From: Christoph Hummer Date: Mon, 9 Sep 2024 17:07:43 +0200 Subject: [PATCH 016/174] Update CreateDocker.php --- .../include/CreateDocker.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index 11e4eac2a..568ae97af 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -213,6 +213,9 @@ if (isset($_GET['xmlTemplate'])) { if (is_file($xmlTemplate)) { $xml = xmlToVar($xmlTemplate); $templateName = $xml['Name']; + if (preg_match('/^container:(.*)/', $xml['Network'])) { + $xml['Network'] = explode(':', $xml['Network'], 2); + } if ($xmlType == 'default') { if (!empty($dockercfg['DOCKER_APP_CONFIG_PATH']) && file_exists($dockercfg['DOCKER_APP_CONFIG_PATH'])) { // override /config @@ -858,6 +861,7 @@ _(Network Type)_: : + getDockerContainers() as $ct) { + if ($ct['Name'] !== $xml['Name']) { + $list[] = $ct['Name']; + echo mk_option($ct['Name'], $ct['Name'], $ct['Name']); + } + } + ?> +:docker_container_network_help: + _(Console shell command)_: : From e52813b6262f5c4235de4e97c214608d2a96f62b Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Thu, 19 Sep 2024 22:16:00 +0100 Subject: [PATCH 024/174] Divide net and disk values by timer --- emhttp/plugins/dynamix.vm.manager/nchan/vm_usage | 4 ++-- emhttp/plugins/dynamix/nchan/vm_dashusage | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage b/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage index ce62b8a93..887ec80c3 100755 --- a/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage +++ b/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage @@ -80,8 +80,8 @@ while (true) { $echodata .= my_scale($vmdata['mem']*1024,$unit)."$unit / ".my_scale($vmdata['curmem']*1024,$unit)."$unit"; if ($vmdata['curmem'] === $vmdata['maxmem']) $echodata .= " "; else $echodata .= " / " .my_scale($vmdata['maxmem']*1024,$unit)."$unit "; - $echodata .= _("Read").": ".my_scale($vmdata['rdrate'],$unit)."$unit/s
"._("Write").": ".my_scale($vmdata['wrrate'],$unit)."$unit/s"; - $echodata .= _("RX").": ".my_scale($vmdata['rxrate'],$unit)."$unit/s
"._("TX").": ".my_scale($vmdata['txrate'],$unit)."$unit/s"; + $echodata .= _("Read").": ".my_scale($vmdata['rdrate']/$timer,$unit)."$unit/s
"._("Write").": ".my_scale($vmdata['wrrate']/$timer,$unit)."$unit/s"; + $echodata .= _("RX").": ".my_scale($vmdata['rxrate']/$timer,$unit)."$unit/s
"._("TX").": ".my_scale($vmdata['txrate']/$timer,$unit)."$unit/s"; } $echo = $echodata ; } diff --git a/emhttp/plugins/dynamix/nchan/vm_dashusage b/emhttp/plugins/dynamix/nchan/vm_dashusage index 3cdffef28..be0415b81 100755 --- a/emhttp/plugins/dynamix/nchan/vm_dashusage +++ b/emhttp/plugins/dynamix/nchan/vm_dashusage @@ -78,8 +78,8 @@ while (true) { $echo[$vmencode ]['mem'] = "Mem: ".my_scale($vmdata['mem']*1024,$unit)."$unit / ".my_scale($vmdata['curmem']*1024,$unit)."$unit"; if ($vmdata['maxmem'] == $vmdata['curmem']) $echo[$vmencode ]['mem'] .="  "; else $echo[$vmencode ]['mem'] .= " / ".my_scale($vmdata['maxmem']*1024,$unit)."$unit  "; - $echo[$vmencode ]['disk'] = "Disk: "._("Rd").": ".my_scale($vmdata['rdrate'],$unit)."$unit/s "._("Wr").": ".my_scale($vmdata['wrrate'],$unit)."$unit/s  "; - $echo[$vmencode ]['net'] = "Net: "._("RX").": ".my_scale($vmdata['rxrate'],$unit)."$unit/s "._("TX").": ".my_scale($vmdata['txrate'],$unit)."$unit/s  "; + $echo[$vmencode ]['disk'] = "Disk: "._("Rd").": ".my_scale($vmdata['rdrate']/$timer,$unit)."$unit/s "._("Wr").": ".my_scale($vmdata['wrrate']/$timer,$unit)."$unit/s  "; + $echo[$vmencode ]['net'] = "Net: "._("RX").": ".my_scale($vmdata['rxrate']/$timer,$unit)."$unit/s "._("TX").": ".my_scale($vmdata['txrate']/$timer,$unit)."$unit/s  "; } } From 4a4983f7c58880a9b87d081b640edc1e7c1fa90e Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Mon, 16 Sep 2024 15:02:15 -0700 Subject: [PATCH 025/174] rc.S: reboot should not invoke shutdown --- etc/rc.d/rc.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/rc.d/rc.S b/etc/rc.d/rc.S index 2d3387abb..082e84926 100755 --- a/etc/rc.d/rc.S +++ b/etc/rc.d/rc.S @@ -79,7 +79,7 @@ abort() { /bin/umount -a read -p "$1 - press ENTER key to reboot..." /bin/echo - /sbin/reboot + /sbin/reboot -fd } find_device() { From 4c6be23467f0b220f4d735f8e724bbb428f9a5b2 Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Fri, 20 Sep 2024 09:18:39 -0700 Subject: [PATCH 026/174] Clean up empty cgroups --- etc/rc.d/rc.S.cont | 6 ++++ etc/rc.d/rc.cgroup2unraid | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 etc/rc.d/rc.cgroup2unraid diff --git a/etc/rc.d/rc.S.cont b/etc/rc.d/rc.S.cont index d98f3e407..6930cf426 100755 --- a/etc/rc.d/rc.S.cont +++ b/etc/rc.d/rc.S.cont @@ -69,6 +69,7 @@ if /bin/grep -wq cgroup /proc/filesystems; then # See https://docs.kernel.org/admin-guide/cgroup-v2.html (section Mounting) # Mount cgroup2 filesystem /sbin/mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup + chmod +x /etc/rc.d/rc.cgroup2unraid else # Display message if /sys/fs/cgroup does not exist echo "/sys/fs/cgroup does not exist. cgroup2 cannot be mounted." @@ -159,6 +160,11 @@ if [[ -x /etc/rc.d/rc.cgconfig && -x /etc/rc.d/rc.cgred && -d /sys/fs/cgroup ]]; /etc/rc.d/rc.cgred start fi +# Start cgroup2 cleanup daemon +if [[ -x /etc/rc.d/rc.cgroup2unraid && -d /sys/fs/cgroup ]]; then + /etc/rc.d/rc.cgroup2unraid start +fi + # Create /tmp/{.ICE-unix,.X11-unix} if they are not present: if [[ ! -e /tmp/.ICE-unix ]]; then /bin/mkdir -p /tmp/.ICE-unix diff --git a/etc/rc.d/rc.cgroup2unraid b/etc/rc.d/rc.cgroup2unraid new file mode 100644 index 000000000..75087556a --- /dev/null +++ b/etc/rc.d/rc.cgroup2unraid @@ -0,0 +1,75 @@ +#!/bin/bash +# +# script: rc.cgroup2unraid +# +# start/stop/status/restart/run Unraid cgroup2 cleanup: +# +# LimeTech - created for Unraid OS +# /etc/rc.d/rc.cgroup2unraid + +DAEMON="Unraid cgroup2 cleanup daemon" +CGROUP2="/usr/libexec/unraid/cgroup2-unraid" +PID="/var/run/cgroup2-unraid.pid" + +# run & log functions +. /etc/rc.d/rc.runlog + + +cgroup2daemon_running(){ + sleep 0.1 + [[ $(pgrep -cf $CGROUP2) -gt 0 ]] +} + +case "$1" in + start) + if cgroup2daemon_running ; then + REPLY="Already started" + else + $CGROUP2 --daemon + echo $(pgrep -f $CGROUP2) > $PID + if cgroup2daemon_running; then + REPLY="Started" + else + REPLY="Failed" + fi + fi + log "$DAEMON... $REPLY." + ;; + stop) + if ! cgroup2daemon_running ; then + REPLY="Already stopped" + else + log "Stopping $DAEMON..." + kill $(cat $PID) + if cgroup2daemon_running; then + REPLY="Failed" + else + REPLY="Stopped" + fi + fi + log "$DAEMON... $REPLY." + ;; + status) + if cgroup2daemon_running ; then + echo "$DAEMON running" + else + echo "$DAEMON not running" + if [ -f $PID ]; then + rm -f $PID + fi + fi + ;; + run) + echo "Cleaning up cgroups..." + $CGROUP2 + echo "Done!" + ;; + restart) + $0 stop + $0 start + ;; + *) + echo "Usage: $BASENAME start|stop|status|restart|run" + exit 1 +esac +exit 0 \ No newline at end of file From 54b1e81b3806d89c9e4ffbcc0aa22c736dec24cd Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Mon, 23 Sep 2024 10:54:57 -0700 Subject: [PATCH 027/174] unconditinally set directories to mode 0777 --- emhttp/plugins/dynamix/scripts/newperms | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/emhttp/plugins/dynamix/scripts/newperms b/emhttp/plugins/dynamix/scripts/newperms index 7f36b231d..34188a375 100755 --- a/emhttp/plugins/dynamix/scripts/newperms +++ b/emhttp/plugins/dynamix/scripts/newperms @@ -12,11 +12,10 @@ # With corrections suggested by forum member Stokkes -# Here's a breakdown of chmod "u-x,go-rwx,go+u,ugo+X" -# u-x Clear the 'x' bit in the user permissions (leaves rw as-is) +# Here's a breakdown of chmod "go-rwx,u-x,go+u" # go-rwx Clear the 'rwx' bits in both the group and other permissions +# u-x Clear the 'x' bit in the user permissions (leaves rw as-is) # go+u Copy the user permissions to group and other -# ugo+X Set the 'x' bit for directories in user, group, and other $nchan = $argv[$argc-1] == 'nchan'; // console or nchan output if ($nchan) unset($argv[$argc-1]); // remove nchan parameter @@ -45,10 +44,13 @@ function process($path) { $owner = $argv[2] ?? 'nobody'; $group = $argv[3] ?? 'users'; if (is_dir($path) && preg_match('/^\/mnt\/.+/',$path)) { - write("Processing: $path\n", "... chmod -R u-x,go-rwx,go+u,ugo+X $path\n"); - exec("chmod -R u-x,go-rwx,go+u,ugo+X ".escapeshellarg($path)); - write("... chown -R $owner:$group $path\n"); + write("Processing: $path\n"); + write("... chown -R $owner:$group\n"); exec("chown -R $owner:$group ".escapeshellarg($path)); + write("... chmod -R go-rwx,u-x,go+u\n"); + exec("chmod -R go-rwx,u-x,go+u ".escapeshellarg($path)); + write("... find -type d -exec chmod 777 {} \\;\n"); + exec("find ".escapeshellarg($path)." -type d -exec chmod 777 {} \\;"); write("... sync\n"); exec("sync"); write("\n"); From 8f656e87b1c19f2adcbf10ca530721873e8745f6 Mon Sep 17 00:00:00 2001 From: Tom Mortensen Date: Mon, 23 Sep 2024 10:57:13 -0700 Subject: [PATCH 028/174] establish sensible zfs pool defaults --- emhttp/plugins/dynamix/DeviceInfo.page | 124 +++++++++++++---------- emhttp/plugins/dynamix/nchan/device_list | 9 +- 2 files changed, 73 insertions(+), 60 deletions(-) diff --git a/emhttp/plugins/dynamix/DeviceInfo.page b/emhttp/plugins/dynamix/DeviceInfo.page index 92cd59bd0..b91674e5e 100755 --- a/emhttp/plugins/dynamix/DeviceInfo.page +++ b/emhttp/plugins/dynamix/DeviceInfo.page @@ -17,7 +17,6 @@ Tag="hdd-o" 0 ? $sheets[$i-1] : $sheets[$end]; $next = $i<$end ? $sheets[$i+1] : $sheets[0]; $textErase = isPool($name) ? _('This will ERASE content of ALL devices in the pool') : _('This will ERASE ALL device content'); $textDelete = _('This will unassign all devices from the pool but will NOT modify any device contents'); -$fsTypeImmutable = !(_var($var,'fsState')=='Stopped' && (empty(_var($disk,'uuid')) || _var($disk,'slots',1)==1)); function disabled_if($condition) { if ($condition !== false) echo ' disabled'; @@ -200,7 +214,7 @@ function prepareZFS(form) { } -function selectDiskFsWidth(slots) { +function setDiskFsWidth(slots) { $('#diskFsWidth').empty(); $('#diskFsWidth').append($('