- From df466334121c3c6e366145bcf3ffc5675cc2eb13 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 25 Aug 2025 18:28:03 +0200
- Subject: [PATCH 1/4] tests: winfsinfo1: Implement "getfilefssizeinformation"
- subcmd
- Implement "getfilefssizeinformation" subcmd to query
- |FileFsSizeInformation| volume information.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/winfsinfo1/winfsinfo.c | 57 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 57 insertions(+)
- diff --git a/tests/winfsinfo1/winfsinfo.c b/tests/winfsinfo1/winfsinfo.c
- index 5aa3041..b36fc6f 100644
- --- a/tests/winfsinfo1/winfsinfo.c
- +++ b/tests/winfsinfo1/winfsinfo.c
- @@ -382,6 +382,59 @@ int getfilefssectorsizeinformation(const char *progname, const char *filename)
- (void)printf(")\n");
- res = EXIT_SUCCESS;
- +done:
- + (void)CloseHandle(fileHandle);
- + return res;
- +}
- +
- +static
- +int getfilefssizeinformation(const char *progname, const char *filename)
- +{
- + int res = EXIT_FAILURE;
- +
- + HANDLE fileHandle = CreateFileA(filename,
- + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- + FILE_FLAG_BACKUP_SEMANTICS, NULL);
- + if (fileHandle == INVALID_HANDLE_VALUE) {
- + (void)fprintf(stderr,
- + "%s: Error opening file '%s'. Last error was %d.\n",
- + progname,
- + filename,
- + (int)GetLastError());
- + return EXIT_FAILURE;
- + }
- +
- + FILE_FS_SIZE_INFORMATION ffsi = { 0 };
- + NTSTATUS status;
- + IO_STATUS_BLOCK io;
- +
- + status = ZwQueryVolumeInformationFile(fileHandle, &io, &ffsi, sizeof(ffsi),
- + FileFsSizeInformation);
- +
- + switch (status) {
- + case STATUS_SUCCESS:
- + break;
- + default:
- + (void)fprintf(stderr, "ZwQueryVolumeInformationFile() failed with 0x%lx\n", (long)status);
- + res = EXIT_FAILURE;
- + goto done;
- + }
- +
- + (void)printf("(\n");
- + (void)printf("\tfilename='%s'\n", filename);
- +
- + (void)printf("\tTotalAllocationUnits=%lld\n",
- + (long long)ffsi.TotalAllocationUnits.QuadPart);
- + (void)printf("\tAvailableAllocationUnits=%lld\n",
- + (long long)ffsi.AvailableAllocationUnits.QuadPart);
- + (void)printf("\tSectorsPerAllocationUnit=%lu\n",
- + (unsigned long)ffsi.SectorsPerAllocationUnit);
- + (void)printf("\tBytesPerSector=%lu\n",
- + (unsigned long)ffsi.BytesPerSector);
- +
- + (void)printf(")\n");
- + res = EXIT_SUCCESS;
- +
- done:
- (void)CloseHandle(fileHandle);
- return res;
- @@ -1401,6 +1454,7 @@ void usage(void)
- "getfinalpath|"
- #ifdef NTDLL_HAS_ZWQUERYVOLUMEINFORMATIONFILE
- "getfilefssectorsizeinformation|"
- + "getfilefssizeinformation|"
- #endif /* NTDLL_HAS_ZWQUERYVOLUMEINFORMATIONFILE */
- "filebasicinfo|"
- "fileexinfostandard|"
- @@ -1453,6 +1507,9 @@ int main(int ac, char *av[])
- else if (!strcmp(subcmd, "getfilefssectorsizeinformation")) {
- return getfilefssectorsizeinformation(av[0], av[2]);
- }
- + else if (!strcmp(subcmd, "getfilefssizeinformation")) {
- + return getfilefssizeinformation(av[0], av[2]);
- + }
- #endif /* NTDLL_HAS_ZWQUERYVOLUMEINFORMATIONFILE */
- else if (!strcmp(subcmd, "filebasicinfo")) {
- return get_file_basic_info(av[0], av[2]);
- --
- 2.45.1
- From 9f0073f8a72ac8b97610d4b0dcb6704fb5060b75 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 26 Aug 2025 14:35:49 +0200
- Subject: [PATCH 2/4] cygwin,tests: Add new /sbin/winrunassystem utility to run
- Windows executables as user SYSTEM
- Add new /sbin/winrunassystem utility to run Windows executables as Windows
- user SYSTEM (S-1-5-18).
- Example:
- Create global mount (for all users/services on a machine):
- $ /sbin/winrunassystem "$(cygpath -w /sbin/nfs_mount.exe)" -o sec=sys,rw 'N' nfs://derfwnb4966_ipv6linklocal//bigdis
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- cygwin/Makefile | 4 +
- cygwin/Makefile.install | 7 +
- tests/winrunassystem/Makefile | 23 +
- tests/winrunassystem/winrunassystem.c | 579 ++++++++++++++++++++++++++
- 4 files changed, 613 insertions(+)
- create mode 100644 tests/winrunassystem/Makefile
- create mode 100644 tests/winrunassystem/winrunassystem.c
- diff --git a/cygwin/Makefile b/cygwin/Makefile
- index 6fbb7f0..13d0a03 100644
- --- a/cygwin/Makefile
- +++ b/cygwin/Makefile
- @@ -25,6 +25,7 @@ $(PROJECT_BASEDIR_DIR)/tests/ea/nfs_ea.exe \
- $(PROJECT_BASEDIR_DIR)/tests/filemmaptests/qsortonmmapedfile1.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.exe \
- + $(PROJECT_BASEDIR_DIR)/tests/winrunassystem/winrunassystem.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe: build_testutils
- #
- @@ -72,6 +73,7 @@ build_testutils:
- (cd "$(PROJECT_BASEDIR_DIR)/tests/filemmaptests" && make all)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make all)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile" && make all)
- + (cd "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem" && make all)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make all)
- build: build_32bit_release build_32bit_debug build_64bit_release build_64bit_debug build_arm_64bit_debug build_testutils
- @@ -109,6 +111,7 @@ clean:
- (cd "$(PROJECT_BASEDIR_DIR)/tests/filemmaptests" && make clean)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make clean)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile" && make clean)
- + (cd "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem" && make clean)
- (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make clean)
- installdest_util: \
- @@ -121,6 +124,7 @@ installdest_util: \
- $(PROJECT_BASEDIR_DIR)/tests/filemmaptests/qsortonmmapedfile1.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.exe \
- + $(PROJECT_BASEDIR_DIR)/tests/winrunassystem/winrunassystem.exe \
- $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe \
- $(CYGWIN_MAKEFILE_DIR)/devel/msnfs41client.bash
- diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
- index 2ad96b0..d0574a4 100644
- --- a/cygwin/Makefile.install
- +++ b/cygwin/Makefile.install
- @@ -126,6 +126,13 @@ installdest:
- else \
- (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) winoffloadcopyfile.i686.exe winoffloadcopyfile.exe) \
- fi
- + cp "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem/winrunassystem.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/winrunassystem.x86_64.exe
- + cp "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem/winrunassystem.i686.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/winrunassystem.i686.exe
- + if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
- + (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/ && $(LINKEXE) winrunassystem.x86_64.exe winrunassystem.exe) \
- + else \
- + (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/ && $(LINKEXE) winrunassystem.i686.exe winrunassystem.exe) \
- + fi
- cp "$(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/lssparse.x86_64.exe
- if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
- (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) lssparse.x86_64.exe lssparse.exe) \
- diff --git a/tests/winrunassystem/Makefile b/tests/winrunassystem/Makefile
- new file mode 100644
- index 0000000..9ade5ec
- --- /dev/null
- +++ b/tests/winrunassystem/Makefile
- @@ -0,0 +1,23 @@
- +#
- +# Makefile for winrunassystem
- +#
- +
- +# POSIX Makefile
- +
- +all: winrunassystem.i686.exe winrunassystem.x86_64.exe winrunassystem.exe
- +
- +winrunassystem.i686.exe: winrunassystem.c
- + clang -target i686-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o winrunassystem.i686.exe
- +
- +winrunassystem.x86_64.exe: winrunassystem.c
- + clang -target x86_64-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o winrunassystem.x86_64.exe
- +
- +winrunassystem.exe: winrunassystem.x86_64.exe
- + ln -s winrunassystem.x86_64.exe winrunassystem.exe
- +
- +clean:
- + rm -fv \
- + winrunassystem.i686.exe \
- + winrunassystem.x86_64.exe \
- + winrunassystem.exe
- +# EOF.
- diff --git a/tests/winrunassystem/winrunassystem.c b/tests/winrunassystem/winrunassystem.c
- new file mode 100644
- index 0000000..80b9fbc
- --- /dev/null
- +++ b/tests/winrunassystem/winrunassystem.c
- @@ -0,0 +1,579 @@
- +
- +/*
- + * MIT License
- + *
- + * Copyright (c) 2025 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * Permission is hereby granted, free of charge, to any person obtaining a copy
- + * of this software and associated documentation files (the "Software"), to deal
- + * in the Software without restriction, including without limitation the rights
- + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- + * copies of the Software, and to permit persons to whom the Software is
- + * furnished to do so, subject to the following conditions:
- + *
- + * The above copyright notice and this permission notice shall be included in
- + * allcopies or substantial portions of the Software.
- + *
- + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- + * THE SOFTWARE.
- + */
- +
- +/*
- + * runassystem.c - run Win32 program as Windows user "SYSTEM"
- + *
- + * Written by Roland Mainz <roland.mainz@nrubsig.org>
- + */
- +
- +/*
- + * Compile with:
- + * $ clang -target x86_64-pc-windows-gnu -Wall -municode runassystem.c \
- + * -lWtsapi32 -o runassystem.exe
- + */
- +
- +#define WIN32_LEAN_AND_MEAN 1
- +
- +#include <windows.h>
- +#include <strsafe.h>
- +#include <stdbool.h>
- +#include <stdio.h>
- +#include <wchar.h>
- +#include <WtsApi32.h>
- +#include <sddl.h>
- +#include <fcntl.h>
- +
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- +
- +/* Global variables */
- +/*
- + * |service_name_buffer| - only valid after calling
- + * |SetupTemporaryServiceName()|
- + */
- +static wchar_t service_name_buffer[512];
- +static const wchar_t* SERVICE_DISPLAY_NAME = L"runassystem temporary service";
- +
- +static SERVICE_STATUS g_ServiceStatus = {0};
- +static SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
- +static HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
- +
- +/*
- + * Store argument array passed to |wmain()| because the argument
- + * array for |ServiceMain()| does not have these arguments
- + *
- + * service_argv[0] == *.exe name
- + * service_argv[1] == "--service"
- + * service_argv[2] == <Service name>
- + * service_argv[3] == <command-to-run>
- + * service_argv[4..n] == <command-args>
- + */
- +static int service_argc = 0;
- +static wchar_t **service_argv = NULL;
- +
- +
- +/* Local prototypes */
- +static void ReportError(const char* context);
- +static void LaunchInteractiveProcess(void);
- +static void WINAPI ServiceCtrlHandler(DWORD CtrlCode);
- +static void WINAPI ServiceMain(DWORD argc, LPWSTR* argv);
- +
- +
- +// #define DBG 1
- +
- +#ifdef DBG
- +#define D(x) x
- +#define DbgP(_x_) RASDbgPrint _x_
- +#else
- +#define DbgP(_x_)
- +#define D(x)
- +#endif
- +#define TRACE_TAG L"[RAS]"
- +
- +#define PTR2PTRDIFF_T(p) (((char *)(p))-((char *)0))
- +#define HANDLE2INT(h) ((int)PTR2PTRDIFF_T(h))
- +
- +#ifdef DBG
- +static
- +ULONG _cdecl RASDbgPrint(__in LPWSTR fmt, ...)
- +{
- + DWORD saved_lasterr;
- + ULONG rc = 0;
- +#define SZBUFFER_SIZE 1024
- + wchar_t szbuffer[SZBUFFER_SIZE+1];
- + wchar_t *szbp = szbuffer;
- +
- + saved_lasterr = GetLastError();
- +
- + va_list marker;
- + va_start(marker, fmt);
- +
- + (void)StringCchPrintfW(szbp, SZBUFFER_SIZE-(szbp - szbuffer),
- + TRACE_TAG L"[thr=%04x] ", (int)GetCurrentThreadId());
- + szbp += wcslen(szbp);
- +
- + (void)StringCchVPrintfW(szbp, SZBUFFER_SIZE-(szbp - szbuffer),
- + fmt, marker);
- + szbuffer[SZBUFFER_SIZE-1] = L'\0';
- +
- + OutputDebugStringW(szbuffer);
- +
- + va_end(marker);
- +
- + SetLastError(saved_lasterr);
- +
- + return rc;
- +}
- +#endif /* DBG */
- +
- +static
- +void ReportError(const char* context)
- +{
- + (void)fprintf(stderr,
- + "ERROR in %s: %d\n",
- + context,
- + (int)GetLastError());
- +}
- +
- +static
- +int remove_fmt(const char *fmt, ...)
- +{
- + int retval;
- + char buffer[16384];
- +
- + va_list args;
- + va_start(args, fmt);
- +
- + (void)vsnprintf(buffer, sizeof(buffer), fmt, args);
- + retval = remove(buffer);
- +
- + va_end(args);
- +
- + return retval;
- +}
- +
- +static
- +int system_fmt(const char *fmt, ...)
- +{
- + int retval;
- + char buffer[16384];
- +
- + va_list args;
- + va_start(args, fmt);
- +
- + (void)vsnprintf(buffer, sizeof(buffer), fmt, args);
- + retval = system(buffer);
- +
- + va_end(args);
- +
- + return retval;
- +}
- +
- +static
- +void LaunchInteractiveProcess(void)
- +{
- + STARTUPINFOA si;
- + PROCESS_INFORMATION pi;
- + DWORD child_retval = 120;
- +
- + const wchar_t *service_name = service_argv[2];
- + char namebuff[256];
- +
- + char buffer[16384];
- + char *s = buffer;
- +
- + HANDLE hFile_stdout = INVALID_HANDLE_VALUE;
- + HANDLE hFile_stderr = INVALID_HANDLE_VALUE;
- + HANDLE hFile_status = INVALID_HANDLE_VALUE;
- +
- + SECURITY_ATTRIBUTES sa = { 0 };
- +
- + (void)memset(&si, 0, sizeof(si));
- + (void)memset(&pi, 0, sizeof(pi));
- +
- + si.cb = sizeof(si);
- +
- + sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- + sa.bInheritHandle = TRUE;
- +
- + (void)snprintf(namebuff, sizeof(namebuff),
- + "C:\\Windows\\Temp\\%ls_stdout", service_name);
- + hFile_stdout = CreateFileA(namebuff,
- + GENERIC_READ|GENERIC_WRITE,
- + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- + &sa,
- + CREATE_ALWAYS,
- + FILE_ATTRIBUTE_TEMPORARY,
- + NULL);
- + if (hFile_stdout == INVALID_HANDLE_VALUE) {
- + DbgP((L"LaunchInteractiveProcess: cannot open stdout, lasterr=%d\n",
- + (int)GetLastError()));
- + goto done;
- + }
- + (void)snprintf(namebuff, sizeof(namebuff),
- + "C:\\Windows\\Temp\\%ls_stderr", service_name);
- + hFile_stderr = CreateFileA(namebuff,
- + GENERIC_READ|GENERIC_WRITE,
- + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- + &sa,
- + CREATE_ALWAYS,
- + FILE_ATTRIBUTE_TEMPORARY,
- + NULL);
- + if (hFile_stderr == INVALID_HANDLE_VALUE) {
- + DbgP((L"LaunchInteractiveProcess: cannot open stderr, lasterr=%d\n",
- + (int)GetLastError()));
- + goto done;
- + }
- + (void)snprintf(namebuff, sizeof(namebuff),
- + "C:\\Windows\\Temp\\%ls_status_not_ready", service_name);
- + hFile_status = CreateFileA(namebuff,
- + GENERIC_READ|GENERIC_WRITE,
- + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- + &sa,
- + CREATE_ALWAYS,
- + FILE_ATTRIBUTE_TEMPORARY,
- + NULL);
- + if (hFile_status == INVALID_HANDLE_VALUE) {
- + DbgP((L"LaunchInteractiveProcess: "
- + L"cannot open status file, lasterr=%d\n",
- + (int)GetLastError()));
- + goto done;
- + }
- + (void)SetHandleInformation(hFile_stdout, HANDLE_FLAG_INHERIT, TRUE);
- + (void)SetHandleInformation(hFile_stderr, HANDLE_FLAG_INHERIT, TRUE);
- +
- + /* Command name + <space> separator */
- + s += sprintf(s, "%ls ", service_argv[3]);
- +
- + int i;
- + for (i=4 ; i < service_argc ; i++) {
- + s += sprintf(s, " \"%ls\"", service_argv[i]);
- + }
- +
- + si.dwFlags = STARTF_USESTDHANDLES;
- + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- + si.hStdOutput = hFile_stdout;
- + si.hStdError = hFile_stderr;
- +
- + if (!CreateProcessA(NULL,
- + buffer,
- + NULL,
- + NULL,
- + TRUE,
- + 0,
- + NULL,
- + NULL,
- + &si,
- + &pi)) {
- + (void)printf("CreateProcess failed (%d).\n", (int)GetLastError());
- + return;
- + }
- +
- + (void)WaitForSingleObject(pi.hProcess, INFINITE);
- +
- + (void)GetExitCodeProcess(pi.hProcess, &child_retval);
- +
- +done:
- + (void)CloseHandle(pi.hProcess);
- + (void)CloseHandle(pi.hThread);
- +
- + (void)CloseHandle(hFile_stdout);
- + (void)CloseHandle(hFile_stderr);
- +
- + if (hFile_status != INVALID_HANDLE_VALUE) {
- + char statusbuff[16];
- +
- + (void)sprintf(statusbuff, "%d", (int)child_retval);
- + (void)WriteFile(hFile_status,
- + statusbuff, strlen(statusbuff), NULL, NULL);
- + (void)CloseHandle(hFile_status);
- +
- + /*
- + * Atomically rename file, parent will wait until the file
- + * is available
- + */
- + char oldnamebuff[256];
- + char newnamebuff[256];
- + (void)snprintf(oldnamebuff, sizeof(oldnamebuff),
- + "C:\\Windows\\Temp\\%ls_status_not_ready", service_name);
- + (void)snprintf(newnamebuff, sizeof(newnamebuff),
- + "C:\\Windows\\Temp\\%ls_status", service_name);
- + (void)rename(oldnamebuff, newnamebuff);
- + }
- +}
- +
- +static
- +void WINAPI ServiceCtrlHandler(DWORD CtrlCode)
- +{
- + switch (CtrlCode) {
- + case SERVICE_CONTROL_STOP:
- + if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
- + break;
- +
- + g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
- + SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- + SetEvent(g_ServiceStopEvent);
- + break;
- + default:
- + break;
- + }
- +}
- +
- +static
- +void WINAPI ServiceMain(DWORD argc, wchar_t *argv[])
- +{
- + (void)argc; /* unused */
- + (void)argv; /* unused */
- +
- + g_StatusHandle = RegisterServiceCtrlHandlerW(service_argv[2],
- + ServiceCtrlHandler);
- + if (!g_StatusHandle) {
- + ReportError("RegisterServiceCtrlHandlerW");
- + return;
- + }
- +
- + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
- + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
- + SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- +
- + g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- + if (g_ServiceStopEvent == NULL) {
- + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
- + SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- + return;
- + }
- +
- + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
- + SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- +
- + LaunchInteractiveProcess();
- +
- + (void)WaitForSingleObject(g_ServiceStopEvent, INFINITE);
- +
- + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
- + SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- + (void)CloseHandle(g_ServiceStopEvent);
- +}
- +
- +static
- +void SetupTemporaryServiceName(void)
- +{
- + FILETIME ft;
- + SYSTEMTIME st;
- +
- + /*
- + * Create service name for our temporary service
- + *
- + * Naming requirements:
- + * - unique name
- + * - includes the word "temporary" to give Admins a hint
- + * what we are doing
- + */
- + GetSystemTimePreciseAsFileTime(&ft);
- + (void)FileTimeToSystemTime(&ft, &st);
- + ULONGLONG ullTime =
- + (ULONGLONG)(ft.dwHighDateTime) << 32 | ft.dwLowDateTime;
- + ULONGLONG nanoseconds = (ullTime % 10000000ULL) * 100ULL;
- +
- + /* "RunAsSYSTEM_temporary_service0001_<yyyy-dd-mm_hhmmss.ns>" */
- + (void)swprintf(service_name_buffer, sizeof(service_name_buffer),
- + L"RunAsSYSTEM_%stemporary_service001_%04d%02d%02d_%02d%02d%02d.%09llu",
- + "", /* site-prefix */
- + (int)st.wYear, (int)st.wMonth, (int)st.wDay,
- + (int)st.wHour, (int)st.wMinute, (int)st.wSecond,
- + (unsigned long long)nanoseconds);
- +}
- +
- +static
- +bool InstallService(int argc, wchar_t *argv[])
- +{
- + bool retval = false;
- + wchar_t szPath[MAX_PATH+1];
- + wchar_t szPathWithArg[16384];
- + wchar_t *s;
- + SC_HANDLE hSCManager;
- +
- + hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- + if (!hSCManager) {
- + ReportError("OpenSCManager");
- + return false;
- + }
- +
- + /* Get our *.exe name */
- + if (GetModuleFileNameW(NULL, szPath, MAX_PATH) == 0) {
- + ReportError("GetModuleFileNameW");
- + retval = false;
- + goto done;
- + }
- +
- + /* Manually construct the path with the argument for the service */
- + s = szPathWithArg;
- + s += swprintf(s, 1024, L"\"%ls\" --service %ls",
- + szPath, service_name_buffer);
- + int i;
- + for (i=1 ; i < argc ; i++) {
- + /* FIXME: Quoting */
- + s += swprintf(s, 1024, L" \"%ls\"", argv[i]);
- + }
- +
- + /* Print arguments */
- + D((void)wprintf(L"szPathWithArg='%ls'\n", szPathWithArg));
- +
- + /*
- + * FIXME: We should implement -u and -g to define username and primary
- + * group name
- + */
- + SC_HANDLE hService = CreateServiceW(hSCManager,
- + service_name_buffer, SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS,
- + SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
- + szPathWithArg, NULL, NULL, NULL, L"NT AUTHORITY\\SYSTEM", NULL);
- + if (!hService) {
- + ReportError("CreateServiceW");
- + retval = false;
- + goto done;
- + }
- +
- + D((void)wprintf(L"Service '%ls' created successfully.\n",
- + service_name_buffer));
- + if (!StartServiceW(hService, 0, NULL)) {
- + ReportError("StartServiceW");
- + retval = false;
- + goto done;
- + }
- +
- + D((void)wprintf(L"Service '%ls' started successfully.\n",
- + service_name_buffer));
- +
- + /* Wait until *_status file appears */
- + char namebuff[256];
- + (void)snprintf(namebuff, sizeof(namebuff),
- + "C:\\Windows\\Temp\\%ls_status",
- + service_name_buffer);
- + while (_access(namebuff, 00) != 0) {
- + /*
- + * FIXME: We should have a timeout, test for <CTRL-C>, and decrease
- + * the threads priority while polling (to avoid starving the child
- + * process)
- + */
- + Sleep(200);
- + }
- +
- + (void)CloseServiceHandle(hService);
- +
- + /* Success! */
- + retval = true;
- +
- +done:
- + (void)CloseServiceHandle(hSCManager);
- + return retval;
- +}
- +
- +static
- +void UninstallService(void)
- +{
- + SC_HANDLE hSCManager;
- + SERVICE_STATUS status;
- +
- + hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- + if (!hSCManager) {
- + ReportError("UninstallService: OpenSCManager");
- + return;
- + }
- +
- + SC_HANDLE hService = OpenServiceW(hSCManager,
- + service_name_buffer, SERVICE_ALL_ACCESS);
- + if (!hService) {
- + ReportError("UninstallService: OpenServiceW");
- + goto done;
- + }
- +
- + (void)ControlService(hService, SERVICE_CONTROL_STOP, &status);
- + D((void)wprintf(L"Service stopped.\n"));
- +
- + if (!DeleteService(hService)) {
- + ReportError("UninstallService: DeleteService");
- + } else {
- + D((void)wprintf(L"UninstallService: Service deleted.\n"));
- + }
- +
- + (void)CloseServiceHandle(hService);
- +
- +done:
- + (void)CloseServiceHandle(hSCManager);
- +}
- +
- +static
- +void usage(const wchar_t *av0)
- +{
- + (void)fwprintf(stderr,
- + L"%ls: Run command as user SYSTEM\n",
- + av0);
- +}
- +
- +int wmain(int argc, wchar_t *argv[])
- +{
- + int retval = EXIT_FAILURE;
- +
- + if ((argc == 1) ||
- + ((argc == 2) &&
- + ((wcscmp(argv[1], L"--help") == 0) ||
- + (wcscmp(argv[1], L"-h") == 0) ||
- + (wcscmp(argv[1], L"/?") == 0)))) {
- + usage(argv[0]);
- + return EXIT_USAGE;
- + }
- +
- + /*
- + * If started with "--service", run as a service
- + */
- + if ((argc > 2) && (wcscmp(argv[1], L"--service") == 0)) {
- + service_argc = argc;
- + service_argv = argv;
- +
- + SERVICE_TABLE_ENTRYW ServiceTable[] = {
- + { .lpServiceName = argv[2], .lpServiceProc = ServiceMain },
- + { .lpServiceName = NULL, .lpServiceProc = NULL }
- + };
- +
- + if (!StartServiceCtrlDispatcherW(ServiceTable)) {
- + ReportError("StartServiceCtrlDispatcherW");
- + return 1;
- + }
- + return 0;
- + }
- +
- + /* Otherwise, run as the client to manage the service */
- + D((void)wprintf(L"Running as client to install and start the service...\n"));
- +
- + SetupTemporaryServiceName();
- +
- + /* Remove old status file */
- + (void)remove_fmt("C:\\Windows\\Temp\\%ls_status", service_name_buffer);
- +
- + /* Install and Start */
- + if (InstallService(argc, argv)) {
- + /* Stop and Uninstall */
- + UninstallService();
- +
- + (void)system_fmt("C:\\cygwin64\\bin\\bash.exe -c "
- + "'cat \"/cygdrive/c/Windows/Temp/%ls_stderr\" 1>&2'",
- + service_name_buffer);
- + (void)system_fmt("C:\\cygwin64\\bin\\bash.exe -c "
- + "'cat \"/cygdrive/c/Windows/Temp/%ls_stdout\"'",
- + service_name_buffer);
- + (void)system_fmt("C:\\cygwin64\\bin\\bash.exe -c "
- + "'printf \"# Child status %%d.\\\\n\" "
- + "\"$( <\"/cygdrive/c/Windows/Temp/%ls_status\" )\" 1>&2'",
- + service_name_buffer);
- + (void)remove_fmt("C:\\Windows\\Temp\\%ls_stdout", service_name_buffer);
- + (void)remove_fmt("C:\\Windows\\Temp\\%ls_stderr", service_name_buffer);
- + (void)remove_fmt("C:\\Windows\\Temp\\%ls_status", service_name_buffer);
- +
- + retval = EXIT_SUCCESS;
- + }
- +
- + return retval;
- +}
- --
- 2.45.1
- From a9a8ff080a96199f51e827e2b26fcab04e60301f Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 26 Aug 2025 15:05:26 +0200
- Subject: [PATCH 3/4] mount: nfs_mount.exe --usage should return exit code 2
- per UNIX tradition
- nfs_mount.exe --usage should return exit code 2 per UNIX tradition.
- Reported-by: Aurelien Couderc <aurelien.couderc2002@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- mount/mount.c | 23 ++++++++++++++++-------
- 1 file changed, 16 insertions(+), 7 deletions(-)
- diff --git a/mount/mount.c b/mount/mount.c
- index 5fd1dda..8afb199 100644
- --- a/mount/mount.c
- +++ b/mount/mount.c
- @@ -50,6 +50,8 @@
- */
- #include "git_version.h"
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- +
- /*
- * Disable "warning C4996: 'wcscpy': This function or variable may be
- * unsafe." because in this case the buffers are properly sized,
- @@ -249,7 +251,7 @@ int mount_main(int argc, wchar_t *argv[])
- if ((!wcscmp(argv[i], L"-h")) ||
- (!wcscmp(argv[i], L"--help"))) {
- PrintMountUsage(argv[0]);
- - result = 1;
- + result = ERROR_INVALID_COMMAND_LINE;
- goto out;
- }
- /* print version info */
- @@ -425,7 +427,7 @@ opt_o_argv_i_again:
- /* Windows-style "nfs_mount /?" help */
- else if (!wcscmp(argv[i], L"/?")) {
- PrintMountUsage(argv[0]);
- - result = 1;
- + result = ERROR_INVALID_COMMAND_LINE;
- goto out;
- }
- /* drive letter */
- @@ -532,7 +534,7 @@ int umount_main(int argc, wchar_t *argv[])
- if ((!wcscmp(argv[i], L"-h")) ||
- (!wcscmp(argv[i], L"--help"))) {
- PrintUmountUsage(argv[0]);
- - result = 1;
- + result = ERROR_INVALID_COMMAND_LINE;
- goto out;
- }
- /* print version info */
- @@ -556,7 +558,7 @@ int umount_main(int argc, wchar_t *argv[])
- /* Windows-style "nfs_umount /?" help */
- else if (!wcscmp(argv[i], L"/?")) {
- PrintUmountUsage(argv[0]);
- - result = 1;
- + result = ERROR_INVALID_COMMAND_LINE;
- goto out;
- }
- /* drive letter */
- @@ -573,7 +575,6 @@ int umount_main(int argc, wchar_t *argv[])
- if (pLocalName == NULL) {
- result = ERROR_BAD_ARGUMENTS;
- (void)fwprintf(stderr, L"Drive letter expected.\n");
- - PrintUmountUsage(argv[0]);
- goto out;
- }
- @@ -702,9 +703,17 @@ int __cdecl wmain(int argc, wchar_t *argv[])
- out:
- /*
- * POSIX return value of a command can only in the range from
- - * |0|...|SCHAR_MAX|, so map the |ERROR_*| to |1|,|0|.
- + * |0|...|SCHAR_MAX|, so map the |ERROR_*| to { |2|,|1|,|0| }.
- */
- - return (result != NO_ERROR)?1:0;
- + if (result == ERROR_INVALID_COMMAND_LINE) {
- + return EXIT_USAGE;
- + }
- + else if (result != NO_ERROR) {
- + return EXIT_FAILURE;
- + }
- + else {
- + return EXIT_SUCCESS;
- + }
- }
- --
- 2.45.1
- From 21330b3cbcc1008840bea0d7eb915d4d1f9ce854 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 26 Aug 2025 15:10:00 +0200
- Subject: [PATCH 4/4] tests: Add comment about |EXIT_USAGE| being an UNIX
- tradition
- Add comment about |EXIT_USAGE| being an UNIX tradition.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/filemmaptests/qsortonmmapedfile1.c | 2 +-
- tests/lssparse/lssparse.c | 2 +-
- tests/winclonefile/winclonefile.c | 2 +-
- tests/winoffloadcopyfile/winoffloadcopyfile.c | 2 +-
- 4 files changed, 4 insertions(+), 4 deletions(-)
- diff --git a/tests/filemmaptests/qsortonmmapedfile1.c b/tests/filemmaptests/qsortonmmapedfile1.c
- index 976c325..31c5da8 100644
- --- a/tests/filemmaptests/qsortonmmapedfile1.c
- +++ b/tests/filemmaptests/qsortonmmapedfile1.c
- @@ -61,7 +61,7 @@
- #include <stdlib.h>
- #include <string.h>
- -#define EXIT_USAGE 2
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- #define RECORD_DATA_SIZE 15
- #define RECORD_SIZE (RECORD_DATA_SIZE+1)
- diff --git a/tests/lssparse/lssparse.c b/tests/lssparse/lssparse.c
- index ae1c73e..5c56a4d 100644
- --- a/tests/lssparse/lssparse.c
- +++ b/tests/lssparse/lssparse.c
- @@ -41,7 +41,7 @@
- #include <unistd.h>
- #include <errno.h>
- -#define EXIT_USAGE (2)
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- static
- void
- diff --git a/tests/winclonefile/winclonefile.c b/tests/winclonefile/winclonefile.c
- index c79672d..80bf35a 100644
- --- a/tests/winclonefile/winclonefile.c
- +++ b/tests/winclonefile/winclonefile.c
- @@ -35,7 +35,7 @@
- #include <winioctl.h>
- #include <stdio.h>
- -#define EXIT_USAGE (2)
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- #ifdef DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC
- /*
- diff --git a/tests/winoffloadcopyfile/winoffloadcopyfile.c b/tests/winoffloadcopyfile/winoffloadcopyfile.c
- index db1a209..5669140 100644
- --- a/tests/winoffloadcopyfile/winoffloadcopyfile.c
- +++ b/tests/winoffloadcopyfile/winoffloadcopyfile.c
- @@ -35,7 +35,7 @@
- #include <winioctl.h>
- #include <stdio.h>
- -#define EXIT_USAGE (2)
- +#define EXIT_USAGE (2) /* Traditional UNIX exit code for usage */
- /* MinGW headers are currently missing these defines and types */
- #ifndef OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE
- --
- 2.45.1
msnfs41client: Patches for EXIT_USAGE, tests, winrunassystem+misc, 2025-08-26
Posted by Anonymous on Tue 26th Aug 2025 14:41
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.