From 801cc5600469f2cab1a51b97237c469b5a3d01b0 Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Mon, 28 Oct 2024 11:50:43 +0900 Subject: [PATCH] Start port of zed zed -d path/to/zed.d -p path/to/pid.txt -s path/to/zed.state -f Add simple zedlet and support functions Add all-debug.ps1 example, which uses zed-function.ps1 to post Notification on events. More work needed, in particular to make scripts run in the background rather than being waited upon. Signed-off-by: Jorgen Lundman --- cmd/CMakeLists.txt | 1 + cmd/zed/CMakeLists.txt | 35 ++ cmd/zed/agents/fmd_api.c | 10 +- cmd/zed/os/windows/resource.h | 15 + cmd/zed/os/windows/resource.rc | 110 ++++ cmd/zed/os/windows/zed.d/all-debug.ps1 | 30 + cmd/zed/os/windows/zed.d/zed-functions.ps1 | 107 ++++ cmd/zed/os/windows/zed.d/zed.rc | 199 +++++++ cmd/zed/os/windows/zed_exec.c | 512 ++++++++++++++++++ cmd/zed/zed_conf.c | 2 + cmd/zed/zed_log.c | 8 +- .../windows/Inno.Setup/ZFSInstall-debug.iss | 3 + include/os/windows/spl/sys/uio.h | 3 +- include/os/windows/zfs/zfs_config.h | 7 +- include/sys/sysevent/dev.h | 2 +- lib/libspl/include/os/windows/fcntl.h | 23 + lib/libspl/include/os/windows/inttypes.h | 38 ++ lib/libspl/include/os/windows/paths.h | 20 + lib/libspl/include/os/windows/signal.h | 5 + lib/libspl/include/os/windows/sys/uio.h | 3 + lib/libspl/include/os/windows/syslog.h | 78 +++ lib/libspl/include/os/windows/unistd.h | 5 +- lib/libspl/include/os/windows/wosix.h | 2 + lib/libspl/os/windows/posix.c | 42 +- 24 files changed, 1249 insertions(+), 11 deletions(-) create mode 100644 cmd/zed/CMakeLists.txt create mode 100644 cmd/zed/os/windows/resource.h create mode 100644 cmd/zed/os/windows/resource.rc create mode 100644 cmd/zed/os/windows/zed.d/all-debug.ps1 create mode 100644 cmd/zed/os/windows/zed.d/zed-functions.ps1 create mode 100644 cmd/zed/os/windows/zed.d/zed.rc create mode 100644 cmd/zed/os/windows/zed_exec.c create mode 100644 lib/libspl/include/os/windows/inttypes.h create mode 100644 lib/libspl/include/os/windows/paths.h create mode 100644 lib/libspl/include/os/windows/syslog.h diff --git a/cmd/CMakeLists.txt b/cmd/CMakeLists.txt index 813522b16478..8ce472d663c2 100644 --- a/cmd/CMakeLists.txt +++ b/cmd/CMakeLists.txt @@ -12,3 +12,4 @@ add_subdirectory(os/windows/kstat) add_subdirectory(os/windows/zfsinstaller) add_subdirectory(raidz_test) add_subdirectory(zinject) +add_subdirectory(zed) diff --git a/cmd/zed/CMakeLists.txt b/cmd/zed/CMakeLists.txt new file mode 100644 index 000000000000..39d883ad020b --- /dev/null +++ b/cmd/zed/CMakeLists.txt @@ -0,0 +1,35 @@ + +use_clang() + +um_add_executable(zed + zed.c + zed_conf.c + zed_disk_event.c + zed_event.c + zed_file.c + zed_log.c + zed_strings.c + agents/fmd_api.c + agents/fmd_serd.c + agents/zfs_agents.c + agents/zfs_diagnosis.c + agents/zfs_mod.c + agents/zfs_retire.c + os/windows/zed_exec.c + os/windows/resource.rc +) +target_link_libraries(zed PRIVATE +# libnvpair +# libuutil + libzfs +# libzfs_core + libzpool +) + +target_include_directories(zed PRIVATE "${CMAKE_SOURCE_DIR}/cmd/zed" "${CMAKE_SOURCE_DIR}/include") + +install(TARGETS zed RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +install(FILES $ + DESTINATION "${CMAKE_INSTALL_BINDIR}" + OPTIONAL +) diff --git a/cmd/zed/agents/fmd_api.c b/cmd/zed/agents/fmd_api.c index fe43e2ab971e..394e5f3eef47 100644 --- a/cmd/zed/agents/fmd_api.c +++ b/cmd/zed/agents/fmd_api.c @@ -564,7 +564,7 @@ fmd_serd_gc(fmd_hdl_t *hdl) } /* FMD Timers */ - +#if 0 static void _timer_notify(union sigval sv) { @@ -584,7 +584,7 @@ _timer_notify(union sigval sv) if (ops->fmdo_timeout != NULL) ops->fmdo_timeout(hdl, ftp, ftp->ft_arg); } - +#endif /* * Install a new timer which will fire at least delta nanoseconds after the * current time. After the timeout has expired, the module's fmdo_timeout @@ -608,9 +608,9 @@ fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) its.it_interval.tv_nsec = its.it_value.tv_nsec; sev.sigev_notify = SIGEV_THREAD; - sev.sigev_notify_function = _timer_notify; - sev.sigev_notify_attributes = NULL; - sev.sigev_value.sival_ptr = ftp; +// sev.sigev_notify_function = _timer_notify; +// sev.sigev_notify_attributes = NULL; +// sev.sigev_value.sival_ptr = ftp; sev.sigev_signo = 0; timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid); diff --git a/cmd/zed/os/windows/resource.h b/cmd/zed/os/windows/resource.h new file mode 100644 index 000000000000..8a09cc650089 --- /dev/null +++ b/cmd/zed/os/windows/resource.h @@ -0,0 +1,15 @@ +// {{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/cmd/zed/os/windows/resource.rc b/cmd/zed/os/windows/resource.rc new file mode 100644 index 000000000000..7d3a6879ae23 --- /dev/null +++ b/cmd/zed/os/windows/resource.rc @@ -0,0 +1,110 @@ +// Microsoft Visual C++ generated resource script. +// +#include +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (India) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENN) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_INDIA +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "400904b0" + BEGIN + VALUE "CompanyName", "TODO: " + VALUE "FileDescription", "zed.exe" + VALUE "FileVersion", "1.0.0.1" + VALUE "LegalCopyright", "Copyright (C) 2021" + VALUE "OriginalFilename", "resource.rc" + VALUE "ProductName", "zed.exe" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x4009, 1200 + END +END + +#endif // English (India) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/cmd/zed/os/windows/zed.d/all-debug.ps1 b/cmd/zed/os/windows/zed.d/all-debug.ps1 new file mode 100644 index 000000000000..e0045c033fec --- /dev/null +++ b/cmd/zed/os/windows/zed.d/all-debug.ps1 @@ -0,0 +1,30 @@ +#!/bin/powershell +# shellcheck disable=SC2154 +# +# Log all environment variables to ZED_DEBUG_LOG. +# +# This can be a useful aid when developing/debugging ZEDLETs since it shows the +# environment variables defined for each zevent. + +if (Test-Path "$env:ZED_ZEDLET_DIR\zed.rc") { + . "$env:ZED_ZEDLET_DIR\zed.rc" +} +if (Test-Path "$env:ZED_ZEDLET_DIR\zed-functions.ps1") { + . "$env:ZED_ZEDLET_DIR\zed-functions.ps1" +} + +# +# all-debug.ps1 +# + +Write-Host "all-debug.ps1 is running" + +$envVar = $env:ZED_ZEDLET_DIR +if ($envVar) { + Write-Host "ZED_ZEDLET_DIR is set to: $envVar" +} else { + Write-Host "ZED_ZEDLET_DIR is not set." +} + +Show-ToastNotification -Title "POOL: $env:ZEVENT_POOL" -Message "Event $env:ZEVENT_SUBCLASS has occurred." + diff --git a/cmd/zed/os/windows/zed.d/zed-functions.ps1 b/cmd/zed/os/windows/zed.d/zed-functions.ps1 new file mode 100644 index 000000000000..e040dcbb3b80 --- /dev/null +++ b/cmd/zed/os/windows/zed.d/zed-functions.ps1 @@ -0,0 +1,107 @@ +# zed-functions.ps1 +# +# 2024 Jorgen Lundman +# + +# This one doesn't need any extra PS modules, but is +# ugly. +function Show-PlainToastNotification { + param ( + [string]$Title = "ZED Notification", + [string]$Message = "Default message" + ) + + # Load the required assemblies + Add-Type -AssemblyName System.Windows.Forms + Add-Type -AssemblyName System.Drawing + + # Create a form to act as a notification + $form = New-Object System.Windows.Forms.Form + $form.StartPosition = 'Manual' + $form.Location = New-Object System.Drawing.Point(0, 0) + $form.Size = New-Object System.Drawing.Size(300, 100) + $form.FormBorderStyle = 'None' + $form.BackColor = [System.Drawing.Color]::White + $form.TopMost = $true + $form.ShowInTaskbar = $false + $form.Opacity = 0.9 + + # Create a label for the title + $titleLabel = New-Object System.Windows.Forms.Label + $titleLabel.Text = $Title + $titleLabel.Font = New-Object System.Drawing.Font("Arial", 14, [System.Drawing.FontStyle]::Bold) + $titleLabel.AutoSize = $true + $titleLabel.Location = New-Object System.Drawing.Point(10, 10) + + # Create a label for the message + $messageLabel = New-Object System.Windows.Forms.Label + $messageLabel.Text = $Message + $messageLabel.AutoSize = $true + $messageLabel.Location = New-Object System.Drawing.Point(10, 40) + + # Add the labels to the form + $form.Controls.Add($titleLabel) + $form.Controls.Add($messageLabel) + + # Show the form + $form.Show() + + # Timer to close the notification after 5 seconds + $timer = New-Object System.Windows.Forms.Timer + $timer.Interval = 5000 # milliseconds + $timer.Add_Tick({ + $form.Close() + $timer.Stop() + }) + $timer.Start() + + # Run the form's message loop + [System.Windows.Forms.Application]::Run($form) +} + +# For real notifications to work, run in powershell (Admin) +# "Install-Module -Name BurntToast -Force -AllowClobber" +# Failing that, fall back to a regular MessageBox +function Show-ToastNotification { + param ( + [string]$Title = "Notification", + [string]$Message = "This is a test notification." + ) + + # Check if the BurntToast module is available + if (Get-Module -ListAvailable -Name BurntToast) { + try { + # Import the module + Import-Module BurntToast -ErrorAction Stop + + # Create a BurntToast notification + New-BurntToastNotification -Text $Title, $Message + } + catch { + # If there's an error, fall back to a basic notification + Write-Host "BurntToast failed to create a notification: $_" + Show-MessageBox "$Message" "$Title" + } + } + else { + # Fallback if BurntToast is not installed + Write-Host "BurntToast module is not installed. Falling back to basic notification." + Show-MessageBox "$Message" "$Title" + } +} + +# Function to show a message box +function Show-MessageBox { + param ( + [string]$Message, + [string]$Title + ) + + # Load the necessary assembly + Add-Type -AssemblyName System.Windows.Forms + + # Display the message box + [System.Windows.Forms.MessageBox]::Show($Message, $Title) +} + + diff --git a/cmd/zed/os/windows/zed.d/zed.rc b/cmd/zed/os/windows/zed.d/zed.rc new file mode 100644 index 000000000000..c03409504cf7 --- /dev/null +++ b/cmd/zed/os/windows/zed.d/zed.rc @@ -0,0 +1,199 @@ +## +# zed.rc – ZEDLET configuration. +## +# shellcheck disable=SC2034 + +## +# Absolute path to the debug output file. +# +#$env:ZED_DEBUG_LOG="/tmp/zed.debug.log" + +## +# Email address of the zpool administrator for receipt of notifications; +# multiple addresses can be specified if they are delimited by whitespace. +# Email will only be sent if ZED_EMAIL_ADDR is defined. +# Enabled by default; comment to disable. +# +$env:ZED_EMAIL_ADDR="root" + +## +# Name or path of executable responsible for sending notifications via email; +# the mail program must be capable of reading a message body from stdin. +# Email will only be sent if ZED_EMAIL_ADDR is defined. +# +#$env:ZED_EMAIL_PROG="mail" + +## +# Command-line options for ZED_EMAIL_PROG. +# The string @ADDRESS@ will be replaced with the recipient email address(es). +# The string @SUBJECT@ will be replaced with the notification subject; +# this should be protected with quotes to prevent word-splitting. +# Email will only be sent if ZED_EMAIL_ADDR is defined. +# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification +# +#$env:ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@" + +## +# Default directory for zed lock files. +# +#$env:ZED_LOCKDIR="/var/lock" + +## +# Minimum number of seconds between notifications for a similar event. +# +#$env:ZED_NOTIFY_INTERVAL_SECS=3600 + +## +# Notification verbosity. +# If set to 0, suppress notification if the pool is healthy. +# If set to 1, send notification regardless of pool health. +# +#$env:ZED_NOTIFY_VERBOSE=0 + +## +# Send notifications for 'ereport.fs.zfs.data' events. +# Disabled by default, any non-empty value will enable the feature. +# +#$env:ZED_NOTIFY_DATA= + +## +# Pushbullet access token. +# This grants full access to your account -- protect it accordingly! +# +# +# Disabled by default; uncomment to enable. +# +#$env:ZED_PUSHBULLET_ACCESS_TOKEN="" + +## +# Pushbullet channel tag for push notification feeds that can be subscribed to. +# +# If not defined, push notifications will instead be sent to all devices +# associated with the account specified by the access token. +# Disabled by default; uncomment to enable. +# +#$env:ZED_PUSHBULLET_CHANNEL_TAG="" + +## +# Slack Webhook URL. +# This allows posting to the given channel and includes an access token. +# +# Disabled by default; uncomment to enable. +# +#$env:ZED_SLACK_WEBHOOK_URL="" + +## +# Pushover token. +# This defines the application from which the notification will be sent. +# +# Disabled by default; uncomment to enable. +# ZED_PUSHOVER_USER, below, must also be configured. +# +#$env:ZED_PUSHOVER_TOKEN="" + +## +# Pushover user key. +# This defines which user or group will receive Pushover notifications. +# +# Disabled by default; uncomment to enable. +# ZED_PUSHOVER_TOKEN, above, must also be configured. +#$env:ZED_PUSHOVER_USER="" + +## +# Default directory for zed state files. +# +#$env:ED_RUNDIR="/var/run" + +## +# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED. This works for +# device mapper and multipath devices as well. This works with JBOD enclosures +# and NVMe PCI drives (assuming they're supported by Linux in sysfs). +# +$env:ZED_USE_ENCLOSURE_LEDS=1 + +## +# Run a scrub after every resilver +# Disabled by default, 1 to enable and 0 to disable. +#$env:ZED_SCRUB_AFTER_RESILVER=0 + +## +# The syslog priority (e.g., specified as a "facility.level" pair). +# +#$env:ZED_SYSLOG_PRIORITY="daemon.notice" + +## +# The syslog tag for marking zed events. +# +#$env:ZED_SYSLOG_TAG="zed" + +## +# Which set of event subclasses to log +# By default, events from all subclasses are logged. +# If ZED_SYSLOG_SUBCLASS_INCLUDE is set, only subclasses +# matching the pattern are logged. Use the pipe symbol (|) +# or shell wildcards (*, ?) to match multiple subclasses. +# Otherwise, if ZED_SYSLOG_SUBCLASS_EXCLUDE is set, the +# matching subclasses are excluded from logging. +#$env:ED_SYSLOG_SUBCLASS_INCLUDE="checksum|scrub_*|vdev.*" +$env:ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event" + +## +# Use GUIDs instead of names when logging pool and vdevs +# Disabled by default, 1 to enable and 0 to disable. +#$env:ZED_SYSLOG_DISPLAY_GUIDS=1 + +## +# Power off the drive's slot in the enclosure if it becomes FAULTED. This can +# help silence misbehaving drives. This assumes your drive enclosure fully +# supports slot power control via sysfs. +#$env:ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT=1 + +## +# Power off the drive's slot in the enclosure if there is a hung I/O which +# exceeds the deadman timeout. This can help prevent a single misbehaving +# drive from rendering a redundant pool unavailable. This assumes your drive +# enclosure fully supports slot power control via sysfs. +#$env:ZED_POWER_OFF_ENCLOSURE_SLOT_ON_DEADMAN=1 + +## +# Ntfy topic +# This defines which topic will receive the ntfy notification. +# +# Disabled by default; uncomment to enable. +#$env:ZED_NTFY_TOPIC="" + +## +# Ntfy access token (optional for public topics) +# This defines an access token which can be used +# to allow you to authenticate when sending to topics +# +# Disabled by default; uncomment to enable. +#$env:ZED_NTFY_ACCESS_TOKEN="" + +## +# Ntfy Service URL +# This defines which service the ntfy call will be directed toward +# +# https://ntfy.sh by default; uncomment to enable an alternative service url. +#$env : ZED_NTFY_URL="https://ntfy.sh" + +## +# Gotify server URL +# This defines a URL that the Gotify call will be directed toward. +# +# Disabled by default; uncomment to enable. +#$env:ZED_GOTIFY_URL="" + +## +# Gotify application token +# This defines a Gotify application token which a message is associated with. +# This token is generated when an application is created on the Gotify server. +# Disabled by default; uncomment to enable. +#$env:ZED_GOTIFY_APPTOKEN="" + +## +# Gotify priority (optional) +# If defined, this overrides the default priority of the +# Gotify application associated with ZED_GOTIFY_APPTOKEN. +# Value is an integer 0 and up. +#$env:ZED_GOTIFY_PRIORITY="" diff --git a/cmd/zed/os/windows/zed_exec.c b/cmd/zed/os/windows/zed_exec.c new file mode 100644 index 000000000000..d76ace1e6fa8 --- /dev/null +++ b/cmd/zed/os/windows/zed_exec.c @@ -0,0 +1,512 @@ +/* + * This file is part of the ZFS Event Daemon (ZED). + * + * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). + * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. + * Refer to the OpenZFS git commit log for authoritative copyright attribution. + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License Version 1.0 (CDDL-1.0). + * You can obtain a copy of the license from the top-level file + * "OPENSOLARIS.LICENSE" or at . + * You may not use this file except in compliance with the license. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zed_exec.h" +#include "zed_log.h" +#include "zed_strings.h" + +#define ZEVENT_FILENO 3 + +struct launched_process_node { + avl_node_t node; + pid_t pid; + uint64_t eid; + char *name; +}; + +static int +_launched_process_node_compare(const void *x1, const void *x2) +{ + pid_t p1; + pid_t p2; + + assert(x1 != NULL); + assert(x2 != NULL); + + p1 = ((const struct launched_process_node *) x1)->pid; + p2 = ((const struct launched_process_node *) x2)->pid; + + if (p1 < p2) + return (-1); + else if (p1 == p2) + return (0); + else + return (1); +} + +static pthread_t _reap_children_tid = (pthread_t)-1; +static volatile boolean_t _reap_children_stop; +static avl_tree_t _launched_processes; +static pthread_mutex_t _launched_processes_lock = PTHREAD_MUTEX_INITIALIZER; +static int16_t _launched_processes_limit; + +/* + * Create an environment string array for passing to execve() using the + * NAME=VALUE strings in container [zsp]. + * Return a newly-allocated environment, or NULL on error. + */ +static char ** +_zed_exec_create_env(zed_strings_t *zsp) +{ + int num_ptrs; + int buflen; + char *buf; + char **pp; + char *p; + const char *q; + int i; + int len; + + num_ptrs = zed_strings_count(zsp) + 1; + buflen = num_ptrs * sizeof (char *); + for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp)) + buflen += strlen(q) + 1; + + buf = calloc(1, buflen); + if (!buf) + return (NULL); + + pp = (char **)buf; + p = buf + (num_ptrs * sizeof (char *)); + i = 0; + for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp)) { + pp[i] = p; + len = strlen(q) + 1; + memcpy(p, q, len); + p += len; + i++; + } + pp[i] = NULL; + assert(buf + buflen == p); + return ((char **)buf); +} + +// Compare function for qsort +int +compareEnvStrings(const void *a, const void *b) +{ + return (strcmp(*(const char **)a, *(const char **)b)); +} + +char * +env_get_merge_sort(char *unix[]) +{ + // How many Unix entries? + int unix_num = 0; + int unix_strlen = 0; + + for (unix_num = 0; unix[unix_num]; unix_num++) + unix_strlen += strlen(unix[unix_num]) + 1; + + // Get ENV (Windows style) + LPCH envStrings = GetEnvironmentStrings(); + if (!envStrings) + return (NULL); + + // How many Windows keys=value + int win_num = 0; + char *envPtr = envStrings; + + // Count the number of environment variables + while (*envPtr) { + win_num++; + envPtr += strlen(envPtr) + 1; // Move to the next variable + } + int win_strlen = envPtr - envStrings; + + // Get me an array to hold all key=value + char **envArray = (char **)malloc((unix_num + win_num + 1) * + sizeof (char *)); // +1 for NULL + + // Copy over Unix pointers + int index = 0; + + for (int i = 0; i < unix_num; i++) + envArray[index++] = unix[i]; + + // Build Win entries + envPtr = envStrings; + + // Count the number of environment variables + while (*envPtr) { + envArray[index++] = envPtr; + envPtr += strlen(envPtr) + 1; // Move to the next variable + } + envArray[index] = NULL; // No index++, dont sort NULL + + // Sort the array of pointers + qsort(envArray, index, sizeof (char *), compareEnvStrings); + + // Allocate output string + char *output = malloc(unix_strlen + win_strlen + 1); + if (!output) { + FreeEnvironmentStrings(envStrings); + return (NULL); + } + int output_index = 0; + + for (int i = 0; i < index; i++) { + int len; + len = strlen(envArray[i]); + memcpy(&output[output_index], + envArray[i], + len); + output_index += len; + output[output_index++] = 0; + } + output[output_index++] = 0; + + free(envArray); + FreeEnvironmentStrings(envStrings); + return (output); +} + +void +launch_process(const char *path, const char *prog, char *env[]) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&si, sizeof (si)); + si.cb = sizeof (si); + ZeroMemory(&pi, sizeof (pi)); + char cmd[MAX_PATH]; + char *envBlock; + + fprintf(stderr, "Launching process '%s' in '%s'\r\n", prog, path); + fflush(stderr); + + snprintf(cmd, sizeof (cmd), + "powershell.exe -ExecutionPolicy Bypass -File %s", path); + /* + * ENV: + * Unix is an array of strings, will last pointer NULL. + * Win is a multi-string, with double 0 character at end. + * "HOME=/User/lundman\0SHELL=/bin/bash\0\0". + * We also need to copy *this* process ENV for CWDs, AND + * the env has to be *sorted* or it won't work. + */ + + char *sortedMergedEnv = env_get_merge_sort(env); + + if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, sortedMergedEnv, + NULL, &si, &pi)) { + zed_log_msg(LOG_WARNING, + "Failed to create process \"%s\": %d %s", + prog, GetLastError(), strerror(GetLastError())); + if (sortedMergedEnv) + free(sortedMergedEnv); + return; + } + if (sortedMergedEnv) + free(sortedMergedEnv); + + // While we debug + WaitForSingleObject(pi.hProcess, INFINITE); + + // Close process and thread handles + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +/* + * Fork a child process to handle event [eid]. The program [prog] + * in directory [dir] is executed with the environment [env]. + * + * The file descriptor [zfd] is the zevent_fd used to track the + * current cursor location within the zevent nvlist. + */ +static void +_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog, + char *env[], int zfd, boolean_t in_foreground) +{ + char path[PATH_MAX]; + int n; + pid_t pid; + int fd; + struct launched_process_node *node; + sigset_t mask; + struct timespec launch_timeout = + { .tv_sec = 0, .tv_nsec = 200 * 1000 * 1000, }; + + assert(dir != NULL); + assert(prog != NULL); + assert(env != NULL); + assert(zfd >= 0); + + while (__atomic_load_n(&_launched_processes_limit, + __ATOMIC_SEQ_CST) <= 0) + (void) nanosleep(&launch_timeout, NULL); + + n = snprintf(path, sizeof (path), "%s/%s", dir, prog); + if ((n < 0) || (n >= sizeof (path))) { + zed_log_msg(LOG_WARNING, + "Failed to fork \"%s\" for eid=%llu: %s", + prog, eid, strerror(ENAMETOOLONG)); + return; + } + (void) pthread_mutex_lock(&_launched_processes_lock); + pid = fork(); + if (pid < 0) { + (void) pthread_mutex_unlock(&_launched_processes_lock); + zed_log_msg(LOG_WARNING, + "Failed to fork \"%s\" for eid=%llu: %s", + prog, eid, strerror(errno)); + return; + } else if (pid == 0) { + (void) sigemptyset(&mask); + (void) sigprocmask(SIG_SETMASK, &mask, NULL); + + (void) umask(022); + if (in_foreground && /* we're already devnulled if daemonised */ + (fd = open("/dev/null", O_RDWR | O_CLOEXEC)) != -1) { + (void) dup2(fd, STDIN_FILENO); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + } + (void) dup2(zfd, ZEVENT_FILENO); + execle(path, prog, NULL, env); + _exit(127); + } + +#ifdef _WIN32 + /* + * fork() always returns 1 (parent) above, so here we can spawn process + */ + launch_process(path, prog, env); +#endif + + /* parent process */ + + node = calloc(1, sizeof (*node)); + if (node) { + node->pid = pid; + node->eid = eid; + node->name = strdup(prog); + if (node->name == NULL) { + perror("strdup"); + exit(EXIT_FAILURE); + } + + avl_add(&_launched_processes, node); + } + (void) pthread_mutex_unlock(&_launched_processes_lock); + + __atomic_sub_fetch(&_launched_processes_limit, 1, __ATOMIC_SEQ_CST); + zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d", + prog, eid, pid); +} + +static void +_nop(int sig) +{ + (void) sig; +} + +static void * +_reap_children(void *arg) +{ + (void) arg; +#if 0 + struct launched_process_node node, *pnode; + pid_t pid; + int status; + struct rusage usage; + struct sigaction sa = {}; + + (void) sigfillset(&sa.sa_mask); + (void) sigdelset(&sa.sa_mask, SIGCHLD); + (void) pthread_sigmask(SIG_SETMASK, &sa.sa_mask, NULL); + + (void) sigemptyset(&sa.sa_mask); + sa.sa_handler = _nop; + sa.sa_flags = SA_NOCLDSTOP; + (void) sigaction(SIGCHLD, &sa, NULL); + + for (_reap_children_stop = B_FALSE; !_reap_children_stop; ) { + (void) pthread_mutex_lock(&_launched_processes_lock); + pid = wait4(0, &status, WNOHANG, &usage); + + if (pid == 0 || pid == (pid_t)-1) { + (void) pthread_mutex_unlock(&_launched_processes_lock); + if (pid == 0 || errno == ECHILD) + pause(); + else if (errno != EINTR) + zed_log_msg(LOG_WARNING, + "Failed to wait for children: %s", + strerror(errno)); + } else { + memset(&node, 0, sizeof (node)); + node.pid = pid; + pnode = avl_find(&_launched_processes, &node, NULL); + if (pnode) { + memcpy(&node, pnode, sizeof (node)); + + avl_remove(&_launched_processes, pnode); + free(pnode); + } + (void) pthread_mutex_unlock(&_launched_processes_lock); + __atomic_add_fetch(&_launched_processes_limit, 1, + __ATOMIC_SEQ_CST); + + usage.ru_utime.tv_sec += usage.ru_stime.tv_sec; + usage.ru_utime.tv_usec += usage.ru_stime.tv_usec; + usage.ru_utime.tv_sec += + usage.ru_utime.tv_usec / (1000 * 1000); + usage.ru_utime.tv_usec %= 1000 * 1000; + + if (WIFEXITED(status)) { + zed_log_msg(LOG_INFO, + "Finished \"%s\" eid=%llu pid=%d " + "time=%llu.%06us exit=%d", + node.name, node.eid, pid, + (unsigned long long) usage.ru_utime.tv_sec, + (unsigned int) usage.ru_utime.tv_usec, + WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + zed_log_msg(LOG_INFO, + "Finished \"%s\" eid=%llu pid=%d " + "time=%llu.%06us sig=%d/%s", + node.name, node.eid, pid, + (unsigned long long) usage.ru_utime.tv_sec, + (unsigned int) usage.ru_utime.tv_usec, + WTERMSIG(status), + strsignal(WTERMSIG(status))); + } else { + zed_log_msg(LOG_INFO, + "Finished \"%s\" eid=%llu pid=%d " + "time=%llu.%06us status=0x%X", + node.name, node.eid, pid, + (unsigned long long) usage.ru_utime.tv_sec, + (unsigned int) usage.ru_utime.tv_usec, + (unsigned int) status); + } + + free(node.name); + } + } +#endif + return (NULL); +} + +void +zed_exec_fini(void) +{ + struct launched_process_node *node; + void *ck = NULL; + + if (_reap_children_tid == (pthread_t)-1) + return; + + _reap_children_stop = B_TRUE; + (void) pthread_kill(_reap_children_tid, SIGCHLD); + (void) pthread_join(_reap_children_tid, NULL); + + while ((node = avl_destroy_nodes(&_launched_processes, &ck)) != NULL) { + free(node->name); + free(node); + } + avl_destroy(&_launched_processes); + + (void) pthread_mutex_destroy(&_launched_processes_lock); + (void) pthread_mutex_init(&_launched_processes_lock, NULL); + + _reap_children_tid = (pthread_t)-1; +} + +/* + * Process the event [eid] by synchronously invoking all zedlets with a + * matching class prefix. + * + * Each executable in [zcp->zedlets] from the directory [zcp->zedlet_dir] + * is matched against the event's [class], [subclass], and the "all" class + * (which matches all events). + * Every zedlet with a matching class prefix is invoked. + * The NAME=VALUE strings in [envs] will be passed to the zedlet as + * environment variables. + * + * The file descriptor [zcp->zevent_fd] is the zevent_fd used to track the + * current cursor location within the zevent nvlist. + * + * Return 0 on success, -1 on error. + */ +int +zed_exec_process(uint64_t eid, const char *class, const char *subclass, + struct zed_conf *zcp, zed_strings_t *envs) +{ + const char *class_strings[4]; + const char *allclass = "all"; + const char **csp; + const char *z; + char **e; + int n; + + if (!zcp->zedlet_dir || !zcp->zedlets || !envs || zcp->zevent_fd < 0) + return (-1); + + if (_reap_children_tid == (pthread_t)-1) { + _launched_processes_limit = zcp->max_jobs; + + if (pthread_create(&_reap_children_tid, NULL, + _reap_children, NULL) != 0) + return (-1); + pthread_setname_np(_reap_children_tid, "reap ZEDLETs"); + + avl_create(&_launched_processes, _launched_process_node_compare, + sizeof (struct launched_process_node), + offsetof(struct launched_process_node, node)); + } + + csp = class_strings; + + if (class) + *csp++ = class; + + if (subclass) + *csp++ = subclass; + + if (allclass) + *csp++ = allclass; + + *csp = NULL; + + e = _zed_exec_create_env(envs); + + for (z = zed_strings_first(zcp->zedlets); z; + z = zed_strings_next(zcp->zedlets)) { + for (csp = class_strings; *csp; csp++) { + n = strlen(*csp); + if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n])) + _zed_exec_fork_child(eid, zcp->zedlet_dir, + z, e, zcp->zevent_fd, zcp->do_foreground); + } + } + free(e); + return (0); +} diff --git a/cmd/zed/zed_conf.c b/cmd/zed/zed_conf.c index 29de27c77c34..42d8c7f2d645 100644 --- a/cmd/zed/zed_conf.c +++ b/cmd/zed/zed_conf.c @@ -386,12 +386,14 @@ zed_conf_scan_dir(struct zed_conf *zcp) direntp->d_name); continue; } +#ifndef _WIN32 if (!(st.st_mode & S_IXUSR)) { zed_log_msg(LOG_INFO, "Ignoring \"%s\": not executable by user", direntp->d_name); continue; } +#endif if ((st.st_mode & S_IWGRP) && !zcp->do_force) { zed_log_msg(LOG_NOTICE, "Ignoring \"%s\": writable by group", diff --git a/cmd/zed/zed_log.c b/cmd/zed/zed_log.c index 0c4ab6f47db7..47341d72f215 100644 --- a/cmd/zed/zed_log.c +++ b/cmd/zed/zed_log.c @@ -218,9 +218,15 @@ _zed_log_aux(int priority, const char *fmt, va_list vargs) if (_ctx.do_syslog) syslog(priority, "%s", buf); - +#ifdef _WIN32 + if (_ctx.do_stderr && (priority <= _ctx.priority)) { + fprintf(stderr, "%s\r\n", buf); + fflush(stderr); + } +#else if (_ctx.do_stderr && (priority <= _ctx.priority)) fprintf(stderr, "%s\n", buf); +#endif } /* diff --git a/contrib/windows/Inno.Setup/ZFSInstall-debug.iss b/contrib/windows/Inno.Setup/ZFSInstall-debug.iss index 4fde3c423b25..d28245d0278a 100644 --- a/contrib/windows/Inno.Setup/ZFSInstall-debug.iss +++ b/contrib/windows/Inno.Setup/ZFSInstall-debug.iss @@ -89,6 +89,7 @@ Source: "{#Root}\out\build\x64-Debug\cmd\os\windows/zfsinstaller/zfsinstaller.ex Source: "{#Root}\out\build\x64-Debug\cmd\zpool\zpool.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\zfs\zfs.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\zdb\zdb.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "{#Root}\out\build\x64-Debug\cmd\zed\zed.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\zstream\zstreamdump.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\raidz_test\raidz_test.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\module\os\windows\driver\OpenZFS.sys"; DestDir: "{app}"; Flags: ignoreversion @@ -102,6 +103,7 @@ Source: "{#Root}\out\build\x64-Debug\cmd\zstream\*.pdb"; DestDir: "{app}\symbols Source: "{#Root}\out\build\x64-Debug\cmd\zpool\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\zfs\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\zdb\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion +Source: "{#Root}\out\build\x64-Debug\cmd\zed\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\raidz_test\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\os\windows\zfsinstaller\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion Source: "{#Root}\out\build\x64-Debug\cmd\os\windows\kstat\*.pdb"; DestDir: "{app}\symbols"; Flags: ignoreversion @@ -110,6 +112,7 @@ Source: "{#Root}\contrib\windows\parsedump\*.*"; DestDir: "{app}"; Flags: ignore Source: "{#Root}\scripts\zfs_prepare_disk"; DestDir: "{app}"; Flags: ignoreversion Source: "{#Root}\cmd\zpool\compatibility.d\*"; DestDir: "{app}\compatibility.d"; Flags: ignoreversion Source: "{#Root}\cmd\zpool\zpool.d\*"; DestDir: "{app}\zpool.d"; Flags: ignoreversion +Source: "{#Root}\cmd\zed\os\windows\zed.d\*"; DestDir: "{app}\zed.d"; Flags: ignoreversion ; NOTE: Don't use "Flags: ignoreversion" on any shared system files diff --git a/include/os/windows/spl/sys/uio.h b/include/os/windows/spl/sys/uio.h index 5f00902da98a..4172755cb0b0 100644 --- a/include/os/windows/spl/sys/uio.h +++ b/include/os/windows/spl/sys/uio.h @@ -185,7 +185,8 @@ extern int zfs_uio_prefaultpages(ssize_t, zfs_uio_t *); #define zfs_uio_fault_disable(uio, set) #define zfs_uio_fault_move(p, n, rw, u) zfs_uiomove((p), (n), (rw), (u)) -static ssize_t writev(int fd, struct iovec *iov, unsigned iov_cnt); +extern ssize_t readv(int, const struct iovec *, int); +extern ssize_t writev(int fd, struct iovec *iov, unsigned iov_cnt); #ifdef __cplusplus } diff --git a/include/os/windows/zfs/zfs_config.h b/include/os/windows/zfs/zfs_config.h index 43458c522832..9478b0e13c3e 100644 --- a/include/os/windows/zfs/zfs_config.h +++ b/include/os/windows/zfs/zfs_config.h @@ -54,7 +54,7 @@ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mlockall' function. */ -#define HAVE_MLOCKALL 1 +/* #undef HAVE_MLOCKALL 1 */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 @@ -153,3 +153,8 @@ #define ZFS_META_ALIAS ZFS_META_GITREV #define ZFSEXECDIR "C:/Program Files/OpenZFS on Windows" + +#define RUNSTATEDIR ZFSEXECDIR "/zed" +#define _PATH_STDPATH "" +#define SBINDIR ZFSEXECDIR + diff --git a/include/sys/sysevent/dev.h b/include/sys/sysevent/dev.h index 0783d0073162..5700fe180dc1 100644 --- a/include/sys/sysevent/dev.h +++ b/include/sys/sysevent/dev.h @@ -239,7 +239,7 @@ extern "C" { #define DEV_INSTANCE "instance" #define DEV_PROP_PREFIX "prop-" -#ifdef __linux__ +#if defined(__linux__) || defined(_WIN32) #define DEV_IDENTIFIER "devid" #define DEV_PATH "path" #define DEV_IS_PART "is_slice" diff --git a/lib/libspl/include/os/windows/fcntl.h b/lib/libspl/include/os/windows/fcntl.h index b8dee281657f..f17ab4108bcc 100644 --- a/lib/libspl/include/os/windows/fcntl.h +++ b/lib/libspl/include/os/windows/fcntl.h @@ -45,6 +45,29 @@ */ #define AT_FDCWD -100 +/* regular version, for both small and large file compilation environment */ +typedef struct flock { + short l_type; + short l_whence; + unsigned long long l_start; + unsigned long long l_len; /* len == 0 means until end of file */ + int l_sysid; + unsigned int l_pid; + long l_pad[4]; /* reserve area */ +} flock_t; + +/* + * File segment locking types. + */ +#define F_RDLCK 01 /* Read lock */ +#define F_WRLCK 02 /* Write lock */ +#define F_UNLCK 03 /* Remove lock(s) */ +#define F_UNLKSYS 04 /* remove remote locks for a given system */ + +#define F_SETLK 6 /* Set file lock */ +#define F_SETLKW 7 /* Set file lock and wait */ +#define F_GETLK 14 /* Get file lock */ + extern int fcntl(int fildes, int cmd, /* arg */ ...); #endif /* _LIBSPL_SYS_FCNTL_H */ diff --git a/lib/libspl/include/os/windows/inttypes.h b/lib/libspl/include/os/windows/inttypes.h new file mode 100644 index 000000000000..209ee55090b5 --- /dev/null +++ b/lib/libspl/include/os/windows/inttypes.h @@ -0,0 +1,38 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _LIBSPL_INTTYPES_H +#define _LIBSPL_INTTYPES_H + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "lli" +#define PRId32 "i" +#define PRIu64 "llu" +#define PRIx64 "llx" +#define PRIi64 "lli" +#define PRId64 "lli" + +#define strtoimax strtoull + + +#endif /* SPL_INTTYPES_H */ diff --git a/lib/libspl/include/os/windows/paths.h b/lib/libspl/include/os/windows/paths.h new file mode 100644 index 000000000000..286589203255 --- /dev/null +++ b/lib/libspl/include/os/windows/paths.h @@ -0,0 +1,20 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ diff --git a/lib/libspl/include/os/windows/signal.h b/lib/libspl/include/os/windows/signal.h index 8bc15e3dd8c9..234a254307fd 100644 --- a/lib/libspl/include/os/windows/signal.h +++ b/lib/libspl/include/os/windows/signal.h @@ -35,7 +35,9 @@ #define SIGEV_SIGNAL 1 /* Generate a queued signal. */ #define SIGEV_THREAD 2 /* Call back from another pthread. */ +#define SIGHUP 1 #define SIGPIPE 13 +#define SIGCHLD 18 #define SIGUSR1 30 /* user defined signal 1 */ #define SIGUSR2 31 /* user defined signal 2 */ @@ -45,8 +47,11 @@ struct proc; // extern int // thread_issignal(struct proc *, thread_t, sigset_t); +#define SA_RESTART 0x00000004 #define SA_SIGINFO 0x00000008 +#define SIG_SETMASK 3 + typedef struct __siginfo { /* Windows version goes here */ void *si_addr; diff --git a/lib/libspl/include/os/windows/sys/uio.h b/lib/libspl/include/os/windows/sys/uio.h index 1d23a05880c7..7d38fc9971e8 100644 --- a/lib/libspl/include/os/windows/sys/uio.h +++ b/lib/libspl/include/os/windows/sys/uio.h @@ -49,4 +49,7 @@ typedef struct iovec iovec_t; #include_next +extern ssize_t readv(int, const struct iovec *, int); +extern ssize_t writev(int fd, struct iovec *iov, unsigned iov_cnt); + #endif /* _WINDOWS_SYS_UIO_H */ diff --git a/lib/libspl/include/os/windows/syslog.h b/lib/libspl/include/os/windows/syslog.h new file mode 100644 index 000000000000..1e230b93a7ab --- /dev/null +++ b/lib/libspl/include/os/windows/syslog.h @@ -0,0 +1,78 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _SPL_SYSLOG_H +#define _SPL_SYSLOG_H + +#include + +/* + * Facility codes + */ +#define LOG_KERN (0<<3) /* kernel messages */ +#define LOG_USER (1<<3) /* random user-level messages */ +#define LOG_MAIL (2<<3) /* mail system */ +#define LOG_DAEMON (3<<3) /* system daemons */ +#define LOG_AUTH (4<<3) /* security/authorization messages */ +#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +#define LOG_LPR (6<<3) /* line printer subsystem */ +#define LOG_NEWS (7<<3) /* netnews subsystem */ +#define LOG_UUCP (8<<3) /* uucp subsystem */ +#define LOG_ALTCRON (9<<3) /* BSD cron/at subsystem */ +#define LOG_AUTHPRIV (10<<3) /* BSD security/authorization messages */ +#define LOG_FTP (11<<3) /* file transfer subsystem */ +#define LOG_NTP (12<<3) /* network time subsystem */ +#define LOG_AUDIT (13<<3) /* audit subsystem */ +#define LOG_CONSOLE (14<<3) /* BSD console messages */ +#define LOG_CRON (15<<3) /* cron/at subsystem */ +#define LOG_LOCAL0 (16<<3) /* reserved for local use */ +#define LOG_LOCAL1 (17<<3) /* reserved for local use */ +#define LOG_LOCAL2 (18<<3) /* reserved for local use */ +#define LOG_LOCAL3 (19<<3) /* reserved for local use */ +#define LOG_LOCAL4 (20<<3) /* reserved for local use */ +#define LOG_LOCAL5 (21<<3) /* reserved for local use */ +#define LOG_LOCAL6 (22<<3) /* reserved for local use */ +#define LOG_LOCAL7 (23<<3) /* reserved for local use */ + +/* + * Priorities (these are ordered) + */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but signification condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +#define LOG_PID 0x01 /* log the pid with each message */ +// #define LOG_CONS 0x02 /* log on the console if errors in sending */ +// #define LOG_ODELAY 0x04 /* delay open until syslog() is called */ +#define LOG_NDELAY 0x08 /* don't delay open */ +// #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ + +void openlog(const char *, int, int); +// void syslog(int, const char *, ...); +// void closelog(void); +// int setlogmask(int); + +#endif diff --git a/lib/libspl/include/os/windows/unistd.h b/lib/libspl/include/os/windows/unistd.h index 4e96d0b5c3ad..414a09ba30f9 100644 --- a/lib/libspl/include/os/windows/unistd.h +++ b/lib/libspl/include/os/windows/unistd.h @@ -48,6 +48,7 @@ extern char *optarg; #include #include +#define _SC_OPEN_MAX 5 #define _SC_PAGESIZE 11 #define _SC_PAGE_SIZE _SC_PAGESIZE #define _SC_NPROCESSORS_ONLN 15 @@ -99,9 +100,11 @@ extern void closelog(void); extern int unmount(const char *dir, int flags); +extern pid_t setsid(void); + static inline pid_t fork(void) { - return (0); + return (1); } extern int mkostemps(char *templ, int suffixlen, DWORD flags); diff --git a/lib/libspl/include/os/windows/wosix.h b/lib/libspl/include/os/windows/wosix.h index d1d74c0c907f..432996e5dfc6 100644 --- a/lib/libspl/include/os/windows/wosix.h +++ b/lib/libspl/include/os/windows/wosix.h @@ -162,6 +162,8 @@ extern int wosix_access(const char *name, int mode); #define ftruncate wosix_ftruncate #undef socketpair #define socketpair wosix_socketpair +#undef dup2 +#define dup2 wosix_dup2 #undef fdopen #define fdopen wosix_fdopen #undef freopen diff --git a/lib/libspl/os/windows/posix.c b/lib/libspl/os/windows/posix.c index 6c1e25c52ebd..5b6508b3c72a 100644 --- a/lib/libspl/os/windows/posix.c +++ b/lib/libspl/os/windows/posix.c @@ -1011,6 +1011,12 @@ wosix_open(const char *inpath, int oflag, ...) path = otherpath; } + if (strncmp(path, "\\dev\\null", 9) == 0) { + snprintf(otherpath, MAXPATHLEN, "NUL:"); + path = otherpath; + } + + // Try to open verbatim, but if that fail, check if it is the // "#offset#length#name" style, and try again. We let it fail first // just in case someone names their file with a starting '#'. @@ -1232,6 +1238,35 @@ writev(int fd, struct iovec *iov, unsigned iov_cnt) return (ret); } +ssize_t +readv(int fd, const struct iovec *iov, int iov_cnt) +{ + unsigned int i = 0; + ssize_t ret = 0; + while (i < iov_cnt) { + ssize_t r = wosix_read(fd, iov[i].iov_base, iov[i].iov_len); + + if (r > 0) { + ret += r; + } else if (!r) { + break; + } else if (errno == EINTR) { + continue; + } else { + /* + * else it is some "other" error, + * only return if there was no data processed. + */ + if (ret == 0) { + ret = -1; + } + break; + } + +i++; + } + return (ret); +} + #define is_wprefix(s, prefix) \ (wcsncmp((s), (prefix), sizeof (prefix) / sizeof (WCHAR) - 1) == 0) @@ -1663,7 +1698,7 @@ wosix_socketpair(int domain, int type, int protocol, int sv[2]) int wosix_dup2(int fildes, int fildes2) { - return (-1); + return (0); } void * @@ -2041,3 +2076,8 @@ getgrnam_r(const char *name, struct group *grp, *result = NULL; return (0); } + +extern pid_t setsid(void) +{ + return (0); +}