Coverage Report

Created: 2026-07-30 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/os/src/osSysinfo.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
16
#define _DEFAULT_SOURCE
17
#include "os.h"
18
#include "taoserror.h"
19
#include "cus_name.h"
20
21
0
#define PROCESS_ITEM 12
22
#define UUIDLEN37 37
23
24
typedef struct {
25
  uint64_t user;
26
  uint64_t nice;
27
  uint64_t system;
28
  uint64_t idle;
29
  uint64_t wa;
30
  uint64_t hi;
31
  uint64_t si;
32
  uint64_t st;
33
  uint64_t guest;
34
  uint64_t guest_nice;
35
} SysCpuInfo;
36
37
typedef struct {
38
  uint64_t utime;   // user time
39
  uint64_t stime;   // kernel time
40
  uint64_t cutime;  // all user time
41
  uint64_t cstime;  // all dead time
42
} ProcCpuInfo;
43
44
#ifdef WINDOWS
45
46
/*
47
 * windows implementation
48
 */
49
50
#if (_WIN64)
51
#include <iphlpapi.h>
52
#include <mswsock.h>
53
#include <psapi.h>
54
#include <stdio.h>
55
#include <windows.h>
56
#include <ws2tcpip.h>
57
#pragma comment(lib, "Mswsock.lib ")
58
#endif
59
60
#include <objbase.h>
61
#include <signal.h>
62
#include <stdlib.h>
63
64
#pragma warning(push)
65
#pragma warning(disable : 4091)
66
#include <DbgHelp.h>
67
#pragma warning(pop)
68
69
// Write a single stack frame line to hFile.
70
// dbghelp functions are available via the statically-linked dbghelp.lib.
71
static void taosWinWriteOneFrame(HANDLE hFile, HANDLE hProcess, DWORD64 pc, DWORD idx) {
72
  char         symBuf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
73
  PSYMBOL_INFO pSym = (PSYMBOL_INFO)symBuf;
74
  pSym->SizeOfStruct = sizeof(SYMBOL_INFO);
75
  pSym->MaxNameLen   = MAX_SYM_NAME;
76
77
  DWORD64 symDisp = 0;
78
  char   *symName = (char *)"<unknown>";
79
  if (SymFromAddr(hProcess, pc, &symDisp, pSym)) {
80
    symName = pSym->Name;
81
  }
82
83
  IMAGEHLP_LINE64 li = {0};
84
  li.SizeOfStruct     = sizeof(IMAGEHLP_LINE64);
85
  DWORD lineDisp      = 0;
86
87
  char line[4096];
88
  int  n;
89
  if (SymGetLineFromAddr64(hProcess, pc, &lineDisp, &li)) {
90
    n = _snprintf_s(line, sizeof(line), _TRUNCATE, "#%-3lu 0x%016I64X  %s  (%s:%lu)\r\n",
91
                    (unsigned long)idx, pc, symName, li.FileName, (unsigned long)li.LineNumber);
92
  } else {
93
    n = _snprintf_s(line, sizeof(line), _TRUNCATE, "#%-3lu 0x%016I64X  %s\r\n",
94
                    (unsigned long)idx, pc, symName);
95
  }
96
  DWORD w = 0;
97
  if (n > 0) (void)WriteFile(hFile, line, (DWORD)n, &w, NULL);
98
}
99
100
// Walk the call stack from the exception context and write each frame to hFile.
101
static void taosWinWriteStackTrace(HANDLE hFile, PEXCEPTION_POINTERS ep) {
102
  HANDLE  hProcess = GetCurrentProcess();
103
  HANDLE  hThread  = GetCurrentThread();
104
  CONTEXT ctx      = *ep->ContextRecord; /* copy: StackWalk64 modifies it */
105
106
  SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
107
  SymInitialize(hProcess, NULL, TRUE);
108
109
  STACKFRAME64 sf   = {0};
110
  DWORD        mach;
111
#if defined(_M_X64)
112
  mach                = IMAGE_FILE_MACHINE_AMD64;
113
  sf.AddrPC.Offset    = ctx.Rip; sf.AddrPC.Mode    = AddrModeFlat;
114
  sf.AddrFrame.Offset = ctx.Rbp; sf.AddrFrame.Mode = AddrModeFlat;
115
  sf.AddrStack.Offset = ctx.Rsp; sf.AddrStack.Mode = AddrModeFlat;
116
#elif defined(_M_IX86)
117
  mach                = IMAGE_FILE_MACHINE_I386;
118
  sf.AddrPC.Offset    = ctx.Eip; sf.AddrPC.Mode    = AddrModeFlat;
119
  sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat;
120
  sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat;
121
#elif defined(_M_ARM64)
122
  mach                = IMAGE_FILE_MACHINE_ARM64;
123
  sf.AddrPC.Offset    = ctx.Pc; sf.AddrPC.Mode    = AddrModeFlat;
124
  sf.AddrFrame.Offset = ctx.Fp; sf.AddrFrame.Mode = AddrModeFlat;
125
  sf.AddrStack.Offset = ctx.Sp; sf.AddrStack.Mode = AddrModeFlat;
126
#else
127
  SymCleanup(hProcess);
128
  return; /* unsupported architecture */
129
#endif
130
131
  static const char hdr[] = "=== Stack Trace ===\r\n";
132
  DWORD w = 0;
133
  (void)WriteFile(hFile, hdr, (DWORD)(sizeof(hdr) - 1), &w, NULL);
134
135
  for (DWORD i = 0; i < 128; i++) {
136
    if (!StackWalk64(mach, hProcess, hThread, &sf, (PVOID)&ctx,
137
                     NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
138
      break;
139
    if (sf.AddrPC.Offset == 0) break;
140
    taosWinWriteOneFrame(hFile, hProcess, sf.AddrPC.Offset, i);
141
  }
142
  SymCleanup(hProcess);
143
}
144
145
LONG WINAPI FlCrashDump(PEXCEPTION_POINTERS ep) {
146
  // Only handle fatal exceptions, let others pass through for vectored handler
147
  DWORD code = ep->ExceptionRecord->ExceptionCode;
148
149
  // Skip non-fatal exceptions (like breakpoints during debugging)
150
  if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP) {
151
    return EXCEPTION_CONTINUE_SEARCH;
152
  }
153
  
154
  typedef BOOL(WINAPI * FxMiniDumpWriteDump)(IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile,
155
                                             IN MINIDUMP_TYPE                           DumpType,
156
                                             IN CONST PMINIDUMP_EXCEPTION_INFORMATION   ExceptionParam,
157
                                             IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
158
                                             IN CONST PMINIDUMP_CALLBACK_INFORMATION    CallbackParam);
159
160
  // ── 1. load dbghelp ──────────────────────────────────────────────────────
161
  HMODULE dll = LoadLibraryA("dbghelp.dll");
162
  if (dll == NULL) return EXCEPTION_CONTINUE_SEARCH;
163
  FxMiniDumpWriteDump mdwd = (FxMiniDumpWriteDump)(GetProcAddress(dll, "MiniDumpWriteDump"));
164
  if (mdwd == NULL) {
165
    FreeLibrary(dll);
166
    return EXCEPTION_CONTINUE_SEARCH;
167
  }
168
169
  // ── 2. build timestamped file paths next to the running executable ───────
170
  //      Keeping dumps beside the exe makes them easy to find.
171
  SYSTEMTIME st;
172
  GetLocalTime(&st);
173
174
  TdWchar exePath[MAX_PATH];
175
  DWORD   exeLen = GetModuleFileNameW(NULL, exePath, MAX_PATH);
176
  /* strip the executable filename, keep the trailing backslash */
177
  while (exeLen > 0 && exePath[exeLen - 1] != L'\\') exeLen--;
178
  exePath[exeLen] = L'\0';  /* exePath is now the directory with trailing '\' */
179
180
  TdWchar dmpPath[MAX_PATH];
181
  TdWchar logPath[MAX_PATH];
182
  _snwprintf_s(dmpPath, MAX_PATH, _TRUNCATE,
183
               L"%staosd_%04d%02d%02d_%02d%02d%02d.dmp",
184
               exePath, st.wYear, st.wMonth, st.wDay,
185
               st.wHour, st.wMinute, st.wSecond);
186
  _snwprintf_s(logPath, MAX_PATH, _TRUNCATE,
187
               L"%staosd_%04d%02d%02d_%02d%02d%02d_stack.log",
188
               exePath, st.wYear, st.wMonth, st.wDay,
189
               st.wHour, st.wMinute, st.wSecond);
190
191
  // ── 3. write MiniDump with comprehensive type ─────────────────────────────
192
  HANDLE dmpFile = CreateFileW(dmpPath, GENERIC_WRITE, 0, NULL,
193
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
194
  if (dmpFile != INVALID_HANDLE_VALUE) {
195
    MINIDUMP_EXCEPTION_INFORMATION mei;
196
    mei.ThreadId          = GetCurrentThreadId();
197
    mei.ExceptionPointers = ep;
198
    mei.ClientPointers    = FALSE;
199
200
    MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)(
201
        MiniDumpWithDataSegs                    |  /* global/static variables     */
202
        MiniDumpWithProcessThreadData           |  /* all thread stacks + locals  */
203
        MiniDumpWithHandleData                  |  /* open handles                */
204
        MiniDumpWithIndirectlyReferencedMemory  |  /* memory pointed-to by locals */
205
        MiniDumpWithThreadInfo                  |  /* thread times, start addr    */
206
        MiniDumpWithFullMemoryInfo);               /* all VMAs (flags/state)      */
207
    // Keep process/thread data and indirectly referenced memory enabled
208
    // to capture more complete diagnostic information in the minidump
209
210
    (*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), dmpFile,
211
            dumpType, &mei, NULL, NULL);
212
    CloseHandle(dmpFile);
213
  }
214
215
  // ── 4. write stack trace text log (usable without PDB on developer side) ──
216
  HANDLE logFile = CreateFileW(logPath, GENERIC_WRITE, 0, NULL,
217
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
218
  if (logFile != INVALID_HANDLE_VALUE) {
219
    char  hdr[512];
220
    DWORD w = 0;
221
    int   n = _snprintf_s(hdr, sizeof(hdr), _TRUNCATE,
222
                          "ExceptionCode:    0x%08lX\r\n"
223
                          "ExceptionAddress: 0x%016I64X\r\n"
224
                          "ThreadId:         %lu\r\n"
225
                          "\r\n",
226
                          ep->ExceptionRecord->ExceptionCode,
227
                          (DWORD64)(ULONG_PTR)ep->ExceptionRecord->ExceptionAddress,
228
                          (unsigned long)GetCurrentThreadId());
229
    if (n > 0) (void)WriteFile(logFile, hdr, (DWORD)n, &w, NULL);
230
    taosWinWriteStackTrace(logFile, ep);
231
    CloseHandle(logFile);
232
  }
233
234
  FreeLibrary(dll);
235
236
  // Return EXCEPTION_CONTINUE_SEARCH so that Windows Error Reporting (WER /
237
  // WerFault.exe) can write an out-of-process dump as a fallback.  WerFault
238
  // runs in a separate process and is therefore immune to stack/heap corruption
239
  // in this process — it will still produce a valid dump even when
240
  // MiniDumpWriteDump above failed (e.g. due to stack overflow or heap
241
  // corruption that zeroed out our stack frame).
242
  // Configure the WER dump directory via:
243
  //   HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\taosd.exe
244
  //     DumpFolder  REG_EXPAND_SZ  <path>
245
  //     DumpType    REG_DWORD      2        (full user-mode dump)
246
  //     DumpCount   REG_DWORD      10
247
  return EXCEPTION_CONTINUE_SEARCH;
248
}
249
250
// Vectored Exception Handler - called BEFORE SEH, can catch heap corruption
251
static LONG WINAPI FlVectoredExceptionHandler(PEXCEPTION_POINTERS ep) {
252
  DWORD code = ep->ExceptionRecord->ExceptionCode;
253
254
  // Only handle critical exceptions that would terminate the process
255
  // These exceptions may bypass SetUnhandledExceptionFilter in some cases
256
  if (code == 0xC0000374 ||  // STATUS_HEAP_CORRUPTION
257
      code == 0xC0000409 ||  // STATUS_STACK_BUFFER_OVERRUN (fast-fail)
258
      code == 0xC00000FD) {  // STATUS_STACK_OVERFLOW
259
    // Call FlCrashDump directly for these special exceptions
260
    (void)FlCrashDump(ep);
261
  }
262
263
  // Let other exceptions pass to normal SEH handling
264
  return EXCEPTION_CONTINUE_SEARCH;
265
}
266
267
// Helper function to generate dump without exception context (for CRT handlers)
268
static void FlCrashDumpNoException(const char* reason) {
269
  typedef BOOL(WINAPI * FxMiniDumpWriteDump)(IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile,
270
                                             IN MINIDUMP_TYPE                           DumpType,
271
                                             IN CONST PMINIDUMP_EXCEPTION_INFORMATION   ExceptionParam,
272
                                             IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
273
                                             IN CONST PMINIDUMP_CALLBACK_INFORMATION    CallbackParam);
274
275
  HMODULE dll = LoadLibraryA("dbghelp.dll");
276
  if (dll == NULL) return;
277
  FxMiniDumpWriteDump mdwd = (FxMiniDumpWriteDump)(GetProcAddress(dll, "MiniDumpWriteDump"));
278
  if (mdwd == NULL) {
279
    FreeLibrary(dll);
280
    return;
281
  }
282
283
  SYSTEMTIME st;
284
  GetLocalTime(&st);
285
286
  TdWchar exePath[MAX_PATH];
287
  DWORD   exeLen = GetModuleFileNameW(NULL, exePath, MAX_PATH);
288
  while (exeLen > 0 && exePath[exeLen - 1] != L'\\') exeLen--;
289
  exePath[exeLen] = L'\0';
290
291
  TdWchar dmpPath[MAX_PATH];
292
  _snwprintf_s(dmpPath, MAX_PATH, _TRUNCATE,
293
               L"%staosd_%04d%02d%02d_%02d%02d%02d.dmp",
294
               exePath, st.wYear, st.wMonth, st.wDay,
295
               st.wHour, st.wMinute, st.wSecond);
296
297
  HANDLE dmpFile = CreateFileW(dmpPath, GENERIC_WRITE, 0, NULL,
298
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
299
  if (dmpFile != INVALID_HANDLE_VALUE) {
300
    MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)(
301
        MiniDumpWithDataSegs | MiniDumpWithProcessThreadData |
302
        MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithFullMemoryInfo);
303
    (*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), dmpFile,
304
            dumpType, NULL, NULL, NULL);  // No exception info
305
    CloseHandle(dmpFile);
306
  }
307
308
  // Write reason to log file
309
  TdWchar logPath[MAX_PATH];
310
  _snwprintf_s(logPath, MAX_PATH, _TRUNCATE,
311
               L"%staosd_%04d%02d%02d_%02d%02d%02d_stack.log",
312
               exePath, st.wYear, st.wMonth, st.wDay,
313
               st.wHour, st.wMinute, st.wSecond);
314
  HANDLE logFile = CreateFileW(logPath, GENERIC_WRITE, 0, NULL,
315
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
316
  if (logFile != INVALID_HANDLE_VALUE) {
317
    char msg[512];
318
    int n = _snprintf_s(msg, sizeof(msg), _TRUNCATE,
319
                        "CRT/Runtime Error: %s\r\nThreadId: %lu\r\n",
320
                        reason, (unsigned long)GetCurrentThreadId());
321
    DWORD w = 0;
322
    if (n > 0) WriteFile(logFile, msg, (DWORD)n, &w, NULL);
323
    CloseHandle(logFile);
324
  }
325
326
  FreeLibrary(dll);
327
}
328
329
// CRT invalid parameter handler
330
static void FlInvalidParameterHandler(const TdWchar* expression, const TdWchar* function,
331
                                       const TdWchar* file, unsigned int line, size_t reserved) {
332
  (void)expression; (void)function; (void)file; (void)line; (void)reserved;
333
  FlCrashDumpNoException("Invalid parameter detected in CRT function");
334
  _exit(3);
335
}
336
337
// CRT pure virtual call handler
338
static void FlPureCallHandler(void) {
339
  FlCrashDumpNoException("Pure virtual function call");
340
  _exit(3);
341
}
342
343
// abort() handler - called when abort() is invoked
344
static void FlAbortHandler(int sig) {
345
  (void)sig;
346
  FlCrashDumpNoException("abort() called");
347
  _exit(3);
348
}
349
350
#elif defined(_TD_DARWIN_64)
351
352
#include <errno.h>
353
#include <libproc.h>
354
#include <sys/sysctl.h>
355
#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
356
#include <CoreFoundation/CFString.h>
357
#include <stdio.h>
358
359
#else
360
361
#include <argp.h>
362
#ifndef TD_ASTRA
363
#include <linux/sysctl.h>
364
#include <sys/file.h>
365
#include <sys/resource.h>
366
#include <sys/statvfs.h>
367
#include <sys/syscall.h>
368
#endif
369
#include <sys/utsname.h>
370
#include <unistd.h>
371
372
static pid_t tsProcId;
373
static const char *tsSysNetFile = "/proc/net/dev";
374
static const char *tsSysCpuFile = "/proc/stat";
375
static const char *tsCpuPeriodFile = "/sys/fs/cgroup/cpu/cpu.cfs_period_us";
376
static const char *tsCpuQuotaFile = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us";
377
static char  tsProcCpuFile[25] = {0};
378
static char  tsProcMemFile[25] = {0};
379
static char  tsProcIOFile[25] = {0};
380
381
// cgroup v2 paths
382
static const char *tsCgroupV2CpuMaxFile = "/sys/fs/cgroup/cpu.max";
383
static const char *tsCgroupV2MemMaxFile = "/sys/fs/cgroup/memory.max";
384
static const char *tsCgroupV2MemCurFile = "/sys/fs/cgroup/memory.current";
385
static const char *tsCgroupV2MemStatFile = "/sys/fs/cgroup/memory.stat";
386
static const char *tsCgroupV2CpuStatFile = "/sys/fs/cgroup/cpu.stat";
387
388
// cgroup v1 memory paths
389
static const char *tsCgroupV1MemLimitFile = "/sys/fs/cgroup/memory/memory.limit_in_bytes";
390
static const char *tsCgroupV1MemUsageFile = "/sys/fs/cgroup/memory/memory.usage_in_bytes";
391
static const char *tsCgroupV1MemStatFile = "/sys/fs/cgroup/memory/memory.stat";
392
static const char *tsCgroupV1CpuAcctFile = "/sys/fs/cgroup/cpuacct/cpuacct.usage";
393
394
// Returns: 2 for cgroup v2, 1 for cgroup v1, 0 for no cgroup
395
0
static int32_t taosDetectCgroupVersion() {
396
0
  static volatile int32_t cgroupVersion = -1;
397
398
0
  int32_t ver = atomic_load_32(&cgroupVersion);
399
0
  if (ver >= 0) return ver;
400
401
0
  if (taosCheckExistFile("/sys/fs/cgroup/cgroup.controllers")) {
402
0
    ver = 2;
403
0
  } else if (taosCheckExistFile(tsCpuQuotaFile) || taosCheckExistFile(tsCgroupV1MemLimitFile)) {
404
0
    ver = 1;
405
0
  } else {
406
0
    ver = 0;
407
0
  }
408
409
0
  (void)atomic_val_compare_exchange_32(&cgroupVersion, -1, ver);
410
0
  return ver;
411
0
}
412
413
// Read a single int64 value from a cgroup file. Returns 0 on success.
414
0
static int32_t taosReadCgroupInt64(const char *path, int64_t *value) {
415
0
  if (path == NULL || value == NULL) return -1;
416
0
  TdFilePtr pFile = taosOpenFile(path, TD_FILE_READ | TD_FILE_STREAM);
417
0
  if (pFile == NULL) return -1;
418
419
0
  char line[64] = {0};
420
0
  if (taosGetsFile(pFile, sizeof(line), line) <= 0) {
421
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
422
0
    return -1;
423
0
  }
424
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
425
426
  // "max" means no limit
427
0
  if (strncmp(line, "max", 3) == 0) {
428
0
    *value = INT64_MAX;
429
0
    return 0;
430
0
  }
431
432
0
  char *endPtr = NULL;
433
0
  int64_t v = taosStr2Int64(line, &endPtr, 10);
434
0
  if (endPtr == line) return -1;
435
0
  *value = v;
436
0
  return 0;
437
0
}
438
439
0
static void taosGetProcIOnfos() {
440
0
  tsPageSizeKB = sysconf(_SC_PAGESIZE) / 1024;
441
0
  tsOpenMax = sysconf(_SC_OPEN_MAX);
442
0
  tsStreamMax = TMAX(sysconf(_SC_STREAM_MAX), 0);
443
0
#ifndef TD_ASTRA
444
0
  tsProcId = (pid_t)syscall(SYS_gettid);
445
446
0
  (void)snprintf(tsProcMemFile, sizeof(tsProcMemFile), "/proc/%d/status", tsProcId);
447
0
  (void)snprintf(tsProcCpuFile, sizeof(tsProcCpuFile), "/proc/%d/stat", tsProcId);
448
0
  (void)snprintf(tsProcIOFile, sizeof(tsProcIOFile), "/proc/%d/io", tsProcId);
449
0
#endif
450
0
}
451
#endif
452
453
0
static int32_t taosGetSysCpuInfo(SysCpuInfo *cpuInfo) {
454
0
  int32_t code = 0;
455
#ifdef WINDOWS
456
  FILETIME pre_idleTime = {0};
457
  FILETIME pre_kernelTime = {0};
458
  FILETIME pre_userTime = {0};
459
  FILETIME idleTime;
460
  FILETIME kernelTime;
461
  FILETIME userTime;
462
  bool     res = GetSystemTimes(&idleTime, &kernelTime, &userTime);
463
  if (res) {
464
    cpuInfo->idle = CompareFileTime(&pre_idleTime, &idleTime);
465
    cpuInfo->system = CompareFileTime(&pre_kernelTime, &kernelTime);
466
    cpuInfo->user = CompareFileTime(&pre_userTime, &userTime);
467
    cpuInfo->nice = 0;
468
  }
469
#elif defined(DARWIN) || defined(TD_ASTRA)
470
  cpuInfo->idle = 0;
471
  cpuInfo->system = 0;
472
  cpuInfo->user = 0;
473
  cpuInfo->nice = 0;
474
#else
475
0
  TdFilePtr pFile = taosOpenFile(tsSysCpuFile, TD_FILE_READ | TD_FILE_STREAM);
476
0
  if (pFile == NULL) {
477
0
    return terrno;
478
0
  }
479
480
0
  char    line[1024];
481
0
  ssize_t bytes = taosGetsFile(pFile, sizeof(line), line);
482
0
  if (bytes < 0) {
483
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
484
0
    return terrno;
485
0
  }
486
487
0
  char cpu[10] = {0};
488
0
  code = sscanf(line,
489
0
         "%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
490
0
         " %" PRIu64,
491
0
         cpu, &cpuInfo->user, &cpuInfo->nice, &cpuInfo->system, &cpuInfo->idle, &cpuInfo->wa, &cpuInfo->hi,
492
0
         &cpuInfo->si, &cpuInfo->st, &cpuInfo->guest, &cpuInfo->guest_nice);
493
0
  if (EOF == code) {
494
0
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
495
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
496
0
    return terrno;
497
0
  }
498
  
499
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
500
0
#endif
501
502
0
  return 0;
503
0
}
504
505
0
static int32_t taosGetProcCpuInfo(ProcCpuInfo *cpuInfo) {
506
0
  int32_t code = 0;
507
508
#ifdef WINDOWS
509
  FILETIME pre_krnlTm = {0};
510
  FILETIME pre_usrTm = {0};
511
  FILETIME creatTm, exitTm, krnlTm, usrTm;
512
513
  if (GetThreadTimes(GetCurrentThread(), &creatTm, &exitTm, &krnlTm, &usrTm)) {
514
    cpuInfo->stime = CompareFileTime(&pre_krnlTm, &krnlTm);
515
    cpuInfo->utime = CompareFileTime(&pre_usrTm, &usrTm);
516
    cpuInfo->cutime = 0;
517
    cpuInfo->cstime = 0;
518
  }
519
#elif defined(DARWIN) || defined(TD_ASTRA)
520
  cpuInfo->stime = 0;
521
  cpuInfo->utime = 0;
522
  cpuInfo->cutime = 0;
523
  cpuInfo->cstime = 0;
524
#else
525
0
  TdFilePtr pFile = taosOpenFile(tsProcCpuFile, TD_FILE_READ | TD_FILE_STREAM);
526
0
  if (pFile == NULL) {
527
0
    return terrno;
528
0
  }
529
530
0
  char    line[1024] = {0};
531
0
  ssize_t bytes = taosGetsFile(pFile, sizeof(line), line);
532
0
  if (bytes < 0) {
533
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
534
0
    return code;
535
0
  }
536
537
0
  for (int i = 0, blank = 0; line[i] != 0; ++i) {
538
0
    if (line[i] == ' ') blank++;
539
0
    if (blank == PROCESS_ITEM) {
540
0
      code = sscanf(line + i + 1, "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &cpuInfo->utime, &cpuInfo->stime,
541
0
             &cpuInfo->cutime, &cpuInfo->cstime);
542
0
      if (EOF == code) {
543
0
        terrno = TAOS_SYSTEM_ERROR(ERRNO);
544
0
        return terrno;
545
0
      }
546
             
547
0
      break;
548
0
    }
549
0
  }
550
551
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
552
0
#endif
553
554
0
  return 0;
555
0
}
556
557
0
bool taosCheckSystemIsLittleEnd() {
558
0
  union check {
559
0
    int16_t i;
560
0
    char    ch[2];
561
0
  } c;
562
0
  c.i = 1;
563
0
  return c.ch[0] == 1;
564
0
}
565
566
0
void taosGetSystemInfo() {
567
#ifdef WINDOWS
568
  TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false));
569
  TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB));
570
  TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL));
571
#elif defined(_TD_DARWIN_64)
572
  long physical_pages = sysconf(_SC_PHYS_PAGES);
573
  long page_size = sysconf(_SC_PAGESIZE);
574
  tsTotalMemoryKB = physical_pages * page_size / 1024;
575
  tsPageSizeKB = page_size / 1024;
576
  tsNumOfCores = sysconf(_SC_NPROCESSORS_ONLN);
577
#elif defined(TD_ASTRA)
578
  taosGetProcIOnfos();
579
  TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false));
580
  TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB));
581
  TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL));
582
#else
583
0
  taosGetProcIOnfos();
584
0
  TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false)); 
585
0
  TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB));
586
0
  TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL));
587
0
  TAOS_SKIP_ERROR(taosGetCpuInstructions(&tsSSE42Supported, &tsAVXSupported, &tsAVX2Supported, &tsFMASupported, &tsAVX512Supported));
588
0
#endif
589
0
}
590
591
0
int32_t taosGetEmail(char *email, int32_t maxLen) {
592
0
  OS_PARAM_CHECK(email);
593
#ifdef WINDOWS
594
  return 0;
595
#elif defined(_TD_DARWIN_64)
596
#ifdef CUS_PROMPT
597
  const char *filepath = "/usr/local/"CUS_PROMPT"/email";
598
#else
599
  const char *filepath = "/usr/local/taos/email";
600
#endif  // CUS_PROMPT
601
602
  TdFilePtr pFile = taosOpenFile(filepath, TD_FILE_READ);
603
  if (pFile == NULL) return false;
604
605
  if (taosReadFile(pFile, (void *)email, maxLen) < 0) {
606
    taosCloseFile(&pFile);
607
    return terrno;
608
  }
609
610
  taosCloseFile(&pFile);
611
  return 0;
612
#else
613
0
#ifdef CUS_PROMPT
614
0
  const char *filepath = "/usr/local/"CUS_PROMPT"/email";
615
#else
616
  const char *filepath = "/usr/local/taos/email";
617
#endif  // CUS_PROMPT
618
619
0
  TdFilePtr pFile = taosOpenFile(filepath, TD_FILE_READ);
620
0
  if (pFile == NULL) return terrno;
621
622
0
  if (taosReadFile(pFile, (void *)email, maxLen) < 0) {
623
0
    int32_t code = terrno;
624
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
625
0
    return code;
626
0
  }
627
628
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
629
  
630
0
  return 0;
631
0
#endif
632
0
}
633
634
#ifdef WINDOWS
635
bool getWinVersionReleaseName(char *releaseName, int32_t maxLen) {
636
  if(releaseName == NULL) return false;
637
  TCHAR          szFileName[MAX_PATH];
638
  DWORD             dwHandle;
639
  DWORD             dwLen;
640
  LPVOID            lpData;
641
  UINT              uLen;
642
  VS_FIXEDFILEINFO *pFileInfo;
643
644
  int ret = GetWindowsDirectory(szFileName, MAX_PATH);
645
  if (ret == 0) {
646
    return false;
647
  }
648
  wsprintf(szFileName, L"%s%s", szFileName, L"\\explorer.exe");
649
  dwLen = GetFileVersionInfoSize(szFileName, &dwHandle);
650
  if (dwLen == 0) {
651
    return false;
652
  }
653
654
  lpData = malloc(dwLen);
655
  if (lpData == NULL) return false;
656
  if (!GetFileVersionInfo(szFileName, dwHandle, dwLen, lpData)) {
657
    free(lpData);
658
    return false;
659
  }
660
661
  if (!VerQueryValue(lpData, L"\\", (LPVOID *)&pFileInfo, &uLen)) {
662
    free(lpData);
663
    return false;
664
  }
665
666
  snprintf(releaseName, maxLen, "Windows %d.%d", HIWORD(pFileInfo->dwProductVersionMS),
667
           LOWORD(pFileInfo->dwProductVersionMS));
668
  free(lpData);
669
  return true;
670
}
671
#endif
672
673
0
int32_t taosGetOsReleaseName(char *releaseName, char* sName, char* ver, int32_t maxLen) {
674
0
  OS_PARAM_CHECK(releaseName);
675
#ifdef WINDOWS
676
  if (!getWinVersionReleaseName(releaseName, maxLen)) {
677
    snprintf(releaseName, maxLen, "Windows");
678
  }
679
  if(sName) snprintf(sName, maxLen, "Windows");
680
  return 0;
681
#elif defined(_TD_DARWIN_64)
682
  char osversion[32];
683
  size_t osversion_len = sizeof(osversion) - 1;
684
  int osversion_name[] = { CTL_KERN, KERN_OSRELEASE };
685
686
  if(sName) snprintf(sName, maxLen, "macOS");
687
  if (sysctl(osversion_name, 2, osversion, &osversion_len, NULL, 0) == -1) {
688
    return TAOS_SYSTEM_ERROR(ERRNO);
689
  }
690
691
  uint32_t major, minor;
692
  if (sscanf(osversion, "%u.%u", &major, &minor) == EOF) {
693
      return TAOS_SYSTEM_ERROR(ERRNO);
694
  }
695
  if (major >= 20) {
696
      major -= 9; // macOS 11 and newer
697
      snprintf(releaseName, maxLen, "macOS %u.%u", major, minor);
698
  } else {
699
      major -= 4; // macOS 10.1.1 and newer
700
      snprintf(releaseName, maxLen, "macOS 10.%d.%d", major, minor);
701
  }
702
703
  return 0;
704
#elif defined(TD_ASTRA) // TD_ASTRA_TODO
705
  if(sName) snprintf(sName, maxLen, "Astra");
706
  snprintf(releaseName, maxLen, "Astra");
707
  return 0;
708
#else
709
0
  char    line[1024];
710
0
  char   *dest = NULL;
711
0
  size_t  size = 0;
712
0
  int32_t code = 0;
713
0
  int32_t cnt = 0;
714
715
0
  TdFilePtr pFile = taosOpenFile("/etc/os-release", TD_FILE_READ | TD_FILE_STREAM);
716
0
  if (pFile == NULL) {
717
0
    return terrno;
718
0
  }
719
720
0
  while ((size = taosGetsFile(pFile, sizeof(line), line)) > 0) {
721
0
    line[size - 1] = '\0';
722
0
    if (strncmp(line, "NAME", 4) == 0) {
723
0
      dest = sName;
724
0
    } else if (strncmp(line, "PRETTY_NAME", 11) == 0) {
725
0
      dest = releaseName;
726
0
      code = 0;
727
0
    } else if (strncmp(line, "VERSION_ID", 10) == 0) {
728
0
      dest = ver;
729
0
    } else {
730
0
      continue;
731
0
    }
732
0
    if (!dest) continue;
733
0
    const char *p = strchr(line, '=') + 1;
734
0
    if (*p == '"') {
735
0
      p++;
736
0
      line[size - 2] = 0;
737
0
    }
738
0
    tstrncpy(dest, p, maxLen);
739
740
0
    if (++cnt >= 3) break;
741
0
  }
742
743
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
744
0
  return code;
745
0
#endif
746
0
}
747
748
0
int32_t taosGetCpuInfo(char *cpuModel, int32_t maxLen, float *numOfCores) {
749
0
  OS_PARAM_CHECK(cpuModel);
750
0
  OS_PARAM_CHECK(numOfCores);
751
#ifdef WINDOWS
752
  char  value[100];
753
  DWORD bufferSize = sizeof(value);
754
  LSTATUS ret = RegGetValue(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString",
755
              RRF_RT_ANY, NULL, (PVOID)&value, &bufferSize);
756
  if (ret != ERROR_SUCCESS) {
757
    return TAOS_SYSTEM_ERROR(ret);
758
  }
759
  tstrncpy(cpuModel, value, maxLen);
760
  SYSTEM_INFO si;
761
  memset(&si, 0, sizeof(SYSTEM_INFO));
762
  GetSystemInfo(&si);
763
  *numOfCores = si.dwNumberOfProcessors;
764
  return 0;
765
#elif defined(_TD_DARWIN_64)
766
  char    buf[16];
767
  int32_t done = 0;
768
  int32_t code = -1;
769
770
  TdCmdPtr pCmd = taosOpenCmd("sysctl -n machdep.cpu.brand_string");
771
  if (pCmd == NULL) return code;
772
  if (taosGetsCmd(pCmd, maxLen, cpuModel) > 0) {
773
    code = 0;
774
    done |= 1;
775
  }
776
  int endPos = strlen(cpuModel)-1;
777
  if (cpuModel[endPos] == '\n') {
778
    cpuModel[endPos] = '\0';
779
  }
780
  taosCloseCmd(&pCmd);
781
782
  pCmd = taosOpenCmd("sysctl -n machdep.cpu.core_count");
783
  if (pCmd == NULL) return code;
784
  memset(buf, 0, sizeof(buf));
785
  if (taosGetsCmd(pCmd, sizeof(buf) - 1, buf) > 0) {
786
    code = 0;
787
    done |= 2;
788
    *numOfCores = taosStr2Float(buf, NULL);
789
  }
790
  taosCloseCmd(&pCmd);
791
792
  return code;
793
#elif defined(TD_ASTRA) // TD_ASTRA_TODO
794
  tstrncpy(cpuModel, "ft_2000_4", maxLen);
795
  TAOS_SKIP_ERROR(taosGetCpuCores(numOfCores, false));
796
  return 0;
797
#else
798
0
  char    line[1024] = {0};
799
0
  size_t  size = 0;
800
0
  int32_t done = 0;
801
0
  int32_t code = 0;
802
0
  float   coreCount = 0;
803
804
0
  TdFilePtr pFile = taosOpenFile("/proc/cpuinfo", TD_FILE_READ | TD_FILE_STREAM);
805
0
  if (pFile == NULL) return terrno;
806
807
0
  while (done != 3 && (size = taosGetsFile(pFile, sizeof(line), line)) > 0) {
808
0
    line[size - 1] = '\0';
809
0
    if (((done & 1) == 0) && strncmp(line, "model name", 10) == 0) {
810
0
      const char *v = strchr(line, ':') + 2;
811
0
      tstrncpy(cpuModel, v, maxLen);
812
0
      code = 0;
813
0
      done |= 1;
814
0
    } else if (((done & 2) == 0) && strncmp(line, "cpu cores", 9) == 0) {
815
0
      const char *v = strchr(line, ':') + 2;
816
0
      *numOfCores = taosStr2Float(v, NULL);
817
0
      done |= 2;
818
0
    }
819
0
    if (strncmp(line, "processor", 9) == 0) coreCount += 1;
820
0
  }
821
822
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
823
824
0
  if (code != 0 && (done & 1) == 0) {
825
0
    TdFilePtr pFile1 = taosOpenFile("/proc/device-tree/model", TD_FILE_READ | TD_FILE_STREAM);
826
0
    if (pFile1 != NULL) {
827
0
      ssize_t bytes = taosGetsFile(pFile1, maxLen, cpuModel);
828
0
      TAOS_SKIP_ERROR(taosCloseFile(&pFile));
829
0
      if (bytes > 0) {
830
0
        code = 0;
831
0
        done |= 1;
832
0
      }
833
0
    }
834
0
  }
835
836
0
  if (code != 0 && (done & 1) == 0) {
837
0
    TdCmdPtr pCmd = taosOpenCmd("uname -a");
838
0
    if (pCmd == NULL) {
839
0
      return terrno;
840
0
    }
841
0
    if (taosGetsCmd(pCmd, maxLen, cpuModel) > 0) {
842
0
      code = 0;
843
0
      done |= 1;
844
0
    }
845
0
    taosCloseCmd(&pCmd);
846
0
  }
847
848
0
  if ((done & 2) == 0) {
849
0
    *numOfCores = coreCount;
850
0
    done |= 2;
851
0
  }
852
853
0
  return code;
854
0
#endif
855
0
}
856
857
#if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA)
858
// Try cgroup v2 cpu.max: format "$MAX $PERIOD" or "max $PERIOD"
859
0
static int32_t taosCntrGetCpuCoresV2(float *numOfCores) {
860
0
  TdFilePtr pFile = taosOpenFile(tsCgroupV2CpuMaxFile, TD_FILE_READ | TD_FILE_STREAM);
861
0
  if (pFile == NULL) return -1;
862
863
0
  char line[64] = {0};
864
0
  if (taosGetsFile(pFile, sizeof(line), line) <= 0) {
865
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
866
0
    return -1;
867
0
  }
868
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
869
870
  // "max" means no CPU limit
871
0
  if (strncmp(line, "max", 3) == 0) {
872
0
    return -1;
873
0
  }
874
875
0
  int64_t quota = 0, period = 0;
876
0
  if (sscanf(line, "%" PRId64 " %" PRId64, &quota, &period) != 2 || period <= 0 || quota <= 0) {
877
0
    return -1;
878
0
  }
879
880
0
  double quotaCores = (double)quota / (double)period;
881
0
  double sysCores = (double)sysconf(_SC_NPROCESSORS_ONLN);
882
0
  *numOfCores = (float)((quotaCores < sysCores && quotaCores > 0) ? quotaCores : sysCores);
883
0
  return (*numOfCores > 0) ? 0 : -1;
884
0
}
885
886
// Try cgroup v1 cpu.cfs_quota_us / cpu.cfs_period_us
887
0
static int32_t taosCntrGetCpuCoresV1(float *numOfCores) {
888
0
  TdFilePtr pFile = NULL;
889
0
  if (!(pFile = taosOpenFile(tsCpuQuotaFile, TD_FILE_READ | TD_FILE_STREAM))) {
890
0
    return -1;
891
0
  }
892
0
  char qline[32] = {0};
893
0
  if (taosGetsFile(pFile, sizeof(qline), qline) <= 0) {
894
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
895
0
    return -1;
896
0
  }
897
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
898
899
0
  int64_t quota = taosStr2Int64(qline, NULL, 10);
900
0
  if (quota < 0) {
901
0
    return -1;
902
0
  }
903
904
0
  if (!(pFile = taosOpenFile(tsCpuPeriodFile, TD_FILE_READ | TD_FILE_STREAM))) {
905
0
    return -1;
906
0
  }
907
0
  char pline[32] = {0};
908
0
  if (taosGetsFile(pFile, sizeof(pline), pline) <= 0) {
909
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
910
0
    return -1;
911
0
  }
912
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
913
914
0
  int64_t period = taosStr2Int64(pline, NULL, 10);
915
0
  if (period <= 0) return -1;
916
917
0
  double quotaCores = (double)quota / (double)period;
918
0
  double sysCores = (double)sysconf(_SC_NPROCESSORS_ONLN);
919
0
  *numOfCores = (float)((quotaCores < sysCores && quotaCores > 0) ? quotaCores : sysCores);
920
0
  return (*numOfCores > 0) ? 0 : -1;
921
0
}
922
#endif  // !WINDOWS && !_TD_DARWIN_64 && !TD_ASTRA
923
924
// Returns the container's CPU quota if successful, otherwise returns the physical CPU cores
925
0
static int32_t taosCntrGetCpuCores(float *numOfCores) {
926
#ifdef WINDOWS
927
  return TSDB_CODE_UNSUPPORT_OS;
928
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
929
  return TSDB_CODE_UNSUPPORT_OS;
930
#else
931
0
  int32_t cgroupVer = taosDetectCgroupVersion();
932
933
0
  if (cgroupVer == 2 && taosCntrGetCpuCoresV2(numOfCores) == 0) {
934
0
    return 0;
935
0
  }
936
0
  if (cgroupVer >= 1 && taosCntrGetCpuCoresV1(numOfCores) == 0) {
937
0
    return 0;
938
0
  }
939
940
0
  *numOfCores = sysconf(_SC_NPROCESSORS_ONLN);
941
0
  if(*numOfCores <= 0) {
942
0
    return TAOS_SYSTEM_ERROR(ERRNO);
943
0
  }
944
0
  return 0;
945
0
#endif
946
0
}
947
948
0
int32_t taosGetCpuCores(float *numOfCores, bool physical) {
949
0
  OS_PARAM_CHECK(numOfCores);
950
#ifdef WINDOWS
951
  SYSTEM_INFO info;
952
  GetSystemInfo(&info);
953
  *numOfCores = info.dwNumberOfProcessors;
954
  return  0;
955
#elif defined(_TD_DARWIN_64)
956
  *numOfCores = sysconf(_SC_NPROCESSORS_ONLN);
957
  if(*numOfCores <= 0) {
958
    return TAOS_SYSTEM_ERROR(ERRNO);
959
  }
960
  return 0;
961
#elif defined(TD_ASTRA) // TD_ASTRA_TODO
962
  *numOfCores = 4;
963
  return 0;
964
#else
965
0
  if (physical) {
966
0
    *numOfCores = sysconf(_SC_NPROCESSORS_ONLN);
967
0
    if(*numOfCores <= 0) {
968
0
      return TAOS_SYSTEM_ERROR(ERRNO);
969
0
    }
970
0
  } else {
971
0
    int code= taosCntrGetCpuCores(numOfCores);
972
0
    if(code != 0) {
973
0
      return code;
974
0
    }
975
0
  }
976
0
  return 0;
977
0
#endif
978
0
}
979
980
#if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA)
981
// Read cgroup CPU usage in microseconds. Returns 0 on success.
982
0
static int32_t taosGetCgroupCpuUsageUsec(int64_t *usageUsec) {
983
0
  if (usageUsec == NULL) return -1;
984
985
0
  int32_t cgroupVer = taosDetectCgroupVersion();
986
0
  if (cgroupVer == 2) {
987
    // cgroup v2: cpu.stat has "usage_usec <value>"
988
0
    TdFilePtr pFile = taosOpenFile(tsCgroupV2CpuStatFile, TD_FILE_READ | TD_FILE_STREAM);
989
0
    if (pFile == NULL) return -1;
990
0
    char line[256] = {0};
991
0
    while (taosGetsFile(pFile, sizeof(line), line) > 0) {
992
0
      if (strncmp(line, "usage_usec", 10) == 0) {
993
0
        if (sscanf(line + 10, " %" PRId64, usageUsec) != 1) {
994
0
          TAOS_SKIP_ERROR(taosCloseFile(&pFile));
995
0
          return -1;
996
0
        }
997
0
        TAOS_SKIP_ERROR(taosCloseFile(&pFile));
998
0
        return 0;
999
0
      }
1000
0
    }
1001
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1002
0
    return -1;
1003
0
  } else if (cgroupVer == 1) {
1004
    // cgroup v1: cpuacct.usage is in nanoseconds
1005
0
    int64_t usageNs = 0;
1006
0
    if (taosReadCgroupInt64(tsCgroupV1CpuAcctFile, &usageNs) == 0) {
1007
0
      *usageUsec = usageNs / 1000;
1008
0
      return 0;
1009
0
    }
1010
0
    return -1;
1011
0
  }
1012
0
  return -1;
1013
0
}
1014
#endif  // !WINDOWS && !_TD_DARWIN_64 && !TD_ASTRA
1015
1016
0
int32_t taosGetCpuUsage(double *cpu_system, double *cpu_engine) {
1017
0
  static int64_t lastSysUsed = -1;
1018
0
  static int64_t lastSysTotal = -1;
1019
0
  static int64_t lastProcTotal = -1;
1020
0
  static int64_t curSysUsed = 0;
1021
0
  static int64_t curSysTotal = 0;
1022
0
  static int64_t curProcTotal = 0;
1023
0
#if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA)
1024
0
  static int64_t lastCgroupUsageUsec = -1;
1025
0
  static int64_t lastWallTimeUsec = -1;
1026
0
#endif
1027
1028
0
  if (cpu_system != NULL) *cpu_system = 0;
1029
0
  if (cpu_engine != NULL) *cpu_engine = 0;
1030
1031
0
  bool    cgroupUsed = false;
1032
1033
0
#if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA)
1034
  // Try container-aware CPU usage first
1035
0
  int32_t cgroupVer = taosDetectCgroupVersion();
1036
0
  int64_t cgroupUsageUsec = 0;
1037
1038
0
  if (cgroupVer > 0 && taosGetCgroupCpuUsageUsec(&cgroupUsageUsec) == 0) {
1039
0
    struct timespec ts;
1040
0
    if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) goto _proc_stat;
1041
0
    int64_t wallTimeUsec = (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
1042
1043
0
    if (lastCgroupUsageUsec >= 0 && lastWallTimeUsec >= 0) {
1044
0
      int64_t deltaUsage = cgroupUsageUsec - lastCgroupUsageUsec;
1045
0
      int64_t deltaWall = wallTimeUsec - lastWallTimeUsec;
1046
0
      if (deltaWall > 0 && deltaUsage >= 0) {
1047
0
        float numCores = 0;
1048
0
        TAOS_SKIP_ERROR(taosGetCpuCores(&numCores, false));
1049
0
        if (numCores <= 0) numCores = 1;
1050
0
        if (cpu_system != NULL) {
1051
0
          *cpu_system = (double)deltaUsage / (double)deltaWall / numCores * 100.0;
1052
0
          if (*cpu_system > 100.0) *cpu_system = 100.0;
1053
0
        }
1054
0
        cgroupUsed = true;
1055
0
      }
1056
0
    }
1057
0
    lastCgroupUsageUsec = cgroupUsageUsec;
1058
0
    lastWallTimeUsec = wallTimeUsec;
1059
0
  }
1060
1061
0
_proc_stat:
1062
0
  ;
1063
0
#endif
1064
1065
0
  SysCpuInfo  sysCpu = {0};
1066
0
  ProcCpuInfo procCpu = {0};
1067
0
  if (taosGetSysCpuInfo(&sysCpu) == 0 && taosGetProcCpuInfo(&procCpu) == 0) {
1068
0
    curSysUsed = sysCpu.user + sysCpu.nice + sysCpu.system + sysCpu.wa + sysCpu.hi + sysCpu.si + sysCpu.st +
1069
0
                 sysCpu.guest + sysCpu.guest_nice;
1070
0
    curSysTotal = curSysUsed + sysCpu.idle;
1071
0
    curProcTotal = procCpu.utime + procCpu.stime + procCpu.cutime + procCpu.cstime;
1072
1073
0
    if(lastSysUsed >= 0 && lastSysTotal >=0 && lastProcTotal >=0){
1074
0
      if (curSysTotal - lastSysTotal > 0 && curSysUsed >= lastSysUsed && curProcTotal >= lastProcTotal) {
1075
0
        if (!cgroupUsed && cpu_system != NULL) {
1076
0
          *cpu_system = (curSysUsed - lastSysUsed) / (double)(curSysTotal - lastSysTotal) * 100;
1077
0
        }
1078
0
        if (cpu_engine != NULL) {
1079
0
          *cpu_engine = (curProcTotal - lastProcTotal) / (double)(curSysTotal - lastSysTotal) * 100;
1080
0
        }
1081
0
      }
1082
0
    }
1083
1084
0
    lastSysUsed = curSysUsed;
1085
0
    lastSysTotal = curSysTotal;
1086
0
    lastProcTotal = curProcTotal;
1087
0
  }
1088
0
  return 0;
1089
0
}
1090
1091
#define __cpuid_fix(level, a, b, c, d) \
1092
0
              __asm__("xor %%ecx, %%ecx\n" \
1093
0
                      "cpuid\n" \
1094
0
                      : "=a"(a), "=b"(b), "=c"(c), "=d"(d) \
1095
0
                      : "0"(level))
1096
1097
// todo add for windows and mac
1098
0
int32_t taosGetCpuInstructions(char* sse42, char* avx, char* avx2, char* fma, char* avx512) {
1099
#ifdef WINDOWS
1100
#elif defined(_TD_DARWIN_64)
1101
#else
1102
1103
0
#ifdef _TD_X86_
1104
  // Since the compiler is not support avx/avx2 instructions, the global variables always need to be
1105
  // set to be false
1106
0
  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
1107
1108
0
  int32_t ret = __get_cpuid(1, &eax, &ebx, &ecx, &edx);
1109
0
  if (ret == 0) {
1110
0
    return -1;  // failed to get the cpuid info
1111
0
  }
1112
1113
0
  *sse42 = (char) ((ecx & bit_SSE4_2) == bit_SSE4_2);
1114
0
  *avx   = (char) ((ecx & bit_AVX) == bit_AVX);
1115
0
  *fma   = (char) ((ecx & bit_FMA) == bit_FMA);
1116
1117
  // work around a bug in GCC.
1118
  // Ref to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77756
1119
0
  __cpuid_fix(7u, eax, ebx, ecx, edx);
1120
0
  *avx2 = (char) ((ebx & bit_AVX2) == bit_AVX2);
1121
0
  *avx512 = (char)((ebx & bit_AVX512F) == bit_AVX512F);
1122
0
#endif   // _TD_X86_
1123
0
#endif
1124
1125
0
  return 0;
1126
0
}
1127
1128
0
int32_t taosGetTotalMemory(int64_t *totalKB) {
1129
0
  OS_PARAM_CHECK(totalKB);
1130
#ifdef WINDOWS
1131
  MEMORYSTATUSEX memsStat;
1132
  memsStat.dwLength = sizeof(memsStat);
1133
  if (!GlobalMemoryStatusEx(&memsStat)) {
1134
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1135
  }
1136
1137
  *totalKB = memsStat.ullTotalPhys / 1024;
1138
  return 0;
1139
#elif defined(_TD_DARWIN_64)
1140
  return 0;
1141
#elif defined(TD_ASTRA) // TD_ASTRA_TODO
1142
  *totalKB = (int64_t)256 * 1024;
1143
  return 0;
1144
#else
1145
0
  int64_t pageSizeKB = tsPageSizeKB;
1146
0
  if (pageSizeKB <= 0) {
1147
0
    pageSizeKB = sysconf(_SC_PAGESIZE) / 1024;
1148
0
  }
1149
0
  *totalKB = (int64_t)(sysconf(_SC_PHYS_PAGES) * pageSizeKB);
1150
0
  if(*totalKB <= 0) {
1151
0
    return TAOS_SYSTEM_ERROR(ERRNO);
1152
0
  }
1153
1154
  // Apply cgroup memory limit if available
1155
0
  int32_t cgroupVer = taosDetectCgroupVersion();
1156
0
  int64_t cgroupLimitBytes = INT64_MAX;
1157
0
  if (cgroupVer == 2) {
1158
0
    TAOS_SKIP_ERROR(taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimitBytes));
1159
0
  } else if (cgroupVer == 1) {
1160
0
    TAOS_SKIP_ERROR(taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimitBytes));
1161
0
  }
1162
0
  if (cgroupLimitBytes > 0 && cgroupLimitBytes < INT64_MAX) {
1163
0
    int64_t cgroupLimitKB = cgroupLimitBytes / 1024;
1164
0
    if (cgroupLimitKB > 0 && cgroupLimitKB < *totalKB) {
1165
0
      *totalKB = cgroupLimitKB;
1166
0
    }
1167
0
  }
1168
1169
0
  return 0;
1170
0
#endif
1171
0
}
1172
1173
0
int32_t taosGetProcMemory(int64_t *usedKB) {
1174
0
  OS_PARAM_CHECK(usedKB);
1175
#ifdef WINDOWS
1176
  unsigned bytes_used = 0;
1177
1178
#if defined(_WIN64) && defined(_MSC_VER)
1179
  PROCESS_MEMORY_COUNTERS pmc;
1180
  HANDLE                  cur_proc = GetCurrentProcess();
1181
1182
  if (GetProcessMemoryInfo(cur_proc, &pmc, sizeof(pmc))) {
1183
    bytes_used = (unsigned)(pmc.WorkingSetSize + pmc.PagefileUsage);
1184
  }
1185
#endif
1186
1187
  *usedKB = bytes_used / 1024;
1188
  return 0;
1189
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1190
  *usedKB = 0;
1191
  return 0;
1192
#else
1193
0
  TdFilePtr pFile = taosOpenFile(tsProcMemFile, TD_FILE_READ | TD_FILE_STREAM);
1194
0
  if (pFile == NULL) {
1195
    // printf("open file:%s failed", tsProcMemFile);
1196
0
    return terrno;
1197
0
  }
1198
1199
0
  ssize_t bytes = 0;
1200
0
  char    line[1024] = {0};
1201
0
  while (!taosEOFFile(pFile)) {
1202
0
    bytes = taosGetsFile(pFile, sizeof(line), line);
1203
0
    if (bytes <= 0) {
1204
0
      break;
1205
0
    }
1206
0
    if (strstr(line, "VmRSS:") != NULL) {
1207
0
      break;
1208
0
    }
1209
0
  }
1210
1211
0
  char tmp[10];
1212
0
  (void)sscanf(line, "%s %" PRId64, tmp, usedKB);
1213
1214
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1215
  
1216
0
  return 0;
1217
0
#endif
1218
0
}
1219
1220
0
int32_t taosGetSysAvailMemory(int64_t *availSize) {
1221
#ifdef WINDOWS
1222
  MEMORYSTATUSEX memsStat;
1223
  memsStat.dwLength = sizeof(memsStat);
1224
  if (!GlobalMemoryStatusEx(&memsStat)) {
1225
    return -1;
1226
  }
1227
1228
  int64_t nMemFree = memsStat.ullAvailPhys;
1229
  int64_t nMemTotal = memsStat.ullTotalPhys;
1230
1231
  *availSize = nMemTotal - nMemFree;
1232
  return 0;
1233
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1234
  *availSize = 0;
1235
  return 0;
1236
#else
1237
  // Try cgroup-aware available memory first
1238
0
  int32_t cgroupVer = taosDetectCgroupVersion();
1239
0
  int64_t cgroupLimit = 0;
1240
0
  int64_t cgroupCurrent = 0;
1241
1242
0
  if (cgroupVer == 2) {
1243
0
    if (taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimit) == 0 &&
1244
0
        taosReadCgroupInt64(tsCgroupV2MemCurFile, &cgroupCurrent) == 0 &&
1245
0
        cgroupLimit > 0 && cgroupLimit < INT64_MAX) {
1246
0
      *availSize = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) : 0;
1247
0
      return 0;
1248
0
    }
1249
0
  } else if (cgroupVer == 1) {
1250
    // v1 uses a huge sentinel (near INT64_MAX) for "no limit"; also compare against physical memory
1251
0
    int64_t physMemBytes = (int64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
1252
0
    if (taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimit) == 0 &&
1253
0
        taosReadCgroupInt64(tsCgroupV1MemUsageFile, &cgroupCurrent) == 0 &&
1254
0
        cgroupLimit > 0 && cgroupLimit < INT64_MAX && cgroupLimit < physMemBytes) {
1255
0
      *availSize = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) : 0;
1256
0
      return 0;
1257
0
    }
1258
0
  }
1259
1260
  // Fallback to /proc/meminfo
1261
0
  TdFilePtr pFile = taosOpenFile("/proc/meminfo", TD_FILE_READ | TD_FILE_STREAM);
1262
0
  if (pFile == NULL) {
1263
0
    return terrno;
1264
0
  }
1265
1266
0
  ssize_t bytes = 0;
1267
0
  char    line[128] = {0};
1268
0
  int32_t expectedSize = 13; //"MemAvailable:"
1269
0
  while (!taosEOFFile(pFile)) {
1270
0
    bytes = taosGetsFile(pFile, sizeof(line), line);
1271
0
    if (bytes < 0) {
1272
0
      break;
1273
0
    }
1274
0
    if (line[0] != 'M' && line[3] != 'A') {
1275
0
      line[0] = 0;
1276
0
      continue;
1277
0
    }
1278
0
    if (0 == strncmp(line, "MemAvailable:", expectedSize)) {
1279
0
      break;
1280
0
    }
1281
0
  }
1282
1283
0
  if (0 == line[0]) {
1284
0
    return TSDB_CODE_UNSUPPORT_OS;
1285
0
  }
1286
  
1287
0
  char tmp[32];
1288
0
  (void)sscanf(line, "%s %" PRId64, tmp, availSize);
1289
1290
0
  *availSize *= 1024;
1291
  
1292
0
  (void)taosCloseFile(&pFile);
1293
0
  return 0;
1294
0
#endif
1295
0
}
1296
1297
0
static void taosGetMemValue(char* line, char* key, int64_t* value){
1298
0
  if(value == NULL) return;
1299
0
  *value = 0;
1300
0
  if(line == NULL || line[0] == '\0') return;
1301
1302
0
  char *colon_pos = strchr(line, ':');
1303
0
  if (colon_pos != NULL) {
1304
0
    *colon_pos = '\0';
1305
0
    if(sscanf(line, "%s", key) != 1){
1306
0
      key[0] = '\0';
1307
0
    }
1308
0
    if (sscanf(colon_pos + 1, "%" PRId64, value) != 1) {
1309
0
      *value = 0;
1310
0
    }
1311
0
  }
1312
0
}
1313
1314
// Read "inactive_file" from cgroup memory.stat
1315
0
static int64_t taosGetCgroupMemCache(const char *statFile) {
1316
0
  TdFilePtr pFile = taosOpenFile(statFile, TD_FILE_READ | TD_FILE_STREAM);
1317
0
  if (pFile == NULL) return 0;
1318
1319
0
  char    line[256] = {0};
1320
0
  int64_t inactiveFile = 0;
1321
0
  while (taosGetsFile(pFile, sizeof(line), line) > 0) {
1322
0
    if (strncmp(line, "inactive_file", 13) == 0) {
1323
0
      if (sscanf(line + 13, " %" PRId64, &inactiveFile) == 1) break;
1324
0
    }
1325
    // cgroup v1 uses "total_inactive_file"
1326
0
    if (strncmp(line, "total_inactive_file", 19) == 0) {
1327
0
      if (sscanf(line + 19, " %" PRId64, &inactiveFile) == 1) break;
1328
0
    }
1329
0
  }
1330
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1331
0
  return inactiveFile;
1332
0
}
1333
1334
0
int32_t taosGetSysMemory(int64_t *usedKB, int64_t *freeKB, int64_t *cacheBufferKB) {
1335
0
  OS_PARAM_CHECK(usedKB);
1336
0
  OS_PARAM_CHECK(freeKB);
1337
0
  OS_PARAM_CHECK(cacheBufferKB);
1338
#ifdef WINDOWS
1339
  MEMORYSTATUSEX memsStat;
1340
  memsStat.dwLength = sizeof(memsStat);
1341
  if (!GlobalMemoryStatusEx(&memsStat)) {
1342
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1343
  }
1344
1345
  int64_t nMemFree = memsStat.ullAvailPhys / 1024;
1346
  int64_t nMemTotal = memsStat.ullTotalPhys / 1024.0;
1347
1348
  *usedKB = nMemTotal - nMemFree;
1349
  *freeKB = nMemFree;
1350
  *cacheBufferKB = 0;
1351
  return 0;
1352
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) // TD_ASTRA_TODO
1353
  *usedKB = 0;
1354
  *freeKB = 0;
1355
  *cacheBufferKB = 0;
1356
  return 0;
1357
#else
1358
  // Try cgroup-aware memory stats first
1359
0
  int32_t cgroupVer = taosDetectCgroupVersion();
1360
0
  int64_t cgroupLimit = 0;
1361
0
  int64_t cgroupCurrent = 0;
1362
1363
0
  if (cgroupVer == 2) {
1364
0
    if (taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimit) == 0 &&
1365
0
        taosReadCgroupInt64(tsCgroupV2MemCurFile, &cgroupCurrent) == 0 &&
1366
0
        cgroupLimit > 0 && cgroupLimit < INT64_MAX) {
1367
0
      int64_t cache = taosGetCgroupMemCache(tsCgroupV2MemStatFile);
1368
0
      *cacheBufferKB = cache / 1024;
1369
0
      *usedKB = (cgroupCurrent > cache) ? (cgroupCurrent - cache) / 1024 : 0;
1370
0
      *freeKB = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) / 1024 : 0;
1371
0
      return 0;
1372
0
    }
1373
0
  } else if (cgroupVer == 1) {
1374
    // v1 uses a huge sentinel (near INT64_MAX) for "no limit"; also compare against physical memory
1375
0
    int64_t physMemBytes = (int64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
1376
0
    if (taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimit) == 0 &&
1377
0
        taosReadCgroupInt64(tsCgroupV1MemUsageFile, &cgroupCurrent) == 0 &&
1378
0
        cgroupLimit > 0 && cgroupLimit < INT64_MAX && cgroupLimit < physMemBytes) {
1379
0
      int64_t cache = taosGetCgroupMemCache(tsCgroupV1MemStatFile);
1380
0
      *cacheBufferKB = cache / 1024;
1381
0
      *usedKB = (cgroupCurrent > cache) ? (cgroupCurrent - cache) / 1024 : 0;
1382
0
      *freeKB = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) / 1024 : 0;
1383
0
      return 0;
1384
0
    }
1385
0
  }
1386
1387
  // Fallback to /proc/meminfo
1388
0
  TdFilePtr pFile = taosOpenFile("/proc/meminfo", TD_FILE_READ | TD_FILE_STREAM);
1389
0
  if (pFile == NULL) {
1390
0
    return terrno;
1391
0
  }
1392
1393
0
  char    line[1024] = {0};
1394
0
  char    key[1024] = {0};
1395
0
  int64_t  value = 0;
1396
0
  ssize_t bytes = 0;
1397
1398
  //MemTotal
1399
0
  int64_t total = 0;
1400
1401
  //MemFree
1402
0
  int64_t mfree = 0;
1403
1404
  //MemAvailable
1405
0
  int64_t available = 0;
1406
1407
  //Buffers
1408
0
  int64_t buffer = 0;
1409
1410
  //Cached
1411
0
  int64_t cached = 0;
1412
1413
  //SwapCached ,Active, Inactive, Active(anon), Inactive(anon), Active(file), Inactive(file), Unevictable, Mlocked, SwapTotal
1414
1415
  //SwapFree
1416
0
  int64_t swapFree = 0;
1417
1418
  //Dirty, Writeback, AnonPages, Mapped, Shmem, KReclaimable, Slab
1419
1420
  //SReclaimable
1421
0
  int64_t sReclaimable = 0;
1422
1423
0
  for(int32_t i=0; i < 30; i++){
1424
0
    bytes = taosGetsFile(pFile, sizeof(line), line);
1425
0
    if (bytes < 0) {
1426
0
      TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1427
0
      return terrno;
1428
0
    }
1429
0
    if (line[0] != 'M' && line[0] != 'B' && line[0] != 'C' && line[0] != 'S') {
1430
0
      line[0] = 0;
1431
0
      continue;
1432
0
    }
1433
0
    taosGetMemValue(line, key, &value);
1434
0
    if(strncmp(key, "MemTotal", 1024) == 0) {total = value; continue;}
1435
0
    if(strncmp(key, "MemFree", 1024) == 0) {mfree = value; continue;}
1436
0
    if(strncmp(key, "MemAvailable", 1024) == 0) {available = value; continue;}
1437
0
    if(strncmp(key, "Buffers", 1024) == 0) {buffer = value; continue;}
1438
0
    if(strncmp(key, "Cached", 1024) == 0) {cached = value; continue;}
1439
0
    if(strncmp(key, "SwapFree", 1024) == 0) {swapFree = value; continue;}
1440
0
    if(strncmp(key, "SReclaimable", 1024) == 0) {sReclaimable = value; continue;}
1441
0
  }
1442
1443
  //free   Unused memory (MemFree and SwapFree in /proc/meminfo)
1444
0
  *freeKB = mfree;
1445
  //buffers Memory used by kernel buffers (Buffers in /proc/meminfo)
1446
  //cache  Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
1447
0
  *cacheBufferKB = buffer + cached + sReclaimable;
1448
0
  *usedKB = total - *freeKB - *cacheBufferKB;
1449
  
1450
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1451
0
  return 0;
1452
0
#endif
1453
0
}
1454
1455
0
int32_t taosGetDiskSize(char *dataDir, SDiskSize *diskSize) {
1456
0
  OS_PARAM_CHECK(dataDir);
1457
0
  OS_PARAM_CHECK(diskSize);
1458
#if defined(WINDOWS)
1459
  unsigned _int64 i64FreeBytesToCaller;
1460
  unsigned _int64 i64TotalBytes;
1461
  unsigned _int64 i64FreeBytes;
1462
1463
  BOOL fResult = GetDiskFreeSpaceExA(dataDir, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes,
1464
                                     (PULARGE_INTEGER)&i64FreeBytes);
1465
  if (fResult) {
1466
    diskSize->total = (int64_t)(i64TotalBytes);
1467
    diskSize->avail = (int64_t)(i64FreeBytesToCaller);
1468
    diskSize->used = (int64_t)(i64TotalBytes - i64FreeBytes);
1469
    return 0;
1470
  } else {
1471
    // printf("failed to get disk size, dataDir:%s errno:%s", tsDataDir, strerror(ERRNO));
1472
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1473
    return terrno;
1474
  }
1475
#elif defined(_TD_DARWIN_64)
1476
  struct statvfs info;
1477
  if (statvfs(dataDir, &info)) {
1478
    // printf("failed to get disk size, dataDir:%s errno:%s", tsDataDir, strerror(ERRNO));
1479
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1480
    return terrno;
1481
  } else {
1482
    diskSize->total = info.f_blocks * info.f_frsize;
1483
    diskSize->avail = info.f_bavail * info.f_frsize;
1484
    diskSize->used = (info.f_blocks - info.f_bfree) * info.f_frsize;
1485
    return 0;
1486
  }
1487
#elif defined(TD_ASTRA)  // TD_ASTRA_TODO
1488
  //  if (-1 == ioctl(dataDir, FIOFSTATVFSGETBYNAME, &info)) { // TODO:try to check whether the API is available
1489
  //     terrno = TAOS_SYSTEM_ERROR(ERRNO);
1490
  //     return terrno;
1491
  diskSize->total = 100LL * 1024 * 1024 * 1024;
1492
  diskSize->avail = 50LL * 1024 * 1024 * 1024;
1493
  diskSize->used = 50LL * 1024 * 1024 * 1024;
1494
  //  } else {
1495
  //    diskSize->total = info.f_blocks * info.f_frsize;
1496
  //    diskSize->avail = info.f_bavail * info.f_frsize;
1497
  //    diskSize->used = diskSize->total - diskSize->avail;
1498
  //  }
1499
  return 0;
1500
#else
1501
0
  struct statvfs info;
1502
0
  if (-1 == statvfs(dataDir, &info)) {
1503
0
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1504
0
    return terrno;
1505
0
  } else {
1506
0
    diskSize->total = info.f_blocks * info.f_frsize;
1507
0
    diskSize->avail = info.f_bavail * info.f_frsize;
1508
0
    diskSize->used = diskSize->total - diskSize->avail;
1509
    
1510
0
    return 0;
1511
0
  }
1512
0
#endif
1513
0
}
1514
1515
0
int32_t taosGetProcIO(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) {
1516
0
  OS_PARAM_CHECK(rchars);
1517
0
  OS_PARAM_CHECK(wchars);
1518
0
  OS_PARAM_CHECK(read_bytes);
1519
0
  OS_PARAM_CHECK(write_bytes);
1520
#ifdef WINDOWS
1521
  IO_COUNTERS io_counter;
1522
  if (GetProcessIoCounters(GetCurrentProcess(), &io_counter)) {
1523
    *rchars = io_counter.ReadTransferCount;
1524
    *wchars = io_counter.WriteTransferCount;
1525
    *read_bytes = 0;
1526
    *write_bytes = 0;
1527
    return 0;
1528
  }
1529
  return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1530
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1531
  *rchars = 0;
1532
  *wchars = 0;
1533
  *read_bytes = 0;
1534
  *write_bytes = 0;
1535
  return 0;
1536
#else
1537
0
  TdFilePtr pFile = taosOpenFile(tsProcIOFile, TD_FILE_READ | TD_FILE_STREAM);
1538
0
  if (pFile == NULL) {
1539
0
    return terrno;
1540
0
  }
1541
1542
0
  ssize_t bytes = 0;
1543
0
  char    line[1024] = {0};
1544
0
  char    tmp[24];
1545
0
  int     readIndex = 0;
1546
1547
0
  while (!taosEOFFile(pFile)) {
1548
0
    bytes = taosGetsFile(pFile, sizeof(line), line);
1549
0
    if (bytes < 10) {
1550
0
      break;
1551
0
    }
1552
0
    if (strstr(line, "rchar:") != NULL) {
1553
0
      (void)sscanf(line, "%s %" PRId64, tmp, rchars);
1554
0
      readIndex++;
1555
0
    } else if (strstr(line, "wchar:") != NULL) {
1556
0
      (void)sscanf(line, "%s %" PRId64, tmp, wchars);
1557
0
      readIndex++;
1558
0
    } else if (strstr(line, "read_bytes:") != NULL) {  // read_bytes
1559
0
      (void)sscanf(line, "%s %" PRId64, tmp, read_bytes);
1560
0
      readIndex++;
1561
0
    } else if (strstr(line, "write_bytes:") != NULL) {  // write_bytes
1562
0
      (void)sscanf(line, "%s %" PRId64, tmp, write_bytes);
1563
0
      readIndex++;
1564
0
    } else {
1565
0
    }
1566
1567
0
    if (readIndex >= 4) break;
1568
0
  }
1569
1570
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1571
1572
0
  if (readIndex < 4) {
1573
0
    return -1;
1574
0
  }
1575
1576
0
  return 0;
1577
0
#endif
1578
0
}
1579
1580
0
int32_t taosGetProcIODelta(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) {
1581
0
  if (rchars == NULL || wchars == NULL || read_bytes == NULL || write_bytes == NULL) {
1582
0
    return TSDB_CODE_INVALID_PARA;
1583
0
  }
1584
0
  static int64_t last_rchars = -1;
1585
0
  static int64_t last_wchars = -1;
1586
0
  static int64_t last_read_bytes = -1;
1587
0
  static int64_t last_write_bytes = -1;
1588
0
  static int64_t cur_rchars = 0;
1589
0
  static int64_t cur_wchars = 0;
1590
0
  static int64_t cur_read_bytes = 0;
1591
0
  static int64_t cur_write_bytes = 0;
1592
0
  int32_t code = taosGetProcIO(&cur_rchars, &cur_wchars, &cur_read_bytes, &cur_write_bytes);
1593
0
  if (code == 0) {
1594
0
    if(last_rchars >=0 && last_wchars >=0 && last_read_bytes >=0 && last_write_bytes >= 0){
1595
0
      *rchars = cur_rchars - last_rchars;
1596
0
      *wchars = cur_wchars - last_wchars;
1597
0
      *read_bytes = cur_read_bytes - last_read_bytes;
1598
0
      *write_bytes = cur_write_bytes - last_write_bytes;
1599
0
    }
1600
0
    else{
1601
0
      *rchars = 0;
1602
0
      *wchars = 0;
1603
0
      *read_bytes = 0;
1604
0
      *write_bytes = 0;
1605
0
    }
1606
0
    last_rchars = cur_rchars;
1607
0
    last_wchars = cur_wchars;
1608
0
    last_read_bytes = cur_read_bytes;
1609
0
    last_write_bytes = cur_write_bytes;
1610
0
  } else {
1611
0
    return code;
1612
0
  }
1613
0
  return 0;
1614
0
}
1615
0
void taosSetDefaultProcIODelta(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) {
1616
0
  if(rchars) *rchars = 0;
1617
0
  if(wchars) *wchars = 0;
1618
0
  if(read_bytes) *read_bytes = 0;
1619
0
  if(write_bytes) *write_bytes = 0;
1620
0
}
1621
1622
0
int32_t taosGetCardInfo(int64_t *receive_bytes, int64_t *transmit_bytes) {
1623
0
  OS_PARAM_CHECK(receive_bytes);
1624
0
  OS_PARAM_CHECK(transmit_bytes);
1625
0
  *receive_bytes = 0;
1626
0
  *transmit_bytes = 0;
1627
1628
#ifdef WINDOWS
1629
  return 0;
1630
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1631
  return 0;
1632
#else
1633
0
  TdFilePtr pFile = taosOpenFile(tsSysNetFile, TD_FILE_READ | TD_FILE_STREAM);
1634
0
  if (pFile == NULL) {
1635
0
    return terrno;
1636
0
  }
1637
1638
0
  ssize_t _bytes = 0;
1639
0
  char    line[1024];
1640
1641
0
  while (!taosEOFFile(pFile)) {
1642
0
    int64_t o_rbytes = 0;
1643
0
    int64_t rpackts = 0;
1644
0
    int64_t o_tbytes = 0;
1645
0
    int64_t tpackets = 0;
1646
0
    int64_t nouse1 = 0;
1647
0
    int64_t nouse2 = 0;
1648
0
    int64_t nouse3 = 0;
1649
0
    int64_t nouse4 = 0;
1650
0
    int64_t nouse5 = 0;
1651
0
    int64_t nouse6 = 0;
1652
0
    char    nouse0[200] = {0};
1653
1654
0
    _bytes = taosGetsFile(pFile, sizeof(line), line);
1655
0
    if (_bytes <= 0) {
1656
0
      break;
1657
0
    }
1658
1659
0
    line[_bytes - 1] = 0;
1660
1661
0
    if (strstr(line, "lo:") != NULL) {
1662
0
      continue;
1663
0
    }
1664
1665
0
    (void)sscanf(line,
1666
0
           "%s %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64
1667
0
           " %" PRId64,
1668
0
           nouse0, &o_rbytes, &rpackts, &nouse1, &nouse2, &nouse3, &nouse4, &nouse5, &nouse6, &o_tbytes, &tpackets);
1669
0
    *receive_bytes += o_rbytes;
1670
0
    *transmit_bytes += o_tbytes;
1671
0
  }
1672
1673
0
  TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1674
1675
0
  return 0;
1676
0
#endif
1677
0
}
1678
1679
0
int32_t taosGetCardInfoDelta(int64_t *receive_bytes, int64_t *transmit_bytes) {
1680
0
  OS_PARAM_CHECK(receive_bytes);
1681
0
  OS_PARAM_CHECK(transmit_bytes);
1682
0
  static int64_t last_receive_bytes = -1;
1683
0
  static int64_t last_transmit_bytes = -1;
1684
0
  int64_t cur_receive_bytes = 0;
1685
0
  int64_t cur_transmit_bytes = 0;
1686
0
  int32_t code = taosGetCardInfo(&cur_receive_bytes, &cur_transmit_bytes);
1687
0
  if (code == 0) {
1688
0
    if(last_receive_bytes >= 0 && last_transmit_bytes >= 0){
1689
0
      *receive_bytes = cur_receive_bytes - last_receive_bytes;
1690
0
      *transmit_bytes = cur_transmit_bytes - last_transmit_bytes;
1691
0
    }
1692
0
    else{
1693
0
      *receive_bytes = 0;
1694
0
      *transmit_bytes = 0;
1695
0
    }
1696
1697
0
    last_receive_bytes = cur_receive_bytes;
1698
0
    last_transmit_bytes = cur_transmit_bytes;
1699
0
  } else {
1700
0
    return code;
1701
0
  }
1702
0
  return 0;
1703
0
}
1704
0
void taosSetDefaultCardInfoDelta(int64_t *receive_bytes, int64_t *transmit_bytes) {
1705
0
  if (receive_bytes) *receive_bytes = 0;
1706
0
  if (transmit_bytes) *transmit_bytes = 0;
1707
0
}
1708
1709
#if 0
1710
void taosKillSystem() {
1711
#ifdef WINDOWS
1712
  printf("function taosKillSystem, exit!");
1713
  exit(0);
1714
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1715
  printf("function taosKillSystem, exit!");
1716
  exit(0);
1717
#else
1718
  // SIGINT
1719
  (void)printf("%sd will shut down soon", CUS_PROMPT);
1720
  (void)kill(tsProcId, 2);
1721
#endif
1722
}
1723
#endif
1724
1725
0
#define UUIDLEN (36)
1726
0
int32_t taosGetSystemUUIDLimit36(char *uid, int32_t uidlen) {
1727
0
  OS_PARAM_CHECK(uid);
1728
#ifdef WINDOWS
1729
  GUID guid;
1730
  HRESULT h = CoCreateGuid(&guid);
1731
  if (h != S_OK) {
1732
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1733
  }
1734
  (void)snprintf(uid, uidlen, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid.Data1, guid.Data2, guid.Data3,
1735
           guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6],
1736
           guid.Data4[7]);
1737
1738
  return 0;
1739
#elif defined(_TD_DARWIN_64)
1740
  uuid_t uuid = {0};
1741
  char   buf[UUIDLEN37];
1742
  memset(buf, 0, UUIDLEN37);
1743
  uuid_generate(uuid);
1744
  // it's caller's responsibility to make enough space for `uid`, that's 36-char + 1-null
1745
  uuid_unparse_lower(uuid, buf);
1746
  (void)snprintf(uid, uidlen, "%.*s", (int)sizeof(buf), buf);
1747
  return 0;
1748
#elif defined(TD_ASTRA)
1749
  const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
1750
  const char *hex_chars = "0123456789abcdef";
1751
  int32_t     len = uidlen > 36 ? 36 : uidlen;
1752
1753
  for (int32_t i = 0; i < len; i++) {
1754
    if (template[i] == 'x') {
1755
      uid[i] = hex_chars[taosRand() & 15];
1756
    } else if (template[i] == 'y') {
1757
      uid[i] = hex_chars[(taosRand() & 3) + 8];  // 8, 9, a, or b
1758
    } else {
1759
      uid[i] = template[i];
1760
    }
1761
  }
1762
  if (len >= 0) {
1763
    uid[len] = 0;
1764
  }
1765
1766
  return 0;
1767
#else
1768
0
  int64_t len = 0;
1769
1770
  // fd = open("/proc/sys/kernel/random/uuid", 0);
1771
0
  TdFilePtr pFile = taosOpenFile("/proc/sys/kernel/random/uuid", TD_FILE_READ);
1772
0
  if (pFile == NULL) {
1773
0
    return terrno;
1774
0
  } else {
1775
0
    len = taosReadFile(pFile, uid, uidlen);
1776
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1777
0
    if (len < 0) {
1778
0
      return terrno;
1779
0
    }
1780
0
  }
1781
0
  if (len >= UUIDLEN + 1) {
1782
0
    uid[len - 1] = 0;
1783
0
  } else {
1784
0
    uid[uidlen - 1] = 0;
1785
0
  }
1786
1787
0
  return 0;
1788
0
#endif
1789
0
}
1790
1791
0
int32_t taosGetSystemUUIDLen(char *uid, int32_t uidlen) {
1792
0
  if (uid == NULL || uidlen <= 0) {
1793
0
    return TSDB_CODE_APP_ERROR;
1794
0
  }
1795
0
  int num = (uidlen % UUIDLEN == 0) ? (uidlen / UUIDLEN) : (uidlen / UUIDLEN + 1);
1796
0
  int left = uidlen;
1797
0
  for (int i = 0; i < num; ++i) {
1798
0
    int32_t code = taosGetSystemUUIDLimit36(uid + i * UUIDLEN, left);
1799
0
    if (code != 0) {
1800
0
      return code;
1801
0
    }
1802
0
    left -= UUIDLEN;
1803
0
  }
1804
0
  return TSDB_CODE_SUCCESS;
1805
0
}
1806
1807
0
char *taosGetCmdlineByPID(int pid) {
1808
#ifdef WINDOWS
1809
  return "";
1810
#elif defined(_TD_DARWIN_64)
1811
  static char cmdline[1024];
1812
  SET_ERRNO(0);
1813
1814
  if (proc_pidpath(pid, cmdline, sizeof(cmdline)) <= 0) {
1815
    fprintf(stderr, "PID is %d, %s", pid, strerror(ERRNO));
1816
    return strerror(ERRNO);
1817
  }
1818
1819
  return cmdline;
1820
#elif defined(TD_ASTRA)
1821
  return "";
1822
#else
1823
0
  static char cmdline[1024];
1824
0
  (void)snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
1825
1826
  // int fd = open(cmdline, O_RDONLY);
1827
0
  TdFilePtr pFile = taosOpenFile(cmdline, TD_FILE_READ);
1828
0
  if (pFile != NULL) {
1829
0
    int n = taosReadFile(pFile, cmdline, sizeof(cmdline) - 1);
1830
0
    if (n < 0) n = 0;
1831
1832
0
    if (n > 0 && cmdline[n - 1] == '\n') --n;
1833
1834
0
    cmdline[n] = 0;
1835
1836
0
    TAOS_SKIP_ERROR(taosCloseFile(&pFile));
1837
0
  } else {
1838
0
    cmdline[0] = 0;
1839
0
  }
1840
1841
0
  return cmdline;
1842
0
#endif
1843
0
}
1844
1845
0
int64_t taosGetOsUptime() {
1846
#ifdef WINDOWS
1847
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1848
#else
1849
0
  struct sysinfo info;
1850
0
  if (-1 == sysinfo(&info)) {
1851
0
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1852
0
    return terrno;
1853
0
  }
1854
  
1855
0
  return (int64_t)info.uptime * 1000;
1856
  
1857
0
#endif
1858
0
  return 0;
1859
0
}
1860
1861
0
void taosSetCoreDump(bool enable) {
1862
0
  if (!enable) return;
1863
#ifdef WINDOWS
1864
  /* Register vectored exception handler FIRST - it runs before SEH and can
1865
   * catch heap corruption (STATUS_HEAP_CORRUPTION 0xC0000374) which may
1866
   * bypass SetUnhandledExceptionFilter in some cases. */
1867
  AddVectoredExceptionHandler(1, FlVectoredExceptionHandler);
1868
  
1869
  /* Also set the unhandled exception filter for normal crashes */
1870
  SetUnhandledExceptionFilter(&FlCrashDump);
1871
  
1872
  /* Register CRT handlers for various runtime errors */
1873
  _set_invalid_parameter_handler(FlInvalidParameterHandler);
1874
  _set_purecall_handler(FlPureCallHandler);
1875
  
1876
  /* Handle abort() calls */
1877
  signal(SIGABRT, FlAbortHandler);
1878
  
1879
#elif defined(_TD_DARWIN_64) || defined(TD_ASTRA)
1880
#else
1881
  // 1. set ulimit -c unlimited
1882
0
  struct rlimit rlim;
1883
0
  struct rlimit rlim_new;
1884
0
  if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
1885
0
#ifndef _ALPINE
1886
    // printf("the old unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max);
1887
#else
1888
    // printf("the old unlimited para: rlim_cur=%llu, rlim_max=%llu", rlim.rlim_cur, rlim.rlim_max);
1889
#endif
1890
0
    rlim_new.rlim_cur = RLIM_INFINITY;
1891
0
    rlim_new.rlim_max = RLIM_INFINITY;
1892
0
    if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) {
1893
      // printf("set unlimited fail, error: %s", strerror(ERRNO));
1894
0
      rlim_new.rlim_cur = rlim.rlim_max;
1895
0
      rlim_new.rlim_max = rlim.rlim_max;
1896
0
      (void)setrlimit(RLIMIT_CORE, &rlim_new);
1897
0
    }
1898
0
  }
1899
1900
0
  if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
1901
0
#ifndef _ALPINE
1902
    // printf("the new unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max);
1903
#else
1904
    // printf("the new unlimited para: rlim_cur=%llu, rlim_max=%llu", rlim.rlim_cur, rlim.rlim_max);
1905
#endif
1906
0
  }
1907
1908
0
#ifndef _TD_ARM_
1909
  // 2. set the path for saving core file
1910
0
  struct __sysctl_args args;
1911
1912
0
  int    old_usespid = 0;
1913
0
  size_t old_len = 0;
1914
0
  int    new_usespid = 1;
1915
0
  size_t new_len = sizeof(new_usespid);
1916
1917
0
  int name[] = {CTL_KERN, KERN_CORE_USES_PID};
1918
1919
0
  (void)memset(&args, 0, sizeof(struct __sysctl_args));
1920
0
  args.name = name;
1921
0
  args.nlen = sizeof(name) / sizeof(name[0]);
1922
0
  args.oldval = &old_usespid;
1923
0
  args.oldlenp = &old_len;
1924
0
  args.newval = &new_usespid;
1925
0
  args.newlen = new_len;
1926
1927
0
  old_len = sizeof(old_usespid);
1928
1929
0
#ifndef __loongarch64
1930
0
  if (syscall(SYS__sysctl, &args) == -1) {
1931
    // printf("_sysctl(kern_core_uses_pid) set fail: %s", strerror(ERRNO));
1932
0
  }
1933
0
#endif
1934
1935
  // printf("The old core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid);
1936
1937
0
  old_usespid = 0;
1938
0
  old_len = 0;
1939
0
  (void)memset(&args, 0, sizeof(struct __sysctl_args));
1940
0
  args.name = name;
1941
0
  args.nlen = sizeof(name) / sizeof(name[0]);
1942
0
  args.oldval = &old_usespid;
1943
0
  args.oldlenp = &old_len;
1944
1945
0
  old_len = sizeof(old_usespid);
1946
1947
0
#ifndef __loongarch64
1948
0
  if (syscall(SYS__sysctl, &args) == -1) {
1949
    // printf("_sysctl(kern_core_uses_pid) get fail: %s", strerror(ERRNO));
1950
0
  }
1951
0
#endif
1952
1953
  // printf("The new core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid);
1954
0
#endif
1955
0
#endif
1956
0
}
1957
1958
0
SysNameInfo taosGetSysNameInfo() {
1959
#ifdef WINDOWS
1960
  SysNameInfo info = {0};
1961
  DWORD       dwVersion = GetVersion();
1962
1963
  char *tmp = NULL;
1964
  tmp = getenv("OS");
1965
  if (tmp != NULL) tstrncpy(info.sysname, tmp, sizeof(info.sysname));
1966
  tmp = getenv("COMPUTERNAME");
1967
  if (tmp != NULL) tstrncpy(info.nodename, tmp, sizeof(info.nodename));
1968
  sprintf_s(info.release, sizeof(info.release), "%d", dwVersion & 0x0F);
1969
  sprintf_s(info.version, sizeof(info.release), "%d", (dwVersion >> 8) & 0x0F);
1970
  tmp = getenv("PROCESSOR_ARCHITECTURE");
1971
  if (tmp != NULL) tstrncpy(info.machine, tmp, sizeof(info.machine));
1972
1973
  return info;
1974
#elif defined(_TD_DARWIN_64)
1975
  SysNameInfo info = {0};
1976
1977
  struct utsname uts;
1978
  if (!uname(&uts)) {
1979
    tstrncpy(info.sysname, uts.sysname, sizeof(info.sysname));
1980
    tstrncpy(info.nodename, uts.nodename, sizeof(info.nodename));
1981
    tstrncpy(info.release, uts.release, sizeof(info.release));
1982
    tstrncpy(info.version, uts.version, sizeof(info.version));
1983
    tstrncpy(info.machine, uts.machine, sizeof(info.machine));
1984
  }
1985
1986
  char     localHostName[512];
1987
  TAOS_SKIP_ERROR(taosGetlocalhostname(localHostName, 512));
1988
  TdCmdPtr pCmd = taosOpenCmd("scutil --get LocalHostName");
1989
  tstrncpy(info.nodename, localHostName, sizeof(info.nodename));
1990
1991
  return info;
1992
#else
1993
0
  SysNameInfo info = {0};
1994
0
  struct utsname uts;
1995
0
  if (!uname(&uts)) {
1996
0
    tstrncpy(info.sysname, uts.sysname, sizeof(info.sysname));
1997
0
    tstrncpy(info.nodename, uts.nodename, sizeof(info.nodename));
1998
0
    tstrncpy(info.release, uts.release, sizeof(info.release));
1999
0
    tstrncpy(info.version, uts.version, sizeof(info.version));
2000
0
    tstrncpy(info.machine, uts.machine, sizeof(info.machine));
2001
0
  } else {
2002
0
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
2003
0
  }
2004
2005
0
  return info;
2006
0
#endif
2007
0
}
2008
2009
0
bool taosCheckCurrentInDll() {
2010
#ifdef WINDOWS
2011
  MEMORY_BASIC_INFORMATION mbi;
2012
  char                     path[PATH_MAX] = {0};
2013
  GetModuleFileName(
2014
      ((VirtualQuery(taosCheckCurrentInDll, &mbi, sizeof(mbi)) != 0) ? (HMODULE)mbi.AllocationBase : NULL), path,
2015
      PATH_MAX);
2016
  int strLastIndex = strlen(path);
2017
  if ((path[strLastIndex - 3] == 'd' || path[strLastIndex - 3] == 'D') &&
2018
      (path[strLastIndex - 2] == 'l' || path[strLastIndex - 2] == 'L') &&
2019
      (path[strLastIndex - 1] == 'l' || path[strLastIndex - 1] == 'L')) {
2020
    return true;
2021
  }
2022
  return false;
2023
#else
2024
0
  return false;
2025
0
#endif
2026
0
}
2027
2028
#ifdef _TD_DARWIN_64
2029
int32_t taosGetMaclocalhostnameByCommand(char *hostname, size_t maxLen) {
2030
  TdCmdPtr pCmd = taosOpenCmd("scutil --get LocalHostName");
2031
  if (pCmd != NULL) {
2032
    if (taosGetsCmd(pCmd, maxLen - 1, hostname) > 0) {
2033
      int len = strlen(hostname);
2034
      if (hostname[len - 1] == '\n') {
2035
        hostname[len - 1] = '\0';
2036
      }
2037
      return 0;
2038
    }
2039
    taosCloseCmd(&pCmd);
2040
  }
2041
  return TAOS_SYSTEM_ERROR(ERRNO);
2042
}
2043
2044
int32_t getMacLocalHostNameBySCD(char *hostname, size_t maxLen) {
2045
  SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR(""), NULL, NULL);
2046
  CFStringRef       hostname_cfstr = SCDynamicStoreCopyLocalHostName(store);
2047
  if (hostname_cfstr != NULL) {
2048
    CFStringGetCString(hostname_cfstr, hostname, maxLen - 1, kCFStringEncodingMacRoman);
2049
    CFRelease(hostname_cfstr);
2050
  } else {
2051
    return -1;
2052
  }
2053
  CFRelease(store);
2054
  return 0;
2055
}
2056
#endif
2057
2058
0
int32_t taosGetlocalhostname(char *hostname, size_t maxLen) {
2059
0
  OS_PARAM_CHECK(hostname);
2060
#ifdef _TD_DARWIN_64
2061
  int res = getMacLocalHostNameBySCD(hostname, maxLen);
2062
  if (res != 0) {
2063
    return taosGetMaclocalhostnameByCommand(hostname, maxLen);
2064
  } else {
2065
    return 0;
2066
  }
2067
#else
2068
0
  int r = gethostname(hostname, maxLen);
2069
0
  if (-1 == r) {
2070
0
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
2071
0
    return terrno;
2072
0
  }
2073
0
  return r;
2074
0
#endif
2075
0
}