Coverage Report

Created: 2025-06-13 07:09

/src/server/mysys/my_init.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Copyright (c) 2000, 2012, Oracle and/or its affiliates
3
   Copyright (c) 2009, 2011, Monty Program Ab
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; version 2 of the License.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program; if not, write to the Free Software
16
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
17
18
#include "mysys_priv.h"
19
#include "my_static.h"
20
#include "mysys_err.h"
21
#include <m_string.h>
22
#include <m_ctype.h>
23
#include <signal.h>
24
#include <mysql/psi/mysql_stage.h>
25
#ifdef HAVE_UNISTD_H
26
#include <unistd.h>
27
#endif
28
#ifdef _WIN32
29
#ifdef _MSC_VER
30
#include <locale.h>
31
#include <crtdbg.h>
32
/* WSAStartup needs winsock library*/
33
#pragma comment(lib, "ws2_32")
34
#endif
35
static void my_win_init(void);
36
static my_bool win32_init_tcp_ip();
37
static void setup_codepages();
38
#else
39
#define my_win_init()
40
#endif
41
42
#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
43
#define _SC_PAGESIZE _SC_PAGE_SIZE
44
#endif
45
46
#if defined(__linux__)
47
0
#define EXE_LINKPATH "/proc/self/exe"
48
#elif defined(__FreeBSD__)
49
/* unfortunately, not mounted by default */
50
#define EXE_LINKPATH "/proc/curproc/file"
51
#endif
52
53
54
#define SCALE_SEC       100
55
#define SCALE_USEC      10000
56
57
my_bool my_init_done= 0;
58
uint  mysys_usage_id= 0;              /* Incremented for each my_init() */
59
size_t  my_system_page_size= 8192;  /* Default if no sysconf() */
60
61
ulonglong   my_thread_stack_size= (sizeof(void*) <= 4)? 65536: ((256-16)*1024);
62
63
static mode_t atoi_octal(const char *str)
64
0
{
65
0
  long int tmp;
66
0
  while (*str && my_isspace(&my_charset_latin1, *str))
67
0
    str++;
68
0
  str2int(str,
69
0
    (*str == '0' ? 8 : 10),       /* Octalt or decimalt */
70
0
    0, INT_MAX, &tmp);
71
0
  return (mode_t) tmp;
72
0
}
73
74
MYSQL_FILE *mysql_stdin= NULL;
75
static MYSQL_FILE instrumented_stdin;
76
77
#ifdef _WIN32
78
static UINT orig_console_cp, orig_console_output_cp;
79
80
static void reset_console_cp(void)
81
{
82
  /*
83
    We try not to call SetConsoleCP unnecessarily, to workaround a bug on
84
    older Windows 10 (1803), which could switch truetype console fonts to
85
    raster, eventhough SetConsoleCP would be a no-op (switch from UTF8 to UTF8).
86
  */
87
  if (GetConsoleCP() != orig_console_cp)
88
    SetConsoleCP(orig_console_cp);
89
  if (GetConsoleOutputCP() != orig_console_output_cp)
90
    SetConsoleOutputCP(orig_console_output_cp);
91
}
92
93
/*
94
  The below fixes discrepancies in console output and
95
  command line parameter encoding. command line is in
96
  ANSI codepage, output to console by default is in OEM, but
97
  we like them to be in the same encoding.
98
99
  We do this only if current codepage is UTF8, i.e when we
100
  know we're on Windows that can handle UTF8 well.
101
*/
102
static void setup_codepages()
103
{
104
  UINT acp;
105
  BOOL is_a_tty= fileno(stdout) >= 0 && isatty(fileno(stdout));
106
107
  if (is_a_tty)
108
  {
109
    /*
110
      Save console codepages, in case we change them,
111
      to restore them on exit.
112
    */
113
    orig_console_cp= GetConsoleCP();
114
    orig_console_output_cp= GetConsoleOutputCP();
115
    if (orig_console_cp && orig_console_output_cp)
116
      atexit(reset_console_cp);
117
  }
118
119
  if ((acp= GetACP()) != CP_UTF8)
120
    return;
121
122
  /*
123
    Use setlocale to make mbstowcs/mkdir/getcwd behave, see
124
    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale
125
  */
126
  setlocale(LC_ALL, "en_US.UTF8");
127
128
  if (is_a_tty && (orig_console_cp != acp || orig_console_output_cp != acp))
129
  {
130
    /*
131
      If ANSI codepage is UTF8, we actually want to switch console
132
      to it as well.
133
    */
134
    SetConsoleCP(acp);
135
    SetConsoleOutputCP(acp);
136
  }
137
}
138
#endif
139
140
/**
141
  Initialize my_sys functions, resources and variables
142
143
  @return Initialization result
144
    @retval 0 Success
145
    @retval 1 Error. Couldn't initialize environment
146
*/
147
my_bool my_init(void)
148
0
{
149
0
  char *str;
150
151
0
  if (my_init_done)
152
0
    return 0;
153
154
0
  my_init_done= 1;
155
156
0
  mysys_usage_id++;
157
0
  my_umask= 0660;                       /* Default umask for new files */
158
0
  my_umask_dir= 0700;                   /* Default umask for new directories */
159
0
  my_global_flags= 0;
160
0
  my_system_page_size= my_getpagesize();
161
162
  /* Default creation of new files */
163
0
  if ((str= getenv("UMASK")) != 0)
164
0
    my_umask= atoi_octal(str) | 0600;
165
  /* Default creation of new dir's */
166
0
  if ((str= getenv("UMASK_DIR")) != 0)
167
0
    my_umask_dir= atoi_octal(str) | 0700;
168
169
0
  init_glob_errs();
170
171
0
  instrumented_stdin.m_file= stdin;
172
0
  instrumented_stdin.m_psi= NULL;       /* not yet instrumented */
173
0
  mysql_stdin= & instrumented_stdin;
174
175
0
  my_progname_short= "unknown";
176
  /* Initialize our mutex handling */
177
0
  my_mutex_init();
178
179
0
  if (my_thread_global_init())
180
0
    return 1;
181
182
0
  if (my_progname)
183
0
  {
184
0
    char link_name[FN_REFLEN];
185
0
    my_progname_short= my_progname + dirname_length(my_progname);
186
    /*
187
      if my_progname_short doesn't start from "mariadb", but it's
188
      a symlink to an actual executable, that does - warn the user.
189
      First try to find the actual name via /proc, but if it's unmounted
190
      (which it usually is on FreeBSD) resort to my_progname
191
    */
192
0
    if (strncmp(my_progname_short, "mariadb", 7))
193
0
    {
194
0
      int res= 1;
195
0
#ifdef EXE_LINKPATH
196
0
      res= my_readlink(link_name, EXE_LINKPATH, MYF(0));
197
0
#endif
198
0
      if ((res == 0 || my_readlink(link_name, my_progname, MYF(0)) == 0) &&
199
0
           strncmp(link_name + dirname_length(link_name), "mariadb", 7) == 0)
200
0
      my_error(EE_NAME_DEPRECATED, MYF(MY_WME), link_name);
201
0
    }
202
0
  }
203
204
#if defined(SAFEMALLOC) && !defined(DBUG_OFF)
205
  dbug_sanity= sf_sanity;
206
#endif
207
208
  /* $HOME is needed early to parse configuration files located in ~/ */
209
0
  if ((home_dir= getenv("HOME")) != 0)
210
0
    home_dir= intern_filename(home_dir_buff, home_dir);
211
212
0
  {
213
0
    DBUG_ENTER("my_init");
214
0
    DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
215
0
    my_time_init();
216
0
    my_win_init();
217
0
    DBUG_PRINT("exit", ("home: '%s'", home_dir));
218
#ifdef _WIN32
219
    if (win32_init_tcp_ip())
220
      DBUG_RETURN(1);
221
#endif
222
#ifdef CHECK_UNLIKELY
223
    init_my_likely();
224
#endif
225
0
    DBUG_RETURN(0);
226
0
  }
227
0
} /* my_init */
228
229
230
  /* End my_sys */
231
232
void my_end(int infoflag)
233
0
{
234
  /*
235
    this code is suboptimal to workaround a bug in
236
    Sun CC: Sun C++ 5.6 2004/06/02 for x86, and should not be
237
    optimized until this compiler is not in use anymore
238
  */
239
0
  FILE *info_file= DBUG_FILE;
240
0
  my_bool print_info= (info_file != stderr);
241
242
0
  if (!my_init_done)
243
0
    return;
244
245
  /*
246
    We do not use DBUG_ENTER here, as after cleanup DBUG is no longer
247
    operational, so we cannot use DBUG_RETURN.
248
  */
249
0
  DBUG_PRINT("info",("Shutting down: infoflag: %d  print_info: %d",
250
0
                     infoflag, print_info));
251
0
  if (!info_file)
252
0
  {
253
0
    info_file= stderr;
254
0
    print_info= 0;
255
0
  }
256
257
0
  if ((infoflag & MY_CHECK_ERROR) || print_info)
258
0
  {                                     /* Test if some file is left open */
259
0
    char ebuff[512];
260
0
    uint i, open_files, open_streams;
261
262
0
    for (open_streams= open_files= i= 0 ; i < my_file_limit ; i++)
263
0
    {
264
0
      if (my_file_info[i].type == UNOPEN)
265
0
        continue;
266
0
      if (my_file_info[i].type == STREAM_BY_FOPEN ||
267
0
          my_file_info[i].type == STREAM_BY_FDOPEN)
268
0
        open_streams++;
269
0
      else
270
0
        open_files++;
271
272
#ifdef EXTRA_DEBUG
273
      fprintf(stderr, EE(EE_FILE_NOT_CLOSED), my_file_info[i].name, i);
274
      fputc('\n', stderr);
275
#endif
276
0
    }
277
0
    if (open_files || open_streams)
278
0
    {
279
0
      my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING),
280
0
                  open_files, open_streams);
281
0
      my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL);
282
0
      DBUG_PRINT("error", ("%s", ebuff));
283
0
    }
284
285
#ifdef CHECK_UNLIKELY
286
    end_my_likely(info_file);
287
#endif
288
0
  }
289
0
  free_charsets();
290
0
  my_error_unregister_all();
291
0
  my_once_free();
292
293
0
  if ((infoflag & MY_GIVE_INFO) || print_info)
294
0
  {
295
0
#ifdef HAVE_GETRUSAGE
296
0
    struct rusage rus;
297
#ifdef HAVE_valgrind
298
    /* Purify assumes that rus is uninitialized after getrusage call */
299
    bzero((char*) &rus, sizeof(rus));
300
#endif
301
0
    if (!getrusage(RUSAGE_SELF, &rus))
302
0
      fprintf(info_file,"\n\
303
0
User time %.2f, System time %.2f\n\
304
0
Maximum resident set size %ld, Integral resident set size %ld\n\
305
0
Non-physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\n\
306
0
Blocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\n\
307
0
Voluntary context switches %ld, Involuntary context switches %ld\n",
308
0
        (rus.ru_utime.tv_sec * SCALE_SEC +
309
0
         rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
310
0
        (rus.ru_stime.tv_sec * SCALE_SEC +
311
0
         rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
312
0
        rus.ru_maxrss, rus.ru_idrss,
313
0
        rus.ru_minflt, rus.ru_majflt,
314
0
        rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
315
0
        rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
316
0
        rus.ru_nvcsw, rus.ru_nivcsw);
317
0
#endif
318
#if defined(_MSC_VER)
319
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
320
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
321
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
322
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
323
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
324
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
325
   _CrtCheckMemory();
326
#endif
327
0
  }
328
329
0
  my_thread_end();
330
0
  my_thread_global_end();
331
332
0
  if (!(infoflag & MY_DONT_FREE_DBUG))
333
0
    DBUG_END();                /* Must be done as late as possible */
334
335
0
  my_mutex_end();
336
#if defined(SAFE_MUTEX)
337
  /*
338
    Check on destroying of mutexes. A few may be left that will get cleaned
339
    up by C++ destructors
340
  */
341
  safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
342
                 (FILE *) 0);
343
#endif /* defined(SAFE_MUTEX) */
344
345
#ifdef _WIN32
346
   WSACleanup();
347
#endif
348
 
349
  /* At very last, delete mysys key, it is used everywhere including DBUG */
350
0
  my_init_done= 0;
351
0
} /* my_end */
352
353
#ifdef DBUG_ASSERT_EXISTS
354
/* Dummy tag function for debugging */
355
356
void my_debug_put_break_here(void)
357
{
358
}
359
#endif
360
361
#ifdef _WIN32
362
363
364
/*
365
  my_parameter_handler
366
  
367
  Invalid parameter handler we will use instead of the one "baked"
368
  into the CRT.
369
*/
370
371
void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
372
                          const wchar_t * file, unsigned int line,
373
                          uintptr_t pReserved)
374
{
375
  __debugbreak();
376
}
377
378
379
#ifdef __MSVC_RUNTIME_CHECKS
380
#include <rtcapi.h>
381
382
/* Turn off runtime checks for 'handle_rtc_failure' */
383
#pragma runtime_checks("", off)
384
385
/*
386
  handle_rtc_failure
387
  Catch the RTC error and dump it to stderr
388
*/
389
390
int handle_rtc_failure(int err_type, const char *file, int line,
391
                       const char* module, const char *format, ...)
392
{
393
  va_list args;
394
  va_start(args, format);
395
  fprintf(stderr, "Error:");
396
  vfprintf(stderr, format, args);
397
  fprintf(stderr, " At %s:%d\n", file, line);
398
  va_end(args);
399
  (void) fflush(stderr);
400
  __debugbreak();
401
402
  return 0; /* Error is handled */
403
}
404
#pragma runtime_checks("", restore)
405
#endif
406
407
408
static void my_win_init(void)
409
{
410
  DBUG_ENTER("my_win_init");
411
412
#if defined(_MSC_VER)
413
  _set_invalid_parameter_handler(my_parameter_handler);
414
#endif
415
416
#ifdef __MSVC_RUNTIME_CHECKS
417
  /*
418
    Install handler to send RTC (Runtime Error Check) warnings
419
    to log file
420
  */
421
  _RTC_SetErrorFunc(handle_rtc_failure);
422
#endif
423
424
  _tzset();
425
426
  /* Disable automatic LF->CRLF translation. */
427
  FILE* stdf[]= {stdin, stdout, stderr};
428
  for (int i= 0; i < array_elements(stdf); i++)
429
  {
430
    int fd= fileno(stdf[i]);
431
    if (fd >= 0)
432
      (void) _setmode(fd, O_BINARY);
433
  }
434
  _set_fmode(O_BINARY);
435
  setup_codepages();
436
  DBUG_VOID_RETURN;
437
}
438
439
440
static my_bool win32_init_tcp_ip()
441
{
442
  WORD wVersionRequested = MAKEWORD( 2, 2 );
443
  WSADATA wsaData;
444
  if (WSAStartup(wVersionRequested, &wsaData))
445
  {
446
    fprintf(stderr, "WSAStartup() failed with error: %d\n", WSAGetLastError());
447
    return 1;
448
  }
449
  return(0);
450
}
451
#endif /* _WIN32 */
452
453
PSI_stage_info stage_waiting_for_table_level_lock=
454
{0, "Waiting for table level lock", 0};
455
456
#ifdef HAVE_PSI_INTERFACE
457
#if !defined(HAVE_PREAD) && !defined(_WIN32)
458
PSI_mutex_key key_my_file_info_mutex;
459
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
460
461
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
462
PSI_mutex_key key_LOCK_localtime_r;
463
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
464
465
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
466
  key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock,
467
  key_LOCK_timer,
468
  key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
469
  key_THR_LOCK_lock, key_THR_LOCK_malloc,
470
  key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
471
  key_THR_LOCK_open, key_THR_LOCK_threads,
472
  key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap, key_LOCK_uuid_generator;
473
474
static PSI_mutex_info all_mysys_mutexes[]=
475
{
476
#if !defined(HAVE_PREAD) && !defined(_WIN32)
477
  { &key_my_file_info_mutex, "st_my_file_info:mutex", 0},
478
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
479
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
480
  { &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
481
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
482
  { &key_BITMAP_mutex, "BITMAP::mutex", 0},
483
  { &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
484
  { &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
485
  { &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
486
  { &key_LOCK_timer, "LOCK_timer", PSI_FLAG_GLOBAL},
487
  { &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
488
  { &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
489
  { &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL},
490
  { &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL},
491
  { &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL},
492
  { &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0},
493
  { &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL},
494
  { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
495
  { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
496
  { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
497
  { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
498
  { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL},
499
  { &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL }
500
};
501
502
PSI_cond_key key_COND_timer, key_IO_CACHE_SHARE_cond,
503
  key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
504
  key_THR_COND_threads, key_WT_RESOURCE_cond;
505
506
static PSI_cond_info all_mysys_conds[]=
507
{
508
  { &key_COND_timer, "COND_timer", PSI_FLAG_GLOBAL},
509
  { &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
510
  { &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
511
  { &key_my_thread_var_suspend, "my_thread_var::suspend", 0},
512
  { &key_THR_COND_threads, "THR_COND_threads", PSI_FLAG_GLOBAL},
513
  { &key_WT_RESOURCE_cond, "WT_RESOURCE::cond", 0}
514
};
515
516
PSI_rwlock_key key_SAFEHASH_mutex;
517
518
static PSI_rwlock_info all_mysys_rwlocks[]=
519
{
520
  { &key_SAFEHASH_mutex, "SAFE_HASH::mutex", 0}
521
};
522
523
PSI_thread_key key_thread_timer;
524
525
static PSI_thread_info all_mysys_threads[]=
526
{
527
  { &key_thread_timer, "statement_timer", PSI_FLAG_GLOBAL}
528
};
529
530
531
PSI_file_key key_file_charset, key_file_cnf;
532
533
static PSI_file_info all_mysys_files[]=
534
{
535
  { &key_file_charset, "charset", 0},
536
  { &key_file_cnf, "cnf", 0}
537
};
538
539
PSI_stage_info *all_mysys_stages[]=
540
{
541
  & stage_waiting_for_table_level_lock
542
};
543
544
void my_init_mysys_psi_keys()
545
0
{
546
0
  const char* category= "mysys";
547
0
  int count;
548
549
0
  count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
550
0
  mysql_mutex_register(category, all_mysys_mutexes, count);
551
552
0
  count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
553
0
  mysql_cond_register(category, all_mysys_conds, count);
554
555
0
  count= sizeof(all_mysys_rwlocks)/sizeof(all_mysys_rwlocks[0]);
556
0
  mysql_rwlock_register(category, all_mysys_rwlocks, count);
557
558
0
  count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
559
0
  mysql_thread_register(category, all_mysys_threads, count);
560
561
0
  count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
562
0
  mysql_file_register(category, all_mysys_files, count);
563
564
0
  count= array_elements(all_mysys_stages);
565
0
  mysql_stage_register(category, all_mysys_stages, count);
566
0
}
567
#endif /* HAVE_PSI_INTERFACE */
568