/src/postgres/src/backend/utils/init/miscinit.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * miscinit.c |
4 | | * miscellaneous initialization support stuff |
5 | | * |
6 | | * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group |
7 | | * Portions Copyright (c) 1994, Regents of the University of California |
8 | | * |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/utils/init/miscinit.c |
12 | | * |
13 | | *------------------------------------------------------------------------- |
14 | | */ |
15 | | #include "postgres.h" |
16 | | |
17 | | #include <sys/param.h> |
18 | | #include <signal.h> |
19 | | #include <time.h> |
20 | | #include <sys/file.h> |
21 | | #include <sys/stat.h> |
22 | | #include <sys/time.h> |
23 | | #include <fcntl.h> |
24 | | #include <unistd.h> |
25 | | #include <grp.h> |
26 | | #include <pwd.h> |
27 | | #include <netinet/in.h> |
28 | | #include <arpa/inet.h> |
29 | | #include <utime.h> |
30 | | |
31 | | #include "access/htup_details.h" |
32 | | #include "access/parallel.h" |
33 | | #include "catalog/pg_authid.h" |
34 | | #include "common/file_perm.h" |
35 | | #include "libpq/libpq.h" |
36 | | #include "libpq/pqsignal.h" |
37 | | #include "mb/pg_wchar.h" |
38 | | #include "miscadmin.h" |
39 | | #include "pgstat.h" |
40 | | #include "postmaster/autovacuum.h" |
41 | | #include "postmaster/interrupt.h" |
42 | | #include "postmaster/postmaster.h" |
43 | | #include "replication/slotsync.h" |
44 | | #include "storage/fd.h" |
45 | | #include "storage/ipc.h" |
46 | | #include "storage/latch.h" |
47 | | #include "storage/pg_shmem.h" |
48 | | #include "storage/pmsignal.h" |
49 | | #include "storage/proc.h" |
50 | | #include "storage/procarray.h" |
51 | | #include "utils/builtins.h" |
52 | | #include "utils/guc.h" |
53 | | #include "utils/inval.h" |
54 | | #include "utils/memutils.h" |
55 | | #include "utils/pidfile.h" |
56 | | #include "utils/syscache.h" |
57 | | #include "utils/varlena.h" |
58 | | |
59 | | |
60 | 0 | #define DIRECTORY_LOCK_FILE "postmaster.pid" |
61 | | |
62 | | ProcessingMode Mode = InitProcessing; |
63 | | |
64 | | BackendType MyBackendType; |
65 | | |
66 | | /* List of lock files to be removed at proc exit */ |
67 | | static List *lock_files = NIL; |
68 | | |
69 | | static Latch LocalLatchData; |
70 | | |
71 | | /* ---------------------------------------------------------------- |
72 | | * ignoring system indexes support stuff |
73 | | * |
74 | | * NOTE: "ignoring system indexes" means we do not use the system indexes |
75 | | * for lookups (either in hardwired catalog accesses or in planner-generated |
76 | | * plans). We do, however, still update the indexes when a catalog |
77 | | * modification is made. |
78 | | * ---------------------------------------------------------------- |
79 | | */ |
80 | | |
81 | | bool IgnoreSystemIndexes = false; |
82 | | |
83 | | |
84 | | /* ---------------------------------------------------------------- |
85 | | * common process startup code |
86 | | * ---------------------------------------------------------------- |
87 | | */ |
88 | | |
89 | | /* |
90 | | * Initialize the basic environment for a postmaster child |
91 | | * |
92 | | * Should be called as early as possible after the child's startup. However, |
93 | | * on EXEC_BACKEND builds it does need to be after read_backend_variables(). |
94 | | */ |
95 | | void |
96 | | InitPostmasterChild(void) |
97 | 0 | { |
98 | 0 | IsUnderPostmaster = true; /* we are a postmaster subprocess now */ |
99 | | |
100 | | /* |
101 | | * Start our win32 signal implementation. This has to be done after we |
102 | | * read the backend variables, because we need to pick up the signal pipe |
103 | | * from the parent process. |
104 | | */ |
105 | | #ifdef WIN32 |
106 | | pgwin32_signal_initialize(); |
107 | | #endif |
108 | |
|
109 | 0 | InitProcessGlobals(); |
110 | | |
111 | | /* |
112 | | * make sure stderr is in binary mode before anything can possibly be |
113 | | * written to it, in case it's actually the syslogger pipe, so the pipe |
114 | | * chunking protocol isn't disturbed. Non-logpipe data gets translated on |
115 | | * redirection (e.g. via pg_ctl -l) anyway. |
116 | | */ |
117 | | #ifdef WIN32 |
118 | | _setmode(fileno(stderr), _O_BINARY); |
119 | | #endif |
120 | | |
121 | | /* We don't want the postmaster's proc_exit() handlers */ |
122 | 0 | on_exit_reset(); |
123 | | |
124 | | /* In EXEC_BACKEND case we will not have inherited BlockSig etc values */ |
125 | | #ifdef EXEC_BACKEND |
126 | | pqinitmask(); |
127 | | #endif |
128 | | |
129 | | /* Initialize process-local latch support */ |
130 | 0 | InitializeWaitEventSupport(); |
131 | 0 | InitProcessLocalLatch(); |
132 | 0 | InitializeLatchWaitSet(); |
133 | | |
134 | | /* |
135 | | * If possible, make this process a group leader, so that the postmaster |
136 | | * can signal any child processes too. Not all processes will have |
137 | | * children, but for consistency we make all postmaster child processes do |
138 | | * this. |
139 | | */ |
140 | 0 | #ifdef HAVE_SETSID |
141 | 0 | if (setsid() < 0) |
142 | 0 | elog(FATAL, "setsid() failed: %m"); |
143 | 0 | #endif |
144 | | |
145 | | /* |
146 | | * Every postmaster child process is expected to respond promptly to |
147 | | * SIGQUIT at all times. Therefore we centrally remove SIGQUIT from |
148 | | * BlockSig and install a suitable signal handler. (Client-facing |
149 | | * processes may choose to replace this default choice of handler with |
150 | | * quickdie().) All other blockable signals remain blocked for now. |
151 | | */ |
152 | 0 | pqsignal(SIGQUIT, SignalHandlerForCrashExit); |
153 | |
|
154 | 0 | sigdelset(&BlockSig, SIGQUIT); |
155 | 0 | sigprocmask(SIG_SETMASK, &BlockSig, NULL); |
156 | | |
157 | | /* Request a signal if the postmaster dies, if possible. */ |
158 | 0 | PostmasterDeathSignalInit(); |
159 | | |
160 | | /* Don't give the pipe to subprograms that we execute. */ |
161 | 0 | #ifndef WIN32 |
162 | 0 | if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFD, FD_CLOEXEC) < 0) |
163 | 0 | ereport(FATAL, |
164 | 0 | (errcode_for_socket_access(), |
165 | 0 | errmsg_internal("could not set postmaster death monitoring pipe to FD_CLOEXEC mode: %m"))); |
166 | 0 | #endif |
167 | 0 | } |
168 | | |
169 | | /* |
170 | | * Initialize the basic environment for a standalone process. |
171 | | * |
172 | | * argv0 has to be suitable to find the program's executable. |
173 | | */ |
174 | | void |
175 | | InitStandaloneProcess(const char *argv0) |
176 | 0 | { |
177 | 0 | Assert(!IsPostmasterEnvironment); |
178 | |
|
179 | 0 | MyBackendType = B_STANDALONE_BACKEND; |
180 | | |
181 | | /* |
182 | | * Start our win32 signal implementation |
183 | | */ |
184 | | #ifdef WIN32 |
185 | | pgwin32_signal_initialize(); |
186 | | #endif |
187 | |
|
188 | 0 | InitProcessGlobals(); |
189 | | |
190 | | /* Initialize process-local latch support */ |
191 | 0 | InitializeWaitEventSupport(); |
192 | 0 | InitProcessLocalLatch(); |
193 | 0 | InitializeLatchWaitSet(); |
194 | | |
195 | | /* |
196 | | * For consistency with InitPostmasterChild, initialize signal mask here. |
197 | | * But we don't unblock SIGQUIT or provide a default handler for it. |
198 | | */ |
199 | 0 | pqinitmask(); |
200 | 0 | sigprocmask(SIG_SETMASK, &BlockSig, NULL); |
201 | | |
202 | | /* Compute paths, no postmaster to inherit from */ |
203 | 0 | if (my_exec_path[0] == '\0') |
204 | 0 | { |
205 | 0 | if (find_my_exec(argv0, my_exec_path) < 0) |
206 | 0 | elog(FATAL, "%s: could not locate my own executable path", |
207 | 0 | argv0); |
208 | 0 | } |
209 | | |
210 | 0 | if (pkglib_path[0] == '\0') |
211 | 0 | get_pkglib_path(my_exec_path, pkglib_path); |
212 | 0 | } |
213 | | |
214 | | void |
215 | | SwitchToSharedLatch(void) |
216 | 0 | { |
217 | 0 | Assert(MyLatch == &LocalLatchData); |
218 | 0 | Assert(MyProc != NULL); |
219 | |
|
220 | 0 | MyLatch = &MyProc->procLatch; |
221 | |
|
222 | 0 | if (FeBeWaitSet) |
223 | 0 | ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET, |
224 | 0 | MyLatch); |
225 | | |
226 | | /* |
227 | | * Set the shared latch as the local one might have been set. This |
228 | | * shouldn't normally be necessary as code is supposed to check the |
229 | | * condition before waiting for the latch, but a bit care can't hurt. |
230 | | */ |
231 | 0 | SetLatch(MyLatch); |
232 | 0 | } |
233 | | |
234 | | void |
235 | | InitProcessLocalLatch(void) |
236 | 0 | { |
237 | 0 | MyLatch = &LocalLatchData; |
238 | 0 | InitLatch(MyLatch); |
239 | 0 | } |
240 | | |
241 | | void |
242 | | SwitchBackToLocalLatch(void) |
243 | 0 | { |
244 | 0 | Assert(MyLatch != &LocalLatchData); |
245 | 0 | Assert(MyProc != NULL && MyLatch == &MyProc->procLatch); |
246 | |
|
247 | 0 | MyLatch = &LocalLatchData; |
248 | |
|
249 | 0 | if (FeBeWaitSet) |
250 | 0 | ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET, |
251 | 0 | MyLatch); |
252 | |
|
253 | 0 | SetLatch(MyLatch); |
254 | 0 | } |
255 | | |
256 | | /* |
257 | | * Return a human-readable string representation of a BackendType. |
258 | | * |
259 | | * The string is not localized here, but we mark the strings for translation |
260 | | * so that callers can invoke _() on the result. |
261 | | */ |
262 | | const char * |
263 | | GetBackendTypeDesc(BackendType backendType) |
264 | 0 | { |
265 | 0 | const char *backendDesc = gettext_noop("unknown process type"); |
266 | |
|
267 | 0 | switch (backendType) |
268 | 0 | { |
269 | 0 | case B_INVALID: |
270 | 0 | backendDesc = gettext_noop("not initialized"); |
271 | 0 | break; |
272 | 0 | case B_ARCHIVER: |
273 | 0 | backendDesc = gettext_noop("archiver"); |
274 | 0 | break; |
275 | 0 | case B_AUTOVAC_LAUNCHER: |
276 | 0 | backendDesc = gettext_noop("autovacuum launcher"); |
277 | 0 | break; |
278 | 0 | case B_AUTOVAC_WORKER: |
279 | 0 | backendDesc = gettext_noop("autovacuum worker"); |
280 | 0 | break; |
281 | 0 | case B_BACKEND: |
282 | 0 | backendDesc = gettext_noop("client backend"); |
283 | 0 | break; |
284 | 0 | case B_DEAD_END_BACKEND: |
285 | 0 | backendDesc = gettext_noop("dead-end client backend"); |
286 | 0 | break; |
287 | 0 | case B_BG_WORKER: |
288 | 0 | backendDesc = gettext_noop("background worker"); |
289 | 0 | break; |
290 | 0 | case B_BG_WRITER: |
291 | 0 | backendDesc = gettext_noop("background writer"); |
292 | 0 | break; |
293 | 0 | case B_CHECKPOINTER: |
294 | 0 | backendDesc = gettext_noop("checkpointer"); |
295 | 0 | break; |
296 | 0 | case B_IO_WORKER: |
297 | 0 | backendDesc = gettext_noop("io worker"); |
298 | 0 | break; |
299 | 0 | case B_LOGGER: |
300 | 0 | backendDesc = gettext_noop("logger"); |
301 | 0 | break; |
302 | 0 | case B_SLOTSYNC_WORKER: |
303 | 0 | backendDesc = gettext_noop("slotsync worker"); |
304 | 0 | break; |
305 | 0 | case B_STANDALONE_BACKEND: |
306 | 0 | backendDesc = gettext_noop("standalone backend"); |
307 | 0 | break; |
308 | 0 | case B_STARTUP: |
309 | 0 | backendDesc = gettext_noop("startup"); |
310 | 0 | break; |
311 | 0 | case B_WAL_RECEIVER: |
312 | 0 | backendDesc = gettext_noop("walreceiver"); |
313 | 0 | break; |
314 | 0 | case B_WAL_SENDER: |
315 | 0 | backendDesc = gettext_noop("walsender"); |
316 | 0 | break; |
317 | 0 | case B_WAL_SUMMARIZER: |
318 | 0 | backendDesc = gettext_noop("walsummarizer"); |
319 | 0 | break; |
320 | 0 | case B_WAL_WRITER: |
321 | 0 | backendDesc = gettext_noop("walwriter"); |
322 | 0 | break; |
323 | 0 | } |
324 | | |
325 | 0 | return backendDesc; |
326 | 0 | } |
327 | | |
328 | | /* ---------------------------------------------------------------- |
329 | | * database path / name support stuff |
330 | | * ---------------------------------------------------------------- |
331 | | */ |
332 | | |
333 | | void |
334 | | SetDatabasePath(const char *path) |
335 | 0 | { |
336 | | /* This should happen only once per process */ |
337 | 0 | Assert(!DatabasePath); |
338 | 0 | DatabasePath = MemoryContextStrdup(TopMemoryContext, path); |
339 | 0 | } |
340 | | |
341 | | /* |
342 | | * Validate the proposed data directory. |
343 | | * |
344 | | * Also initialize file and directory create modes and mode mask. |
345 | | */ |
346 | | void |
347 | | checkDataDir(void) |
348 | 0 | { |
349 | 0 | struct stat stat_buf; |
350 | |
|
351 | 0 | Assert(DataDir); |
352 | |
|
353 | 0 | if (stat(DataDir, &stat_buf) != 0) |
354 | 0 | { |
355 | 0 | if (errno == ENOENT) |
356 | 0 | ereport(FATAL, |
357 | 0 | (errcode_for_file_access(), |
358 | 0 | errmsg("data directory \"%s\" does not exist", |
359 | 0 | DataDir))); |
360 | 0 | else |
361 | 0 | ereport(FATAL, |
362 | 0 | (errcode_for_file_access(), |
363 | 0 | errmsg("could not read permissions of directory \"%s\": %m", |
364 | 0 | DataDir))); |
365 | 0 | } |
366 | | |
367 | | /* eventual chdir would fail anyway, but let's test ... */ |
368 | 0 | if (!S_ISDIR(stat_buf.st_mode)) |
369 | 0 | ereport(FATAL, |
370 | 0 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
371 | 0 | errmsg("specified data directory \"%s\" is not a directory", |
372 | 0 | DataDir))); |
373 | | |
374 | | /* |
375 | | * Check that the directory belongs to my userid; if not, reject. |
376 | | * |
377 | | * This check is an essential part of the interlock that prevents two |
378 | | * postmasters from starting in the same directory (see CreateLockFile()). |
379 | | * Do not remove or weaken it. |
380 | | * |
381 | | * XXX can we safely enable this check on Windows? |
382 | | */ |
383 | 0 | #if !defined(WIN32) && !defined(__CYGWIN__) |
384 | 0 | if (stat_buf.st_uid != geteuid()) |
385 | 0 | ereport(FATAL, |
386 | 0 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
387 | 0 | errmsg("data directory \"%s\" has wrong ownership", |
388 | 0 | DataDir), |
389 | 0 | errhint("The server must be started by the user that owns the data directory."))); |
390 | 0 | #endif |
391 | | |
392 | | /* |
393 | | * Check if the directory has correct permissions. If not, reject. |
394 | | * |
395 | | * Only two possible modes are allowed, 0700 and 0750. The latter mode |
396 | | * indicates that group read/execute should be allowed on all newly |
397 | | * created files and directories. |
398 | | * |
399 | | * XXX temporarily suppress check when on Windows, because there may not |
400 | | * be proper support for Unix-y file permissions. Need to think of a |
401 | | * reasonable check to apply on Windows. |
402 | | */ |
403 | 0 | #if !defined(WIN32) && !defined(__CYGWIN__) |
404 | 0 | if (stat_buf.st_mode & PG_MODE_MASK_GROUP) |
405 | 0 | ereport(FATAL, |
406 | 0 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
407 | 0 | errmsg("data directory \"%s\" has invalid permissions", |
408 | 0 | DataDir), |
409 | 0 | errdetail("Permissions should be u=rwx (0700) or u=rwx,g=rx (0750)."))); |
410 | 0 | #endif |
411 | | |
412 | | /* |
413 | | * Reset creation modes and mask based on the mode of the data directory. |
414 | | * |
415 | | * The mask was set earlier in startup to disallow group permissions on |
416 | | * newly created files and directories. However, if group read/execute |
417 | | * are present on the data directory then modify the create modes and mask |
418 | | * to allow group read/execute on newly created files and directories and |
419 | | * set the data_directory_mode GUC. |
420 | | * |
421 | | * Suppress when on Windows, because there may not be proper support for |
422 | | * Unix-y file permissions. |
423 | | */ |
424 | 0 | #if !defined(WIN32) && !defined(__CYGWIN__) |
425 | 0 | SetDataDirectoryCreatePerm(stat_buf.st_mode); |
426 | |
|
427 | 0 | umask(pg_mode_mask); |
428 | 0 | data_directory_mode = pg_dir_create_mode; |
429 | 0 | #endif |
430 | | |
431 | | /* Check for PG_VERSION */ |
432 | 0 | ValidatePgVersion(DataDir); |
433 | 0 | } |
434 | | |
435 | | /* |
436 | | * Set data directory, but make sure it's an absolute path. Use this, |
437 | | * never set DataDir directly. |
438 | | */ |
439 | | void |
440 | | SetDataDir(const char *dir) |
441 | 0 | { |
442 | 0 | char *new; |
443 | |
|
444 | 0 | Assert(dir); |
445 | | |
446 | | /* If presented path is relative, convert to absolute */ |
447 | 0 | new = make_absolute_path(dir); |
448 | |
|
449 | 0 | free(DataDir); |
450 | 0 | DataDir = new; |
451 | 0 | } |
452 | | |
453 | | /* |
454 | | * Change working directory to DataDir. Most of the postmaster and backend |
455 | | * code assumes that we are in DataDir so it can use relative paths to access |
456 | | * stuff in and under the data directory. For convenience during path |
457 | | * setup, however, we don't force the chdir to occur during SetDataDir. |
458 | | */ |
459 | | void |
460 | | ChangeToDataDir(void) |
461 | 0 | { |
462 | 0 | Assert(DataDir); |
463 | |
|
464 | 0 | if (chdir(DataDir) < 0) |
465 | 0 | ereport(FATAL, |
466 | 0 | (errcode_for_file_access(), |
467 | 0 | errmsg("could not change directory to \"%s\": %m", |
468 | 0 | DataDir))); |
469 | 0 | } |
470 | | |
471 | | |
472 | | /* ---------------------------------------------------------------- |
473 | | * User ID state |
474 | | * |
475 | | * We have to track several different values associated with the concept |
476 | | * of "user ID". |
477 | | * |
478 | | * AuthenticatedUserId is determined at connection start and never changes. |
479 | | * |
480 | | * SessionUserId is initially the same as AuthenticatedUserId, but can be |
481 | | * changed by SET SESSION AUTHORIZATION (if AuthenticatedUserId is a |
482 | | * superuser). This is the ID reported by the SESSION_USER SQL function. |
483 | | * |
484 | | * OuterUserId is the current user ID in effect at the "outer level" (outside |
485 | | * any transaction or function). This is initially the same as SessionUserId, |
486 | | * but can be changed by SET ROLE to any role that SessionUserId is a |
487 | | * member of. (XXX rename to something like CurrentRoleId?) |
488 | | * |
489 | | * CurrentUserId is the current effective user ID; this is the one to use |
490 | | * for all normal permissions-checking purposes. At outer level this will |
491 | | * be the same as OuterUserId, but it changes during calls to SECURITY |
492 | | * DEFINER functions, as well as locally in some specialized commands. |
493 | | * |
494 | | * SecurityRestrictionContext holds flags indicating reason(s) for changing |
495 | | * CurrentUserId. In some cases we need to lock down operations that are |
496 | | * not directly controlled by privilege settings, and this provides a |
497 | | * convenient way to do it. |
498 | | * ---------------------------------------------------------------- |
499 | | */ |
500 | | static Oid AuthenticatedUserId = InvalidOid; |
501 | | static Oid SessionUserId = InvalidOid; |
502 | | static Oid OuterUserId = InvalidOid; |
503 | | static Oid CurrentUserId = InvalidOid; |
504 | | static const char *SystemUser = NULL; |
505 | | |
506 | | /* We also have to remember the superuser state of the session user */ |
507 | | static bool SessionUserIsSuperuser = false; |
508 | | |
509 | | static int SecurityRestrictionContext = 0; |
510 | | |
511 | | /* We also remember if a SET ROLE is currently active */ |
512 | | static bool SetRoleIsActive = false; |
513 | | |
514 | | /* |
515 | | * GetUserId - get the current effective user ID. |
516 | | * |
517 | | * Note: there's no SetUserId() anymore; use SetUserIdAndSecContext(). |
518 | | */ |
519 | | Oid |
520 | | GetUserId(void) |
521 | 0 | { |
522 | 0 | Assert(OidIsValid(CurrentUserId)); |
523 | 0 | return CurrentUserId; |
524 | 0 | } |
525 | | |
526 | | |
527 | | /* |
528 | | * GetOuterUserId/SetOuterUserId - get/set the outer-level user ID. |
529 | | */ |
530 | | Oid |
531 | | GetOuterUserId(void) |
532 | 0 | { |
533 | 0 | Assert(OidIsValid(OuterUserId)); |
534 | 0 | return OuterUserId; |
535 | 0 | } |
536 | | |
537 | | |
538 | | static void |
539 | | SetOuterUserId(Oid userid, bool is_superuser) |
540 | 0 | { |
541 | 0 | Assert(SecurityRestrictionContext == 0); |
542 | 0 | Assert(OidIsValid(userid)); |
543 | 0 | OuterUserId = userid; |
544 | | |
545 | | /* We force the effective user ID to match, too */ |
546 | 0 | CurrentUserId = userid; |
547 | | |
548 | | /* Also update the is_superuser GUC to match OuterUserId's property */ |
549 | 0 | SetConfigOption("is_superuser", |
550 | 0 | is_superuser ? "on" : "off", |
551 | 0 | PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT); |
552 | 0 | } |
553 | | |
554 | | |
555 | | /* |
556 | | * GetSessionUserId/SetSessionUserId - get/set the session user ID. |
557 | | */ |
558 | | Oid |
559 | | GetSessionUserId(void) |
560 | 0 | { |
561 | 0 | Assert(OidIsValid(SessionUserId)); |
562 | 0 | return SessionUserId; |
563 | 0 | } |
564 | | |
565 | | bool |
566 | | GetSessionUserIsSuperuser(void) |
567 | 0 | { |
568 | 0 | Assert(OidIsValid(SessionUserId)); |
569 | 0 | return SessionUserIsSuperuser; |
570 | 0 | } |
571 | | |
572 | | static void |
573 | | SetSessionUserId(Oid userid, bool is_superuser) |
574 | 0 | { |
575 | 0 | Assert(SecurityRestrictionContext == 0); |
576 | 0 | Assert(OidIsValid(userid)); |
577 | 0 | SessionUserId = userid; |
578 | 0 | SessionUserIsSuperuser = is_superuser; |
579 | 0 | } |
580 | | |
581 | | /* |
582 | | * Return the system user representing the authenticated identity. |
583 | | * It is defined in InitializeSystemUser() as auth_method:authn_id. |
584 | | */ |
585 | | const char * |
586 | | GetSystemUser(void) |
587 | 0 | { |
588 | 0 | return SystemUser; |
589 | 0 | } |
590 | | |
591 | | /* |
592 | | * GetAuthenticatedUserId/SetAuthenticatedUserId - get/set the authenticated |
593 | | * user ID |
594 | | */ |
595 | | Oid |
596 | | GetAuthenticatedUserId(void) |
597 | 0 | { |
598 | 0 | Assert(OidIsValid(AuthenticatedUserId)); |
599 | 0 | return AuthenticatedUserId; |
600 | 0 | } |
601 | | |
602 | | void |
603 | | SetAuthenticatedUserId(Oid userid) |
604 | 0 | { |
605 | 0 | Assert(OidIsValid(userid)); |
606 | | |
607 | | /* call only once */ |
608 | 0 | Assert(!OidIsValid(AuthenticatedUserId)); |
609 | |
|
610 | 0 | AuthenticatedUserId = userid; |
611 | | |
612 | | /* Also mark our PGPROC entry with the authenticated user id */ |
613 | | /* (We assume this is an atomic store so no lock is needed) */ |
614 | 0 | MyProc->roleId = userid; |
615 | 0 | } |
616 | | |
617 | | |
618 | | /* |
619 | | * GetUserIdAndSecContext/SetUserIdAndSecContext - get/set the current user ID |
620 | | * and the SecurityRestrictionContext flags. |
621 | | * |
622 | | * Currently there are three valid bits in SecurityRestrictionContext: |
623 | | * |
624 | | * SECURITY_LOCAL_USERID_CHANGE indicates that we are inside an operation |
625 | | * that is temporarily changing CurrentUserId via these functions. This is |
626 | | * needed to indicate that the actual value of CurrentUserId is not in sync |
627 | | * with guc.c's internal state, so SET ROLE has to be disallowed. |
628 | | * |
629 | | * SECURITY_RESTRICTED_OPERATION indicates that we are inside an operation |
630 | | * that does not wish to trust called user-defined functions at all. The |
631 | | * policy is to use this before operations, e.g. autovacuum and REINDEX, that |
632 | | * enumerate relations of a database or schema and run functions associated |
633 | | * with each found relation. The relation owner is the new user ID. Set this |
634 | | * as soon as possible after locking the relation. Restore the old user ID as |
635 | | * late as possible before closing the relation; restoring it shortly after |
636 | | * close is also tolerable. If a command has both relation-enumerating and |
637 | | * non-enumerating modes, e.g. ANALYZE, both modes set this bit. This bit |
638 | | * prevents not only SET ROLE, but various other changes of session state that |
639 | | * normally is unprotected but might possibly be used to subvert the calling |
640 | | * session later. An example is replacing an existing prepared statement with |
641 | | * new code, which will then be executed with the outer session's permissions |
642 | | * when the prepared statement is next used. These restrictions are fairly |
643 | | * draconian, but the functions called in relation-enumerating operations are |
644 | | * really supposed to be side-effect-free anyway. |
645 | | * |
646 | | * SECURITY_NOFORCE_RLS indicates that we are inside an operation which should |
647 | | * ignore the FORCE ROW LEVEL SECURITY per-table indication. This is used to |
648 | | * ensure that FORCE RLS does not mistakenly break referential integrity |
649 | | * checks. Note that this is intentionally only checked when running as the |
650 | | * owner of the table (which should always be the case for referential |
651 | | * integrity checks). |
652 | | * |
653 | | * Unlike GetUserId, GetUserIdAndSecContext does *not* Assert that the current |
654 | | * value of CurrentUserId is valid; nor does SetUserIdAndSecContext require |
655 | | * the new value to be valid. In fact, these routines had better not |
656 | | * ever throw any kind of error. This is because they are used by |
657 | | * StartTransaction and AbortTransaction to save/restore the settings, |
658 | | * and during the first transaction within a backend, the value to be saved |
659 | | * and perhaps restored is indeed invalid. We have to be able to get |
660 | | * through AbortTransaction without asserting in case InitPostgres fails. |
661 | | */ |
662 | | void |
663 | | GetUserIdAndSecContext(Oid *userid, int *sec_context) |
664 | 0 | { |
665 | 0 | *userid = CurrentUserId; |
666 | 0 | *sec_context = SecurityRestrictionContext; |
667 | 0 | } |
668 | | |
669 | | void |
670 | | SetUserIdAndSecContext(Oid userid, int sec_context) |
671 | 0 | { |
672 | 0 | CurrentUserId = userid; |
673 | 0 | SecurityRestrictionContext = sec_context; |
674 | 0 | } |
675 | | |
676 | | |
677 | | /* |
678 | | * InLocalUserIdChange - are we inside a local change of CurrentUserId? |
679 | | */ |
680 | | bool |
681 | | InLocalUserIdChange(void) |
682 | 0 | { |
683 | 0 | return (SecurityRestrictionContext & SECURITY_LOCAL_USERID_CHANGE) != 0; |
684 | 0 | } |
685 | | |
686 | | /* |
687 | | * InSecurityRestrictedOperation - are we inside a security-restricted command? |
688 | | */ |
689 | | bool |
690 | | InSecurityRestrictedOperation(void) |
691 | 0 | { |
692 | 0 | return (SecurityRestrictionContext & SECURITY_RESTRICTED_OPERATION) != 0; |
693 | 0 | } |
694 | | |
695 | | /* |
696 | | * InNoForceRLSOperation - are we ignoring FORCE ROW LEVEL SECURITY ? |
697 | | */ |
698 | | bool |
699 | | InNoForceRLSOperation(void) |
700 | 0 | { |
701 | 0 | return (SecurityRestrictionContext & SECURITY_NOFORCE_RLS) != 0; |
702 | 0 | } |
703 | | |
704 | | |
705 | | /* |
706 | | * These are obsolete versions of Get/SetUserIdAndSecContext that are |
707 | | * only provided for bug-compatibility with some rather dubious code in |
708 | | * pljava. We allow the userid to be set, but only when not inside a |
709 | | * security restriction context. |
710 | | */ |
711 | | void |
712 | | GetUserIdAndContext(Oid *userid, bool *sec_def_context) |
713 | 0 | { |
714 | 0 | *userid = CurrentUserId; |
715 | 0 | *sec_def_context = InLocalUserIdChange(); |
716 | 0 | } |
717 | | |
718 | | void |
719 | | SetUserIdAndContext(Oid userid, bool sec_def_context) |
720 | 0 | { |
721 | | /* We throw the same error SET ROLE would. */ |
722 | 0 | if (InSecurityRestrictedOperation()) |
723 | 0 | ereport(ERROR, |
724 | 0 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
725 | 0 | errmsg("cannot set parameter \"%s\" within security-restricted operation", |
726 | 0 | "role"))); |
727 | 0 | CurrentUserId = userid; |
728 | 0 | if (sec_def_context) |
729 | 0 | SecurityRestrictionContext |= SECURITY_LOCAL_USERID_CHANGE; |
730 | 0 | else |
731 | 0 | SecurityRestrictionContext &= ~SECURITY_LOCAL_USERID_CHANGE; |
732 | 0 | } |
733 | | |
734 | | |
735 | | /* |
736 | | * Check whether specified role has explicit REPLICATION privilege |
737 | | */ |
738 | | bool |
739 | | has_rolreplication(Oid roleid) |
740 | 0 | { |
741 | 0 | bool result = false; |
742 | 0 | HeapTuple utup; |
743 | | |
744 | | /* Superusers bypass all permission checking. */ |
745 | 0 | if (superuser_arg(roleid)) |
746 | 0 | return true; |
747 | | |
748 | 0 | utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); |
749 | 0 | if (HeapTupleIsValid(utup)) |
750 | 0 | { |
751 | 0 | result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication; |
752 | 0 | ReleaseSysCache(utup); |
753 | 0 | } |
754 | 0 | return result; |
755 | 0 | } |
756 | | |
757 | | /* |
758 | | * Initialize user identity during normal backend startup |
759 | | */ |
760 | | void |
761 | | InitializeSessionUserId(const char *rolename, Oid roleid, |
762 | | bool bypass_login_check) |
763 | 0 | { |
764 | 0 | HeapTuple roleTup; |
765 | 0 | Form_pg_authid rform; |
766 | 0 | char *rname; |
767 | 0 | bool is_superuser; |
768 | | |
769 | | /* |
770 | | * In a parallel worker, we don't have to do anything here. |
771 | | * ParallelWorkerMain already set our output variables, and we aren't |
772 | | * going to enforce either rolcanlogin or rolconnlimit. Furthermore, we |
773 | | * don't really want to perform a catalog lookup for the role: we don't |
774 | | * want to fail if it's been dropped. |
775 | | */ |
776 | 0 | if (InitializingParallelWorker) |
777 | 0 | { |
778 | 0 | Assert(bypass_login_check); |
779 | 0 | return; |
780 | 0 | } |
781 | | |
782 | | /* |
783 | | * Don't do scans if we're bootstrapping, none of the system catalogs |
784 | | * exist yet, and they should be owned by postgres anyway. |
785 | | */ |
786 | 0 | Assert(!IsBootstrapProcessingMode()); |
787 | | |
788 | | /* |
789 | | * Make sure syscache entries are flushed for recent catalog changes. This |
790 | | * allows us to find roles that were created on-the-fly during |
791 | | * authentication. |
792 | | */ |
793 | 0 | AcceptInvalidationMessages(); |
794 | | |
795 | | /* |
796 | | * Look up the role, either by name if that's given or by OID if not. |
797 | | */ |
798 | 0 | if (rolename != NULL) |
799 | 0 | { |
800 | 0 | roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(rolename)); |
801 | 0 | if (!HeapTupleIsValid(roleTup)) |
802 | 0 | ereport(FATAL, |
803 | 0 | (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
804 | 0 | errmsg("role \"%s\" does not exist", rolename))); |
805 | 0 | } |
806 | 0 | else |
807 | 0 | { |
808 | 0 | roleTup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); |
809 | 0 | if (!HeapTupleIsValid(roleTup)) |
810 | 0 | ereport(FATAL, |
811 | 0 | (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
812 | 0 | errmsg("role with OID %u does not exist", roleid))); |
813 | 0 | } |
814 | | |
815 | 0 | rform = (Form_pg_authid) GETSTRUCT(roleTup); |
816 | 0 | roleid = rform->oid; |
817 | 0 | rname = NameStr(rform->rolname); |
818 | 0 | is_superuser = rform->rolsuper; |
819 | |
|
820 | 0 | SetAuthenticatedUserId(roleid); |
821 | | |
822 | | /* |
823 | | * Set SessionUserId and related variables, including "role", via the GUC |
824 | | * mechanisms. |
825 | | * |
826 | | * Note: ideally we would use PGC_S_DYNAMIC_DEFAULT here, so that |
827 | | * session_authorization could subsequently be changed from |
828 | | * pg_db_role_setting entries. Instead, session_authorization in |
829 | | * pg_db_role_setting has no effect. Changing that would require solving |
830 | | * two problems: |
831 | | * |
832 | | * 1. If pg_db_role_setting has values for both session_authorization and |
833 | | * role, we could not be sure which order those would be applied in, and |
834 | | * it would matter. |
835 | | * |
836 | | * 2. Sites may have years-old session_authorization entries. There's not |
837 | | * been any particular reason to remove them. Ending the dormancy of |
838 | | * those entries could seriously change application behavior, so only a |
839 | | * major release should do that. |
840 | | */ |
841 | 0 | SetConfigOption("session_authorization", rname, |
842 | 0 | PGC_BACKEND, PGC_S_OVERRIDE); |
843 | | |
844 | | /* |
845 | | * These next checks are not enforced when in standalone mode, so that |
846 | | * there is a way to recover from sillinesses like "UPDATE pg_authid SET |
847 | | * rolcanlogin = false;". |
848 | | */ |
849 | 0 | if (IsUnderPostmaster) |
850 | 0 | { |
851 | | /* |
852 | | * Is role allowed to login at all? (But background workers can |
853 | | * override this by setting bypass_login_check.) |
854 | | */ |
855 | 0 | if (!bypass_login_check && !rform->rolcanlogin) |
856 | 0 | ereport(FATAL, |
857 | 0 | (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
858 | 0 | errmsg("role \"%s\" is not permitted to log in", |
859 | 0 | rname))); |
860 | | |
861 | | /* |
862 | | * Check connection limit for this role. We enforce the limit only |
863 | | * for regular backends, since other process types have their own |
864 | | * PGPROC pools. |
865 | | * |
866 | | * There is a race condition here --- we create our PGPROC before |
867 | | * checking for other PGPROCs. If two backends did this at about the |
868 | | * same time, they might both think they were over the limit, while |
869 | | * ideally one should succeed and one fail. Getting that to work |
870 | | * exactly seems more trouble than it is worth, however; instead we |
871 | | * just document that the connection limit is approximate. |
872 | | */ |
873 | 0 | if (rform->rolconnlimit >= 0 && |
874 | 0 | AmRegularBackendProcess() && |
875 | 0 | !is_superuser && |
876 | 0 | CountUserBackends(roleid) > rform->rolconnlimit) |
877 | 0 | ereport(FATAL, |
878 | 0 | (errcode(ERRCODE_TOO_MANY_CONNECTIONS), |
879 | 0 | errmsg("too many connections for role \"%s\"", |
880 | 0 | rname))); |
881 | 0 | } |
882 | | |
883 | 0 | ReleaseSysCache(roleTup); |
884 | 0 | } |
885 | | |
886 | | |
887 | | /* |
888 | | * Initialize user identity during special backend startup |
889 | | */ |
890 | | void |
891 | | InitializeSessionUserIdStandalone(void) |
892 | 0 | { |
893 | | /* |
894 | | * This function should only be called in single-user mode, in autovacuum |
895 | | * workers, in slot sync worker and in background workers. |
896 | | */ |
897 | 0 | Assert(!IsUnderPostmaster || AmAutoVacuumWorkerProcess() || |
898 | 0 | AmLogicalSlotSyncWorkerProcess() || AmBackgroundWorkerProcess()); |
899 | | |
900 | | /* call only once */ |
901 | 0 | Assert(!OidIsValid(AuthenticatedUserId)); |
902 | |
|
903 | 0 | AuthenticatedUserId = BOOTSTRAP_SUPERUSERID; |
904 | | |
905 | | /* |
906 | | * XXX Ideally we'd do this via SetConfigOption("session_authorization"), |
907 | | * but we lack the role name needed to do that, and we can't fetch it |
908 | | * because one reason for this special case is to be able to start up even |
909 | | * if something's happened to the BOOTSTRAP_SUPERUSERID's pg_authid row. |
910 | | * Since we don't set the GUC itself, C code will see the value as NULL, |
911 | | * and current_setting() will report an empty string within this session. |
912 | | */ |
913 | 0 | SetSessionAuthorization(BOOTSTRAP_SUPERUSERID, true); |
914 | | |
915 | | /* We could do SetConfigOption("role"), but let's be consistent */ |
916 | 0 | SetCurrentRoleId(InvalidOid, false); |
917 | 0 | } |
918 | | |
919 | | /* |
920 | | * Initialize the system user. |
921 | | * |
922 | | * This is built as auth_method:authn_id. |
923 | | */ |
924 | | void |
925 | | InitializeSystemUser(const char *authn_id, const char *auth_method) |
926 | 0 | { |
927 | 0 | char *system_user; |
928 | | |
929 | | /* call only once */ |
930 | 0 | Assert(SystemUser == NULL); |
931 | | |
932 | | /* |
933 | | * InitializeSystemUser should be called only when authn_id is not NULL, |
934 | | * meaning that auth_method is valid. |
935 | | */ |
936 | 0 | Assert(authn_id != NULL); |
937 | |
|
938 | 0 | system_user = psprintf("%s:%s", auth_method, authn_id); |
939 | | |
940 | | /* Store SystemUser in long-lived storage */ |
941 | 0 | SystemUser = MemoryContextStrdup(TopMemoryContext, system_user); |
942 | 0 | pfree(system_user); |
943 | 0 | } |
944 | | |
945 | | /* |
946 | | * SQL-function SYSTEM_USER |
947 | | */ |
948 | | Datum |
949 | | system_user(PG_FUNCTION_ARGS) |
950 | 0 | { |
951 | 0 | const char *sysuser = GetSystemUser(); |
952 | |
|
953 | 0 | if (sysuser) |
954 | 0 | PG_RETURN_DATUM(CStringGetTextDatum(sysuser)); |
955 | 0 | else |
956 | 0 | PG_RETURN_NULL(); |
957 | 0 | } |
958 | | |
959 | | /* |
960 | | * Change session auth ID while running |
961 | | * |
962 | | * The SQL standard says that SET SESSION AUTHORIZATION implies SET ROLE NONE. |
963 | | * We mechanize that at higher levels not here, because this is the GUC |
964 | | * assign hook for "session_authorization", and it must be commutative with |
965 | | * SetCurrentRoleId (the hook for "role") because guc.c provides no guarantees |
966 | | * which will run first during cases such as transaction rollback. Therefore, |
967 | | * we update derived state (OuterUserId/CurrentUserId/is_superuser) only if |
968 | | * !SetRoleIsActive. |
969 | | */ |
970 | | void |
971 | | SetSessionAuthorization(Oid userid, bool is_superuser) |
972 | 0 | { |
973 | 0 | SetSessionUserId(userid, is_superuser); |
974 | |
|
975 | 0 | if (!SetRoleIsActive) |
976 | 0 | SetOuterUserId(userid, is_superuser); |
977 | 0 | } |
978 | | |
979 | | /* |
980 | | * Report current role id |
981 | | * This follows the semantics of SET ROLE, ie return the outer-level ID |
982 | | * not the current effective ID, and return InvalidOid when the setting |
983 | | * is logically SET ROLE NONE. |
984 | | */ |
985 | | Oid |
986 | | GetCurrentRoleId(void) |
987 | 0 | { |
988 | 0 | if (SetRoleIsActive) |
989 | 0 | return OuterUserId; |
990 | 0 | else |
991 | 0 | return InvalidOid; |
992 | 0 | } |
993 | | |
994 | | /* |
995 | | * Change Role ID while running (SET ROLE) |
996 | | * |
997 | | * If roleid is InvalidOid, we are doing SET ROLE NONE: revert to the |
998 | | * session user authorization. In this case the is_superuser argument |
999 | | * is ignored. |
1000 | | * |
1001 | | * When roleid is not InvalidOid, the caller must have checked whether |
1002 | | * the session user has permission to become that role. (We cannot check |
1003 | | * here because this routine must be able to execute in a failed transaction |
1004 | | * to restore a prior value of the ROLE GUC variable.) |
1005 | | */ |
1006 | | void |
1007 | | SetCurrentRoleId(Oid roleid, bool is_superuser) |
1008 | 0 | { |
1009 | | /* |
1010 | | * Get correct info if it's SET ROLE NONE |
1011 | | * |
1012 | | * If SessionUserId hasn't been set yet, do nothing beyond updating |
1013 | | * SetRoleIsActive --- the eventual SetSessionAuthorization call will |
1014 | | * update the derived state. This is needed since we will get called |
1015 | | * during GUC initialization. |
1016 | | */ |
1017 | 0 | if (!OidIsValid(roleid)) |
1018 | 0 | { |
1019 | 0 | SetRoleIsActive = false; |
1020 | |
|
1021 | 0 | if (!OidIsValid(SessionUserId)) |
1022 | 0 | return; |
1023 | | |
1024 | 0 | roleid = SessionUserId; |
1025 | 0 | is_superuser = SessionUserIsSuperuser; |
1026 | 0 | } |
1027 | 0 | else |
1028 | 0 | SetRoleIsActive = true; |
1029 | | |
1030 | 0 | SetOuterUserId(roleid, is_superuser); |
1031 | 0 | } |
1032 | | |
1033 | | |
1034 | | /* |
1035 | | * Get user name from user oid, returns NULL for nonexistent roleid if noerr |
1036 | | * is true. |
1037 | | */ |
1038 | | char * |
1039 | | GetUserNameFromId(Oid roleid, bool noerr) |
1040 | 0 | { |
1041 | 0 | HeapTuple tuple; |
1042 | 0 | char *result; |
1043 | |
|
1044 | 0 | tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); |
1045 | 0 | if (!HeapTupleIsValid(tuple)) |
1046 | 0 | { |
1047 | 0 | if (!noerr) |
1048 | 0 | ereport(ERROR, |
1049 | 0 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
1050 | 0 | errmsg("invalid role OID: %u", roleid))); |
1051 | 0 | result = NULL; |
1052 | 0 | } |
1053 | 0 | else |
1054 | 0 | { |
1055 | 0 | result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname)); |
1056 | 0 | ReleaseSysCache(tuple); |
1057 | 0 | } |
1058 | 0 | return result; |
1059 | 0 | } |
1060 | | |
1061 | | /* ------------------------------------------------------------------------ |
1062 | | * Client connection state shared with parallel workers |
1063 | | * |
1064 | | * ClientConnectionInfo contains pieces of information about the client that |
1065 | | * need to be synced to parallel workers when they initialize. |
1066 | | *------------------------------------------------------------------------- |
1067 | | */ |
1068 | | |
1069 | | ClientConnectionInfo MyClientConnectionInfo; |
1070 | | |
1071 | | /* |
1072 | | * Intermediate representation of ClientConnectionInfo for easier |
1073 | | * serialization. Variable-length fields are allocated right after this |
1074 | | * header. |
1075 | | */ |
1076 | | typedef struct SerializedClientConnectionInfo |
1077 | | { |
1078 | | int32 authn_id_len; /* strlen(authn_id), or -1 if NULL */ |
1079 | | UserAuth auth_method; |
1080 | | } SerializedClientConnectionInfo; |
1081 | | |
1082 | | /* |
1083 | | * Calculate the space needed to serialize MyClientConnectionInfo. |
1084 | | */ |
1085 | | Size |
1086 | | EstimateClientConnectionInfoSpace(void) |
1087 | 0 | { |
1088 | 0 | Size size = 0; |
1089 | |
|
1090 | 0 | size = add_size(size, sizeof(SerializedClientConnectionInfo)); |
1091 | |
|
1092 | 0 | if (MyClientConnectionInfo.authn_id) |
1093 | 0 | size = add_size(size, strlen(MyClientConnectionInfo.authn_id) + 1); |
1094 | |
|
1095 | 0 | return size; |
1096 | 0 | } |
1097 | | |
1098 | | /* |
1099 | | * Serialize MyClientConnectionInfo for use by parallel workers. |
1100 | | */ |
1101 | | void |
1102 | | SerializeClientConnectionInfo(Size maxsize, char *start_address) |
1103 | 0 | { |
1104 | 0 | SerializedClientConnectionInfo serialized = {0}; |
1105 | |
|
1106 | 0 | serialized.authn_id_len = -1; |
1107 | 0 | serialized.auth_method = MyClientConnectionInfo.auth_method; |
1108 | |
|
1109 | 0 | if (MyClientConnectionInfo.authn_id) |
1110 | 0 | serialized.authn_id_len = strlen(MyClientConnectionInfo.authn_id); |
1111 | | |
1112 | | /* Copy serialized representation to buffer */ |
1113 | 0 | Assert(maxsize >= sizeof(serialized)); |
1114 | 0 | memcpy(start_address, &serialized, sizeof(serialized)); |
1115 | |
|
1116 | 0 | maxsize -= sizeof(serialized); |
1117 | 0 | start_address += sizeof(serialized); |
1118 | | |
1119 | | /* Copy authn_id into the space after the struct */ |
1120 | 0 | if (serialized.authn_id_len >= 0) |
1121 | 0 | { |
1122 | 0 | Assert(maxsize >= (serialized.authn_id_len + 1)); |
1123 | 0 | memcpy(start_address, |
1124 | 0 | MyClientConnectionInfo.authn_id, |
1125 | | /* include the NULL terminator to ease deserialization */ |
1126 | 0 | serialized.authn_id_len + 1); |
1127 | 0 | } |
1128 | 0 | } |
1129 | | |
1130 | | /* |
1131 | | * Restore MyClientConnectionInfo from its serialized representation. |
1132 | | */ |
1133 | | void |
1134 | | RestoreClientConnectionInfo(char *conninfo) |
1135 | 0 | { |
1136 | 0 | SerializedClientConnectionInfo serialized; |
1137 | |
|
1138 | 0 | memcpy(&serialized, conninfo, sizeof(serialized)); |
1139 | | |
1140 | | /* Copy the fields back into place */ |
1141 | 0 | MyClientConnectionInfo.authn_id = NULL; |
1142 | 0 | MyClientConnectionInfo.auth_method = serialized.auth_method; |
1143 | |
|
1144 | 0 | if (serialized.authn_id_len >= 0) |
1145 | 0 | { |
1146 | 0 | char *authn_id; |
1147 | |
|
1148 | 0 | authn_id = conninfo + sizeof(serialized); |
1149 | 0 | MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, |
1150 | 0 | authn_id); |
1151 | 0 | } |
1152 | 0 | } |
1153 | | |
1154 | | |
1155 | | /*------------------------------------------------------------------------- |
1156 | | * Interlock-file support |
1157 | | * |
1158 | | * These routines are used to create both a data-directory lockfile |
1159 | | * ($DATADIR/postmaster.pid) and Unix-socket-file lockfiles ($SOCKFILE.lock). |
1160 | | * Both kinds of files contain the same info initially, although we can add |
1161 | | * more information to a data-directory lockfile after it's created, using |
1162 | | * AddToDataDirLockFile(). See pidfile.h for documentation of the contents |
1163 | | * of these lockfiles. |
1164 | | * |
1165 | | * On successful lockfile creation, a proc_exit callback to remove the |
1166 | | * lockfile is automatically created. |
1167 | | *------------------------------------------------------------------------- |
1168 | | */ |
1169 | | |
1170 | | /* |
1171 | | * proc_exit callback to remove lockfiles. |
1172 | | */ |
1173 | | static void |
1174 | | UnlinkLockFiles(int status, Datum arg) |
1175 | 0 | { |
1176 | 0 | ListCell *l; |
1177 | |
|
1178 | 0 | foreach(l, lock_files) |
1179 | 0 | { |
1180 | 0 | char *curfile = (char *) lfirst(l); |
1181 | |
|
1182 | 0 | unlink(curfile); |
1183 | | /* Should we complain if the unlink fails? */ |
1184 | 0 | } |
1185 | | /* Since we're about to exit, no need to reclaim storage */ |
1186 | 0 | lock_files = NIL; |
1187 | | |
1188 | | /* |
1189 | | * Lock file removal should always be the last externally visible action |
1190 | | * of a postmaster or standalone backend, while we won't come here at all |
1191 | | * when exiting postmaster child processes. Therefore, this is a good |
1192 | | * place to log completion of shutdown. We could alternatively teach |
1193 | | * proc_exit() to do it, but that seems uglier. In a standalone backend, |
1194 | | * use NOTICE elevel to be less chatty. |
1195 | | */ |
1196 | 0 | ereport(IsPostmasterEnvironment ? LOG : NOTICE, |
1197 | 0 | (errmsg("database system is shut down"))); |
1198 | 0 | } |
1199 | | |
1200 | | /* |
1201 | | * Create a lockfile. |
1202 | | * |
1203 | | * filename is the path name of the lockfile to create. |
1204 | | * amPostmaster is used to determine how to encode the output PID. |
1205 | | * socketDir is the Unix socket directory path to include (possibly empty). |
1206 | | * isDDLock and refName are used to determine what error message to produce. |
1207 | | */ |
1208 | | static void |
1209 | | CreateLockFile(const char *filename, bool amPostmaster, |
1210 | | const char *socketDir, |
1211 | | bool isDDLock, const char *refName) |
1212 | 0 | { |
1213 | 0 | int fd; |
1214 | 0 | char buffer[MAXPGPATH * 2 + 256]; |
1215 | 0 | int ntries; |
1216 | 0 | int len; |
1217 | 0 | int encoded_pid; |
1218 | 0 | pid_t other_pid; |
1219 | 0 | pid_t my_pid, |
1220 | 0 | my_p_pid, |
1221 | 0 | my_gp_pid; |
1222 | 0 | const char *envvar; |
1223 | | |
1224 | | /* |
1225 | | * If the PID in the lockfile is our own PID or our parent's or |
1226 | | * grandparent's PID, then the file must be stale (probably left over from |
1227 | | * a previous system boot cycle). We need to check this because of the |
1228 | | * likelihood that a reboot will assign exactly the same PID as we had in |
1229 | | * the previous reboot, or one that's only one or two counts larger and |
1230 | | * hence the lockfile's PID now refers to an ancestor shell process. We |
1231 | | * allow pg_ctl to pass down its parent shell PID (our grandparent PID) |
1232 | | * via the environment variable PG_GRANDPARENT_PID; this is so that |
1233 | | * launching the postmaster via pg_ctl can be just as reliable as |
1234 | | * launching it directly. There is no provision for detecting |
1235 | | * further-removed ancestor processes, but if the init script is written |
1236 | | * carefully then all but the immediate parent shell will be root-owned |
1237 | | * processes and so the kill test will fail with EPERM. Note that we |
1238 | | * cannot get a false negative this way, because an existing postmaster |
1239 | | * would surely never launch a competing postmaster or pg_ctl process |
1240 | | * directly. |
1241 | | */ |
1242 | 0 | my_pid = getpid(); |
1243 | |
|
1244 | 0 | #ifndef WIN32 |
1245 | 0 | my_p_pid = getppid(); |
1246 | | #else |
1247 | | |
1248 | | /* |
1249 | | * Windows hasn't got getppid(), but doesn't need it since it's not using |
1250 | | * real kill() either... |
1251 | | */ |
1252 | | my_p_pid = 0; |
1253 | | #endif |
1254 | |
|
1255 | 0 | envvar = getenv("PG_GRANDPARENT_PID"); |
1256 | 0 | if (envvar) |
1257 | 0 | my_gp_pid = atoi(envvar); |
1258 | 0 | else |
1259 | 0 | my_gp_pid = 0; |
1260 | | |
1261 | | /* |
1262 | | * We need a loop here because of race conditions. But don't loop forever |
1263 | | * (for example, a non-writable $PGDATA directory might cause a failure |
1264 | | * that won't go away). 100 tries seems like plenty. |
1265 | | */ |
1266 | 0 | for (ntries = 0;; ntries++) |
1267 | 0 | { |
1268 | | /* |
1269 | | * Try to create the lock file --- O_EXCL makes this atomic. |
1270 | | * |
1271 | | * Think not to make the file protection weaker than 0600/0640. See |
1272 | | * comments below. |
1273 | | */ |
1274 | 0 | fd = open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode); |
1275 | 0 | if (fd >= 0) |
1276 | 0 | break; /* Success; exit the retry loop */ |
1277 | | |
1278 | | /* |
1279 | | * Couldn't create the pid file. Probably it already exists. |
1280 | | */ |
1281 | 0 | if ((errno != EEXIST && errno != EACCES) || ntries > 100) |
1282 | 0 | ereport(FATAL, |
1283 | 0 | (errcode_for_file_access(), |
1284 | 0 | errmsg("could not create lock file \"%s\": %m", |
1285 | 0 | filename))); |
1286 | | |
1287 | | /* |
1288 | | * Read the file to get the old owner's PID. Note race condition |
1289 | | * here: file might have been deleted since we tried to create it. |
1290 | | */ |
1291 | 0 | fd = open(filename, O_RDONLY, pg_file_create_mode); |
1292 | 0 | if (fd < 0) |
1293 | 0 | { |
1294 | 0 | if (errno == ENOENT) |
1295 | 0 | continue; /* race condition; try again */ |
1296 | 0 | ereport(FATAL, |
1297 | 0 | (errcode_for_file_access(), |
1298 | 0 | errmsg("could not open lock file \"%s\": %m", |
1299 | 0 | filename))); |
1300 | 0 | } |
1301 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_READ); |
1302 | 0 | if ((len = read(fd, buffer, sizeof(buffer) - 1)) < 0) |
1303 | 0 | ereport(FATAL, |
1304 | 0 | (errcode_for_file_access(), |
1305 | 0 | errmsg("could not read lock file \"%s\": %m", |
1306 | 0 | filename))); |
1307 | 0 | pgstat_report_wait_end(); |
1308 | 0 | close(fd); |
1309 | |
|
1310 | 0 | if (len == 0) |
1311 | 0 | { |
1312 | 0 | ereport(FATAL, |
1313 | 0 | (errcode(ERRCODE_LOCK_FILE_EXISTS), |
1314 | 0 | errmsg("lock file \"%s\" is empty", filename), |
1315 | 0 | errhint("Either another server is starting, or the lock file is the remnant of a previous server startup crash."))); |
1316 | 0 | } |
1317 | | |
1318 | 0 | buffer[len] = '\0'; |
1319 | 0 | encoded_pid = atoi(buffer); |
1320 | | |
1321 | | /* if pid < 0, the pid is for postgres, not postmaster */ |
1322 | 0 | other_pid = (pid_t) (encoded_pid < 0 ? -encoded_pid : encoded_pid); |
1323 | |
|
1324 | 0 | if (other_pid <= 0) |
1325 | 0 | elog(FATAL, "bogus data in lock file \"%s\": \"%s\"", |
1326 | 0 | filename, buffer); |
1327 | | |
1328 | | /* |
1329 | | * Check to see if the other process still exists |
1330 | | * |
1331 | | * Per discussion above, my_pid, my_p_pid, and my_gp_pid can be |
1332 | | * ignored as false matches. |
1333 | | * |
1334 | | * Normally kill() will fail with ESRCH if the given PID doesn't |
1335 | | * exist. |
1336 | | * |
1337 | | * We can treat the EPERM-error case as okay because that error |
1338 | | * implies that the existing process has a different userid than we |
1339 | | * do, which means it cannot be a competing postmaster. A postmaster |
1340 | | * cannot successfully attach to a data directory owned by a userid |
1341 | | * other than its own, as enforced in checkDataDir(). Also, since we |
1342 | | * create the lockfiles mode 0600/0640, we'd have failed above if the |
1343 | | * lockfile belonged to another userid --- which means that whatever |
1344 | | * process kill() is reporting about isn't the one that made the |
1345 | | * lockfile. (NOTE: this last consideration is the only one that |
1346 | | * keeps us from blowing away a Unix socket file belonging to an |
1347 | | * instance of Postgres being run by someone else, at least on |
1348 | | * machines where /tmp hasn't got a stickybit.) |
1349 | | */ |
1350 | 0 | if (other_pid != my_pid && other_pid != my_p_pid && |
1351 | 0 | other_pid != my_gp_pid) |
1352 | 0 | { |
1353 | 0 | if (kill(other_pid, 0) == 0 || |
1354 | 0 | (errno != ESRCH && errno != EPERM)) |
1355 | 0 | { |
1356 | | /* lockfile belongs to a live process */ |
1357 | 0 | ereport(FATAL, |
1358 | 0 | (errcode(ERRCODE_LOCK_FILE_EXISTS), |
1359 | 0 | errmsg("lock file \"%s\" already exists", |
1360 | 0 | filename), |
1361 | 0 | isDDLock ? |
1362 | 0 | (encoded_pid < 0 ? |
1363 | 0 | errhint("Is another postgres (PID %d) running in data directory \"%s\"?", |
1364 | 0 | (int) other_pid, refName) : |
1365 | 0 | errhint("Is another postmaster (PID %d) running in data directory \"%s\"?", |
1366 | 0 | (int) other_pid, refName)) : |
1367 | 0 | (encoded_pid < 0 ? |
1368 | 0 | errhint("Is another postgres (PID %d) using socket file \"%s\"?", |
1369 | 0 | (int) other_pid, refName) : |
1370 | 0 | errhint("Is another postmaster (PID %d) using socket file \"%s\"?", |
1371 | 0 | (int) other_pid, refName)))); |
1372 | 0 | } |
1373 | 0 | } |
1374 | | |
1375 | | /* |
1376 | | * No, the creating process did not exist. However, it could be that |
1377 | | * the postmaster crashed (or more likely was kill -9'd by a clueless |
1378 | | * admin) but has left orphan backends behind. Check for this by |
1379 | | * looking to see if there is an associated shmem segment that is |
1380 | | * still in use. |
1381 | | * |
1382 | | * Note: because postmaster.pid is written in multiple steps, we might |
1383 | | * not find the shmem ID values in it; we can't treat that as an |
1384 | | * error. |
1385 | | */ |
1386 | 0 | if (isDDLock) |
1387 | 0 | { |
1388 | 0 | char *ptr = buffer; |
1389 | 0 | unsigned long id1, |
1390 | 0 | id2; |
1391 | 0 | int lineno; |
1392 | |
|
1393 | 0 | for (lineno = 1; lineno < LOCK_FILE_LINE_SHMEM_KEY; lineno++) |
1394 | 0 | { |
1395 | 0 | if ((ptr = strchr(ptr, '\n')) == NULL) |
1396 | 0 | break; |
1397 | 0 | ptr++; |
1398 | 0 | } |
1399 | |
|
1400 | 0 | if (ptr != NULL && |
1401 | 0 | sscanf(ptr, "%lu %lu", &id1, &id2) == 2) |
1402 | 0 | { |
1403 | 0 | if (PGSharedMemoryIsInUse(id1, id2)) |
1404 | 0 | ereport(FATAL, |
1405 | 0 | (errcode(ERRCODE_LOCK_FILE_EXISTS), |
1406 | 0 | errmsg("pre-existing shared memory block (key %lu, ID %lu) is still in use", |
1407 | 0 | id1, id2), |
1408 | 0 | errhint("Terminate any old server processes associated with data directory \"%s\".", |
1409 | 0 | refName))); |
1410 | 0 | } |
1411 | 0 | } |
1412 | | |
1413 | | /* |
1414 | | * Looks like nobody's home. Unlink the file and try again to create |
1415 | | * it. Need a loop because of possible race condition against other |
1416 | | * would-be creators. |
1417 | | */ |
1418 | 0 | if (unlink(filename) < 0) |
1419 | 0 | ereport(FATAL, |
1420 | 0 | (errcode_for_file_access(), |
1421 | 0 | errmsg("could not remove old lock file \"%s\": %m", |
1422 | 0 | filename), |
1423 | 0 | errhint("The file seems accidentally left over, but " |
1424 | 0 | "it could not be removed. Please remove the file " |
1425 | 0 | "by hand and try again."))); |
1426 | 0 | } |
1427 | | |
1428 | | /* |
1429 | | * Successfully created the file, now fill it. See comment in pidfile.h |
1430 | | * about the contents. Note that we write the same first five lines into |
1431 | | * both datadir and socket lockfiles; although more stuff may get added to |
1432 | | * the datadir lockfile later. |
1433 | | */ |
1434 | 0 | snprintf(buffer, sizeof(buffer), "%d\n%s\n" INT64_FORMAT "\n%d\n%s\n", |
1435 | 0 | amPostmaster ? (int) my_pid : -((int) my_pid), |
1436 | 0 | DataDir, |
1437 | 0 | MyStartTime, |
1438 | 0 | PostPortNumber, |
1439 | 0 | socketDir); |
1440 | | |
1441 | | /* |
1442 | | * In a standalone backend, the next line (LOCK_FILE_LINE_LISTEN_ADDR) |
1443 | | * will never receive data, so fill it in as empty now. |
1444 | | */ |
1445 | 0 | if (isDDLock && !amPostmaster) |
1446 | 0 | strlcat(buffer, "\n", sizeof(buffer)); |
1447 | |
|
1448 | 0 | errno = 0; |
1449 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_WRITE); |
1450 | 0 | if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) |
1451 | 0 | { |
1452 | 0 | int save_errno = errno; |
1453 | |
|
1454 | 0 | close(fd); |
1455 | 0 | unlink(filename); |
1456 | | /* if write didn't set errno, assume problem is no disk space */ |
1457 | 0 | errno = save_errno ? save_errno : ENOSPC; |
1458 | 0 | ereport(FATAL, |
1459 | 0 | (errcode_for_file_access(), |
1460 | 0 | errmsg("could not write lock file \"%s\": %m", filename))); |
1461 | 0 | } |
1462 | 0 | pgstat_report_wait_end(); |
1463 | |
|
1464 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_SYNC); |
1465 | 0 | if (pg_fsync(fd) != 0) |
1466 | 0 | { |
1467 | 0 | int save_errno = errno; |
1468 | |
|
1469 | 0 | close(fd); |
1470 | 0 | unlink(filename); |
1471 | 0 | errno = save_errno; |
1472 | 0 | ereport(FATAL, |
1473 | 0 | (errcode_for_file_access(), |
1474 | 0 | errmsg("could not write lock file \"%s\": %m", filename))); |
1475 | 0 | } |
1476 | 0 | pgstat_report_wait_end(); |
1477 | 0 | if (close(fd) != 0) |
1478 | 0 | { |
1479 | 0 | int save_errno = errno; |
1480 | |
|
1481 | 0 | unlink(filename); |
1482 | 0 | errno = save_errno; |
1483 | 0 | ereport(FATAL, |
1484 | 0 | (errcode_for_file_access(), |
1485 | 0 | errmsg("could not write lock file \"%s\": %m", filename))); |
1486 | 0 | } |
1487 | | |
1488 | | /* |
1489 | | * Arrange to unlink the lock file(s) at proc_exit. If this is the first |
1490 | | * one, set up the on_proc_exit function to do it; then add this lock file |
1491 | | * to the list of files to unlink. |
1492 | | */ |
1493 | 0 | if (lock_files == NIL) |
1494 | 0 | on_proc_exit(UnlinkLockFiles, 0); |
1495 | | |
1496 | | /* |
1497 | | * Use lcons so that the lock files are unlinked in reverse order of |
1498 | | * creation; this is critical! |
1499 | | */ |
1500 | 0 | lock_files = lcons(pstrdup(filename), lock_files); |
1501 | 0 | } |
1502 | | |
1503 | | /* |
1504 | | * Create the data directory lockfile. |
1505 | | * |
1506 | | * When this is called, we must have already switched the working |
1507 | | * directory to DataDir, so we can just use a relative path. This |
1508 | | * helps ensure that we are locking the directory we should be. |
1509 | | * |
1510 | | * Note that the socket directory path line is initially written as empty. |
1511 | | * postmaster.c will rewrite it upon creating the first Unix socket. |
1512 | | */ |
1513 | | void |
1514 | | CreateDataDirLockFile(bool amPostmaster) |
1515 | 0 | { |
1516 | 0 | CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir); |
1517 | 0 | } |
1518 | | |
1519 | | /* |
1520 | | * Create a lockfile for the specified Unix socket file. |
1521 | | */ |
1522 | | void |
1523 | | CreateSocketLockFile(const char *socketfile, bool amPostmaster, |
1524 | | const char *socketDir) |
1525 | 0 | { |
1526 | 0 | char lockfile[MAXPGPATH]; |
1527 | |
|
1528 | 0 | snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile); |
1529 | 0 | CreateLockFile(lockfile, amPostmaster, socketDir, false, socketfile); |
1530 | 0 | } |
1531 | | |
1532 | | /* |
1533 | | * TouchSocketLockFiles -- mark socket lock files as recently accessed |
1534 | | * |
1535 | | * This routine should be called every so often to ensure that the socket |
1536 | | * lock files have a recent mod or access date. That saves them |
1537 | | * from being removed by overenthusiastic /tmp-directory-cleaner daemons. |
1538 | | * (Another reason we should never have put the socket file in /tmp...) |
1539 | | */ |
1540 | | void |
1541 | | TouchSocketLockFiles(void) |
1542 | 0 | { |
1543 | 0 | ListCell *l; |
1544 | |
|
1545 | 0 | foreach(l, lock_files) |
1546 | 0 | { |
1547 | 0 | char *socketLockFile = (char *) lfirst(l); |
1548 | | |
1549 | | /* No need to touch the data directory lock file, we trust */ |
1550 | 0 | if (strcmp(socketLockFile, DIRECTORY_LOCK_FILE) == 0) |
1551 | 0 | continue; |
1552 | | |
1553 | | /* we just ignore any error here */ |
1554 | 0 | (void) utime(socketLockFile, NULL); |
1555 | 0 | } |
1556 | 0 | } |
1557 | | |
1558 | | |
1559 | | /* |
1560 | | * Add (or replace) a line in the data directory lock file. |
1561 | | * The given string should not include a trailing newline. |
1562 | | * |
1563 | | * Note: because we don't truncate the file, if we were to rewrite a line |
1564 | | * with less data than it had before, there would be garbage after the last |
1565 | | * line. While we could fix that by adding a truncate call, that would make |
1566 | | * the file update non-atomic, which we'd rather avoid. Therefore, callers |
1567 | | * should endeavor never to shorten a line once it's been written. |
1568 | | */ |
1569 | | void |
1570 | | AddToDataDirLockFile(int target_line, const char *str) |
1571 | 0 | { |
1572 | 0 | int fd; |
1573 | 0 | int len; |
1574 | 0 | int lineno; |
1575 | 0 | char *srcptr; |
1576 | 0 | char *destptr; |
1577 | 0 | char srcbuffer[BLCKSZ]; |
1578 | 0 | char destbuffer[BLCKSZ]; |
1579 | |
|
1580 | 0 | fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); |
1581 | 0 | if (fd < 0) |
1582 | 0 | { |
1583 | 0 | ereport(LOG, |
1584 | 0 | (errcode_for_file_access(), |
1585 | 0 | errmsg("could not open file \"%s\": %m", |
1586 | 0 | DIRECTORY_LOCK_FILE))); |
1587 | 0 | return; |
1588 | 0 | } |
1589 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ); |
1590 | 0 | len = read(fd, srcbuffer, sizeof(srcbuffer) - 1); |
1591 | 0 | pgstat_report_wait_end(); |
1592 | 0 | if (len < 0) |
1593 | 0 | { |
1594 | 0 | ereport(LOG, |
1595 | 0 | (errcode_for_file_access(), |
1596 | 0 | errmsg("could not read from file \"%s\": %m", |
1597 | 0 | DIRECTORY_LOCK_FILE))); |
1598 | 0 | close(fd); |
1599 | 0 | return; |
1600 | 0 | } |
1601 | 0 | srcbuffer[len] = '\0'; |
1602 | | |
1603 | | /* |
1604 | | * Advance over lines we are not supposed to rewrite, then copy them to |
1605 | | * destbuffer. |
1606 | | */ |
1607 | 0 | srcptr = srcbuffer; |
1608 | 0 | for (lineno = 1; lineno < target_line; lineno++) |
1609 | 0 | { |
1610 | 0 | char *eol = strchr(srcptr, '\n'); |
1611 | |
|
1612 | 0 | if (eol == NULL) |
1613 | 0 | break; /* not enough lines in file yet */ |
1614 | 0 | srcptr = eol + 1; |
1615 | 0 | } |
1616 | 0 | memcpy(destbuffer, srcbuffer, srcptr - srcbuffer); |
1617 | 0 | destptr = destbuffer + (srcptr - srcbuffer); |
1618 | | |
1619 | | /* |
1620 | | * Fill in any missing lines before the target line, in case lines are |
1621 | | * added to the file out of order. |
1622 | | */ |
1623 | 0 | for (; lineno < target_line; lineno++) |
1624 | 0 | { |
1625 | 0 | if (destptr < destbuffer + sizeof(destbuffer)) |
1626 | 0 | *destptr++ = '\n'; |
1627 | 0 | } |
1628 | | |
1629 | | /* |
1630 | | * Write or rewrite the target line. |
1631 | | */ |
1632 | 0 | snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s\n", str); |
1633 | 0 | destptr += strlen(destptr); |
1634 | | |
1635 | | /* |
1636 | | * If there are more lines in the old file, append them to destbuffer. |
1637 | | */ |
1638 | 0 | if ((srcptr = strchr(srcptr, '\n')) != NULL) |
1639 | 0 | { |
1640 | 0 | srcptr++; |
1641 | 0 | snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s", |
1642 | 0 | srcptr); |
1643 | 0 | } |
1644 | | |
1645 | | /* |
1646 | | * And rewrite the data. Since we write in a single kernel call, this |
1647 | | * update should appear atomic to onlookers. |
1648 | | */ |
1649 | 0 | len = strlen(destbuffer); |
1650 | 0 | errno = 0; |
1651 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE); |
1652 | 0 | if (pg_pwrite(fd, destbuffer, len, 0) != len) |
1653 | 0 | { |
1654 | 0 | pgstat_report_wait_end(); |
1655 | | /* if write didn't set errno, assume problem is no disk space */ |
1656 | 0 | if (errno == 0) |
1657 | 0 | errno = ENOSPC; |
1658 | 0 | ereport(LOG, |
1659 | 0 | (errcode_for_file_access(), |
1660 | 0 | errmsg("could not write to file \"%s\": %m", |
1661 | 0 | DIRECTORY_LOCK_FILE))); |
1662 | 0 | close(fd); |
1663 | 0 | return; |
1664 | 0 | } |
1665 | 0 | pgstat_report_wait_end(); |
1666 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC); |
1667 | 0 | if (pg_fsync(fd) != 0) |
1668 | 0 | { |
1669 | 0 | ereport(LOG, |
1670 | 0 | (errcode_for_file_access(), |
1671 | 0 | errmsg("could not write to file \"%s\": %m", |
1672 | 0 | DIRECTORY_LOCK_FILE))); |
1673 | 0 | } |
1674 | 0 | pgstat_report_wait_end(); |
1675 | 0 | if (close(fd) != 0) |
1676 | 0 | { |
1677 | 0 | ereport(LOG, |
1678 | 0 | (errcode_for_file_access(), |
1679 | 0 | errmsg("could not write to file \"%s\": %m", |
1680 | 0 | DIRECTORY_LOCK_FILE))); |
1681 | 0 | } |
1682 | 0 | } |
1683 | | |
1684 | | |
1685 | | /* |
1686 | | * Recheck that the data directory lock file still exists with expected |
1687 | | * content. Return true if the lock file appears OK, false if it isn't. |
1688 | | * |
1689 | | * We call this periodically in the postmaster. The idea is that if the |
1690 | | * lock file has been removed or replaced by another postmaster, we should |
1691 | | * do a panic database shutdown. Therefore, we should return true if there |
1692 | | * is any doubt: we do not want to cause a panic shutdown unnecessarily. |
1693 | | * Transient failures like EINTR or ENFILE should not cause us to fail. |
1694 | | * (If there really is something wrong, we'll detect it on a future recheck.) |
1695 | | */ |
1696 | | bool |
1697 | | RecheckDataDirLockFile(void) |
1698 | 0 | { |
1699 | 0 | int fd; |
1700 | 0 | int len; |
1701 | 0 | long file_pid; |
1702 | 0 | char buffer[BLCKSZ]; |
1703 | |
|
1704 | 0 | fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); |
1705 | 0 | if (fd < 0) |
1706 | 0 | { |
1707 | | /* |
1708 | | * There are many foreseeable false-positive error conditions. For |
1709 | | * safety, fail only on enumerated clearly-something-is-wrong |
1710 | | * conditions. |
1711 | | */ |
1712 | 0 | switch (errno) |
1713 | 0 | { |
1714 | 0 | case ENOENT: |
1715 | 0 | case ENOTDIR: |
1716 | | /* disaster */ |
1717 | 0 | ereport(LOG, |
1718 | 0 | (errcode_for_file_access(), |
1719 | 0 | errmsg("could not open file \"%s\": %m", |
1720 | 0 | DIRECTORY_LOCK_FILE))); |
1721 | 0 | return false; |
1722 | 0 | default: |
1723 | | /* non-fatal, at least for now */ |
1724 | 0 | ereport(LOG, |
1725 | 0 | (errcode_for_file_access(), |
1726 | 0 | errmsg("could not open file \"%s\": %m; continuing anyway", |
1727 | 0 | DIRECTORY_LOCK_FILE))); |
1728 | 0 | return true; |
1729 | 0 | } |
1730 | 0 | } |
1731 | 0 | pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ); |
1732 | 0 | len = read(fd, buffer, sizeof(buffer) - 1); |
1733 | 0 | pgstat_report_wait_end(); |
1734 | 0 | if (len < 0) |
1735 | 0 | { |
1736 | 0 | ereport(LOG, |
1737 | 0 | (errcode_for_file_access(), |
1738 | 0 | errmsg("could not read from file \"%s\": %m", |
1739 | 0 | DIRECTORY_LOCK_FILE))); |
1740 | 0 | close(fd); |
1741 | 0 | return true; /* treat read failure as nonfatal */ |
1742 | 0 | } |
1743 | 0 | buffer[len] = '\0'; |
1744 | 0 | close(fd); |
1745 | 0 | file_pid = atol(buffer); |
1746 | 0 | if (file_pid == getpid()) |
1747 | 0 | return true; /* all is well */ |
1748 | | |
1749 | | /* Trouble: someone's overwritten the lock file */ |
1750 | 0 | ereport(LOG, |
1751 | 0 | (errmsg("lock file \"%s\" contains wrong PID: %ld instead of %ld", |
1752 | 0 | DIRECTORY_LOCK_FILE, file_pid, (long) getpid()))); |
1753 | 0 | return false; |
1754 | 0 | } |
1755 | | |
1756 | | |
1757 | | /*------------------------------------------------------------------------- |
1758 | | * Version checking support |
1759 | | *------------------------------------------------------------------------- |
1760 | | */ |
1761 | | |
1762 | | /* |
1763 | | * Determine whether the PG_VERSION file in directory `path' indicates |
1764 | | * a data version compatible with the version of this program. |
1765 | | * |
1766 | | * If compatible, return. Otherwise, ereport(FATAL). |
1767 | | */ |
1768 | | void |
1769 | | ValidatePgVersion(const char *path) |
1770 | 0 | { |
1771 | 0 | char full_path[MAXPGPATH]; |
1772 | 0 | FILE *file; |
1773 | 0 | int ret; |
1774 | 0 | long file_major; |
1775 | 0 | long my_major; |
1776 | 0 | char *endptr; |
1777 | 0 | char file_version_string[64]; |
1778 | 0 | const char *my_version_string = PG_VERSION; |
1779 | |
|
1780 | 0 | my_major = strtol(my_version_string, &endptr, 10); |
1781 | |
|
1782 | 0 | snprintf(full_path, sizeof(full_path), "%s/PG_VERSION", path); |
1783 | |
|
1784 | 0 | file = AllocateFile(full_path, "r"); |
1785 | 0 | if (!file) |
1786 | 0 | { |
1787 | 0 | if (errno == ENOENT) |
1788 | 0 | ereport(FATAL, |
1789 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1790 | 0 | errmsg("\"%s\" is not a valid data directory", |
1791 | 0 | path), |
1792 | 0 | errdetail("File \"%s\" is missing.", full_path))); |
1793 | 0 | else |
1794 | 0 | ereport(FATAL, |
1795 | 0 | (errcode_for_file_access(), |
1796 | 0 | errmsg("could not open file \"%s\": %m", full_path))); |
1797 | 0 | } |
1798 | | |
1799 | 0 | file_version_string[0] = '\0'; |
1800 | 0 | ret = fscanf(file, "%63s", file_version_string); |
1801 | 0 | file_major = strtol(file_version_string, &endptr, 10); |
1802 | |
|
1803 | 0 | if (ret != 1 || endptr == file_version_string) |
1804 | 0 | ereport(FATAL, |
1805 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1806 | 0 | errmsg("\"%s\" is not a valid data directory", |
1807 | 0 | path), |
1808 | 0 | errdetail("File \"%s\" does not contain valid data.", |
1809 | 0 | full_path), |
1810 | 0 | errhint("You might need to initdb."))); |
1811 | | |
1812 | 0 | FreeFile(file); |
1813 | |
|
1814 | 0 | if (my_major != file_major) |
1815 | 0 | ereport(FATAL, |
1816 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1817 | 0 | errmsg("database files are incompatible with server"), |
1818 | 0 | errdetail("The data directory was initialized by PostgreSQL version %s, " |
1819 | 0 | "which is not compatible with this version %s.", |
1820 | 0 | file_version_string, my_version_string))); |
1821 | 0 | } |
1822 | | |
1823 | | /*------------------------------------------------------------------------- |
1824 | | * Library preload support |
1825 | | *------------------------------------------------------------------------- |
1826 | | */ |
1827 | | |
1828 | | /* |
1829 | | * GUC variables: lists of library names to be preloaded at postmaster |
1830 | | * start and at backend start |
1831 | | */ |
1832 | | char *session_preload_libraries_string = NULL; |
1833 | | char *shared_preload_libraries_string = NULL; |
1834 | | char *local_preload_libraries_string = NULL; |
1835 | | |
1836 | | /* Flag telling that we are loading shared_preload_libraries */ |
1837 | | bool process_shared_preload_libraries_in_progress = false; |
1838 | | bool process_shared_preload_libraries_done = false; |
1839 | | |
1840 | | shmem_request_hook_type shmem_request_hook = NULL; |
1841 | | bool process_shmem_requests_in_progress = false; |
1842 | | |
1843 | | /* |
1844 | | * load the shared libraries listed in 'libraries' |
1845 | | * |
1846 | | * 'gucname': name of GUC variable, for error reports |
1847 | | * 'restricted': if true, force libraries to be in $libdir/plugins/ |
1848 | | */ |
1849 | | static void |
1850 | | load_libraries(const char *libraries, const char *gucname, bool restricted) |
1851 | 0 | { |
1852 | 0 | char *rawstring; |
1853 | 0 | List *elemlist; |
1854 | 0 | ListCell *l; |
1855 | |
|
1856 | 0 | if (libraries == NULL || libraries[0] == '\0') |
1857 | 0 | return; /* nothing to do */ |
1858 | | |
1859 | | /* Need a modifiable copy of string */ |
1860 | 0 | rawstring = pstrdup(libraries); |
1861 | | |
1862 | | /* Parse string into list of filename paths */ |
1863 | 0 | if (!SplitDirectoriesString(rawstring, ',', &elemlist)) |
1864 | 0 | { |
1865 | | /* syntax error in list */ |
1866 | 0 | list_free_deep(elemlist); |
1867 | 0 | pfree(rawstring); |
1868 | 0 | ereport(LOG, |
1869 | 0 | (errcode(ERRCODE_SYNTAX_ERROR), |
1870 | 0 | errmsg("invalid list syntax in parameter \"%s\"", |
1871 | 0 | gucname))); |
1872 | 0 | return; |
1873 | 0 | } |
1874 | | |
1875 | 0 | foreach(l, elemlist) |
1876 | 0 | { |
1877 | | /* Note that filename was already canonicalized */ |
1878 | 0 | char *filename = (char *) lfirst(l); |
1879 | 0 | char *expanded = NULL; |
1880 | | |
1881 | | /* If restricting, insert $libdir/plugins if not mentioned already */ |
1882 | 0 | if (restricted && first_dir_separator(filename) == NULL) |
1883 | 0 | { |
1884 | 0 | expanded = psprintf("$libdir/plugins/%s", filename); |
1885 | 0 | filename = expanded; |
1886 | 0 | } |
1887 | 0 | load_file(filename, restricted); |
1888 | 0 | ereport(DEBUG1, |
1889 | 0 | (errmsg_internal("loaded library \"%s\"", filename))); |
1890 | 0 | if (expanded) |
1891 | 0 | pfree(expanded); |
1892 | 0 | } |
1893 | | |
1894 | 0 | list_free_deep(elemlist); |
1895 | 0 | pfree(rawstring); |
1896 | 0 | } |
1897 | | |
1898 | | /* |
1899 | | * process any libraries that should be preloaded at postmaster start |
1900 | | */ |
1901 | | void |
1902 | | process_shared_preload_libraries(void) |
1903 | 0 | { |
1904 | 0 | process_shared_preload_libraries_in_progress = true; |
1905 | 0 | load_libraries(shared_preload_libraries_string, |
1906 | 0 | "shared_preload_libraries", |
1907 | 0 | false); |
1908 | 0 | process_shared_preload_libraries_in_progress = false; |
1909 | 0 | process_shared_preload_libraries_done = true; |
1910 | 0 | } |
1911 | | |
1912 | | /* |
1913 | | * process any libraries that should be preloaded at backend start |
1914 | | */ |
1915 | | void |
1916 | | process_session_preload_libraries(void) |
1917 | 0 | { |
1918 | 0 | load_libraries(session_preload_libraries_string, |
1919 | 0 | "session_preload_libraries", |
1920 | 0 | false); |
1921 | 0 | load_libraries(local_preload_libraries_string, |
1922 | 0 | "local_preload_libraries", |
1923 | 0 | true); |
1924 | 0 | } |
1925 | | |
1926 | | /* |
1927 | | * process any shared memory requests from preloaded libraries |
1928 | | */ |
1929 | | void |
1930 | | process_shmem_requests(void) |
1931 | 0 | { |
1932 | 0 | process_shmem_requests_in_progress = true; |
1933 | 0 | if (shmem_request_hook) |
1934 | 0 | shmem_request_hook(); |
1935 | 0 | process_shmem_requests_in_progress = false; |
1936 | 0 | } |
1937 | | |
1938 | | void |
1939 | | pg_bindtextdomain(const char *domain) |
1940 | 0 | { |
1941 | | #ifdef ENABLE_NLS |
1942 | | if (my_exec_path[0] != '\0') |
1943 | | { |
1944 | | char locale_path[MAXPGPATH]; |
1945 | | |
1946 | | get_locale_path(my_exec_path, locale_path); |
1947 | | bindtextdomain(domain, locale_path); |
1948 | | pg_bind_textdomain_codeset(domain); |
1949 | | } |
1950 | | #endif |
1951 | 0 | } |