~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/utils/init/miscinit.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * miscinit.c
 
4
 *        miscellaneous initialization support stuff
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.137.4.1 2005-03-18 03:49:19 tgl Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include <sys/param.h>
 
18
#include <signal.h>
 
19
#include <sys/file.h>
 
20
#include <sys/stat.h>
 
21
#include <sys/time.h>
 
22
#include <fcntl.h>
 
23
#include <unistd.h>
 
24
#include <grp.h>
 
25
#include <pwd.h>
 
26
#include <netinet/in.h>
 
27
#include <arpa/inet.h>
 
28
#ifdef HAVE_UTIME_H
 
29
#include <utime.h>
 
30
#endif
 
31
 
 
32
#include "catalog/catname.h"
 
33
#include "catalog/pg_shadow.h"
 
34
#include "libpq/libpq-be.h"
 
35
#include "miscadmin.h"
 
36
#include "storage/fd.h"
 
37
#include "storage/ipc.h"
 
38
#include "storage/pg_shmem.h"
 
39
#include "utils/builtins.h"
 
40
#include "utils/guc.h"
 
41
#include "utils/lsyscache.h"
 
42
#include "utils/syscache.h"
 
43
 
 
44
 
 
45
ProcessingMode Mode = InitProcessing;
 
46
 
 
47
/* Note: we rely on these to initialize as zeroes */
 
48
static char directoryLockFile[MAXPGPATH];
 
49
static char socketLockFile[MAXPGPATH];
 
50
 
 
51
 
 
52
/* ----------------------------------------------------------------
 
53
 *              ignoring system indexes support stuff
 
54
 *
 
55
 * NOTE: "ignoring system indexes" means we do not use the system indexes
 
56
 * for lookups (either in hardwired catalog accesses or in planner-generated
 
57
 * plans).      We do, however, still update the indexes when a catalog
 
58
 * modification is made.
 
59
 * ----------------------------------------------------------------
 
60
 */
 
61
 
 
62
static bool isIgnoringSystemIndexes = false;
 
63
 
 
64
/*
 
65
 * IsIgnoringSystemIndexes
 
66
 *              True if ignoring system indexes.
 
67
 */
 
68
bool
 
69
IsIgnoringSystemIndexes(void)
 
70
{
 
71
        return isIgnoringSystemIndexes;
 
72
}
 
73
 
 
74
/*
 
75
 * IgnoreSystemIndexes
 
76
 *              Set true or false whether PostgreSQL ignores system indexes.
 
77
 */
 
78
void
 
79
IgnoreSystemIndexes(bool mode)
 
80
{
 
81
        isIgnoringSystemIndexes = mode;
 
82
}
 
83
 
 
84
/* ----------------------------------------------------------------
 
85
 *              system index reindexing support
 
86
 *
 
87
 * When we are busy reindexing a system index, this code provides support
 
88
 * for preventing catalog lookups from using that index.
 
89
 * ----------------------------------------------------------------
 
90
 */
 
91
 
 
92
static Oid      currentlyReindexedHeap = InvalidOid;
 
93
static Oid      currentlyReindexedIndex = InvalidOid;
 
94
 
 
95
/*
 
96
 * ReindexIsProcessingHeap
 
97
 *              True if heap specified by OID is currently being reindexed.
 
98
 */
 
99
bool
 
100
ReindexIsProcessingHeap(Oid heapOid)
 
101
{
 
102
        return heapOid == currentlyReindexedHeap;
 
103
}
 
104
 
 
105
/*
 
106
 * ReindexIsProcessingIndex
 
107
 *              True if index specified by OID is currently being reindexed.
 
108
 */
 
109
bool
 
110
ReindexIsProcessingIndex(Oid indexOid)
 
111
{
 
112
        return indexOid == currentlyReindexedIndex;
 
113
}
 
114
 
 
115
/*
 
116
 * SetReindexProcessing
 
117
 *              Set flag that specified heap/index are being reindexed.
 
118
 */
 
119
void
 
120
SetReindexProcessing(Oid heapOid, Oid indexOid)
 
121
{
 
122
        Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
 
123
        /* Reindexing is not re-entrant. */
 
124
        if (OidIsValid(currentlyReindexedIndex))
 
125
                elog(ERROR, "cannot reindex while reindexing");
 
126
        currentlyReindexedHeap = heapOid;
 
127
        currentlyReindexedIndex = indexOid;
 
128
}
 
129
 
 
130
/*
 
131
 * ResetReindexProcessing
 
132
 *              Unset reindexing status.
 
133
 */
 
134
void
 
135
ResetReindexProcessing(void)
 
136
{
 
137
        currentlyReindexedHeap = InvalidOid;
 
138
        currentlyReindexedIndex = InvalidOid;
 
139
}
 
140
 
 
141
/* ----------------------------------------------------------------
 
142
 *                              database path / name support stuff
 
143
 * ----------------------------------------------------------------
 
144
 */
 
145
 
 
146
void
 
147
SetDatabasePath(const char *path)
 
148
{
 
149
        if (DatabasePath)
 
150
        {
 
151
                free(DatabasePath);
 
152
                DatabasePath = NULL;
 
153
        }
 
154
        /* use strdup since this is done before memory contexts are set up */
 
155
        if (path)
 
156
        {
 
157
                DatabasePath = strdup(path);
 
158
                AssertState(DatabasePath);
 
159
        }
 
160
}
 
161
 
 
162
/*
 
163
 * Set data directory, but make sure it's an absolute path.  Use this,
 
164
 * never set DataDir directly.
 
165
 */
 
166
void
 
167
SetDataDir(const char *dir)
 
168
{
 
169
        char       *new;
 
170
 
 
171
        AssertArg(dir);
 
172
 
 
173
        /* If presented path is relative, convert to absolute */
 
174
        new = make_absolute_path(dir);
 
175
 
 
176
        if (DataDir)
 
177
                free(DataDir);
 
178
        DataDir = new;
 
179
}
 
180
 
 
181
/*
 
182
 * If the given pathname isn't already absolute, make it so, interpreting
 
183
 * it relative to the current working directory.
 
184
 *
 
185
 * Also canonicalizes the path.  The result is always a malloc'd copy.
 
186
 *
 
187
 * Note: it is probably unwise to use this in running backends, since they
 
188
 * have chdir'd to a database-specific subdirectory; the results would not be
 
189
 * consistent across backends.  Currently this is used only during postmaster
 
190
 * or standalone-backend startup.
 
191
 */
 
192
char *
 
193
make_absolute_path(const char *path)
 
194
{
 
195
        char       *new;
 
196
 
 
197
        /* Returning null for null input is convenient for some callers */
 
198
        if (path == NULL)
 
199
                return NULL;
 
200
 
 
201
        if (!is_absolute_path(path))
 
202
        {
 
203
                char       *buf;
 
204
                size_t          buflen;
 
205
 
 
206
                buflen = MAXPGPATH;
 
207
                for (;;)
 
208
                {
 
209
                        buf = malloc(buflen);
 
210
                        if (!buf)
 
211
                                ereport(FATAL,
 
212
                                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
213
                                                 errmsg("out of memory")));
 
214
 
 
215
                        if (getcwd(buf, buflen))
 
216
                                break;
 
217
                        else if (errno == ERANGE)
 
218
                        {
 
219
                                free(buf);
 
220
                                buflen *= 2;
 
221
                                continue;
 
222
                        }
 
223
                        else
 
224
                        {
 
225
                                free(buf);
 
226
                                elog(FATAL, "could not get current working directory: %m");
 
227
                        }
 
228
                }
 
229
 
 
230
                new = malloc(strlen(buf) + strlen(path) + 2);
 
231
                if (!new)
 
232
                        ereport(FATAL,
 
233
                                        (errcode(ERRCODE_OUT_OF_MEMORY),
 
234
                                         errmsg("out of memory")));
 
235
                sprintf(new, "%s/%s", buf, path);
 
236
                free(buf);
 
237
        }
 
238
        else
 
239
        {
 
240
                new = strdup(path);
 
241
                if (!new)
 
242
                        ereport(FATAL,
 
243
                                        (errcode(ERRCODE_OUT_OF_MEMORY),
 
244
                                         errmsg("out of memory")));
 
245
        }
 
246
 
 
247
        /* Make sure punctuation is canonical, too */
 
248
        canonicalize_path(new);
 
249
 
 
250
        return new;
 
251
}
 
252
 
 
253
 
 
254
/* ----------------------------------------------------------------
 
255
 *      User ID things
 
256
 *
 
257
 * The authenticated user is determined at connection start and never
 
258
 * changes.  The session user can be changed only by SET SESSION
 
259
 * AUTHORIZATION.  The current user may change when "setuid" functions
 
260
 * are implemented.  Conceptually there is a stack, whose bottom
 
261
 * is the session user.  You are yourself responsible to save and
 
262
 * restore the current user id if you need to change it.
 
263
 * ----------------------------------------------------------------
 
264
 */
 
265
static AclId AuthenticatedUserId = 0;
 
266
static AclId SessionUserId = 0;
 
267
static AclId CurrentUserId = 0;
 
268
 
 
269
static bool AuthenticatedUserIsSuperuser = false;
 
270
 
 
271
/*
 
272
 * This function is relevant for all privilege checks.
 
273
 */
 
274
AclId
 
275
GetUserId(void)
 
276
{
 
277
        AssertState(AclIdIsValid(CurrentUserId));
 
278
        return CurrentUserId;
 
279
}
 
280
 
 
281
 
 
282
void
 
283
SetUserId(AclId newid)
 
284
{
 
285
        AssertArg(AclIdIsValid(newid));
 
286
        CurrentUserId = newid;
 
287
}
 
288
 
 
289
 
 
290
/*
 
291
 * This value is only relevant for informational purposes.
 
292
 */
 
293
AclId
 
294
GetSessionUserId(void)
 
295
{
 
296
        AssertState(AclIdIsValid(SessionUserId));
 
297
        return SessionUserId;
 
298
}
 
299
 
 
300
 
 
301
void
 
302
SetSessionUserId(AclId newid)
 
303
{
 
304
        AssertArg(AclIdIsValid(newid));
 
305
        SessionUserId = newid;
 
306
        /* Current user defaults to session user. */
 
307
        if (!AclIdIsValid(CurrentUserId))
 
308
                CurrentUserId = newid;
 
309
}
 
310
 
 
311
 
 
312
void
 
313
InitializeSessionUserId(const char *username)
 
314
{
 
315
        HeapTuple       userTup;
 
316
        Datum           datum;
 
317
        bool            isnull;
 
318
        AclId           usesysid;
 
319
 
 
320
        /*
 
321
         * Don't do scans if we're bootstrapping, none of the system catalogs
 
322
         * exist yet, and they should be owned by postgres anyway.
 
323
         */
 
324
        AssertState(!IsBootstrapProcessingMode());
 
325
 
 
326
        /* call only once */
 
327
        AssertState(!OidIsValid(AuthenticatedUserId));
 
328
 
 
329
        userTup = SearchSysCache(SHADOWNAME,
 
330
                                                         PointerGetDatum(username),
 
331
                                                         0, 0, 0);
 
332
        if (!HeapTupleIsValid(userTup))
 
333
                ereport(FATAL,
 
334
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
335
                                 errmsg("user \"%s\" does not exist", username)));
 
336
 
 
337
        usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
 
338
 
 
339
        AuthenticatedUserId = usesysid;
 
340
        AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper;
 
341
 
 
342
        SetSessionUserId(usesysid); /* sets CurrentUserId too */
 
343
 
 
344
        /* Record username and superuser status as GUC settings too */
 
345
        SetConfigOption("session_authorization", username,
 
346
                                        PGC_BACKEND, PGC_S_OVERRIDE);
 
347
        SetConfigOption("is_superuser",
 
348
                                        AuthenticatedUserIsSuperuser ? "on" : "off",
 
349
                                        PGC_INTERNAL, PGC_S_OVERRIDE);
 
350
 
 
351
        /*
 
352
         * Set up user-specific configuration variables.  This is a good place
 
353
         * to do it so we don't have to read pg_shadow twice during session
 
354
         * startup.
 
355
         */
 
356
        datum = SysCacheGetAttr(SHADOWNAME, userTup,
 
357
                                                        Anum_pg_shadow_useconfig, &isnull);
 
358
        if (!isnull)
 
359
        {
 
360
                ArrayType  *a = DatumGetArrayTypeP(datum);
 
361
 
 
362
                ProcessGUCArray(a, PGC_S_USER);
 
363
        }
 
364
 
 
365
        ReleaseSysCache(userTup);
 
366
}
 
367
 
 
368
 
 
369
void
 
370
InitializeSessionUserIdStandalone(void)
 
371
{
 
372
        /* This function should only be called in a single-user backend. */
 
373
        AssertState(!IsUnderPostmaster);
 
374
 
 
375
        /* call only once */
 
376
        AssertState(!OidIsValid(AuthenticatedUserId));
 
377
 
 
378
        AuthenticatedUserId = BOOTSTRAP_USESYSID;
 
379
        AuthenticatedUserIsSuperuser = true;
 
380
 
 
381
        SetSessionUserId(BOOTSTRAP_USESYSID);
 
382
}
 
383
 
 
384
 
 
385
/*
 
386
 * Change session auth ID while running
 
387
 *
 
388
 * Only a superuser may set auth ID to something other than himself.  Note
 
389
 * that in case of multiple SETs in a single session, the original userid's
 
390
 * superuserness is what matters.  But we set the GUC variable is_superuser
 
391
 * to indicate whether the *current* session userid is a superuser.
 
392
 */
 
393
void
 
394
SetSessionAuthorization(AclId userid, bool is_superuser)
 
395
{
 
396
        /* Must have authenticated already, else can't make permission check */
 
397
        AssertState(AclIdIsValid(AuthenticatedUserId));
 
398
 
 
399
        if (userid != AuthenticatedUserId &&
 
400
                !AuthenticatedUserIsSuperuser)
 
401
                ereport(ERROR,
 
402
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
403
                          errmsg("permission denied to set session authorization")));
 
404
 
 
405
        SetSessionUserId(userid);
 
406
        SetUserId(userid);
 
407
 
 
408
        SetConfigOption("is_superuser",
 
409
                                        is_superuser ? "on" : "off",
 
410
                                        PGC_INTERNAL, PGC_S_OVERRIDE);
 
411
}
 
412
 
 
413
 
 
414
/*
 
415
 * Get user name from user id
 
416
 */
 
417
char *
 
418
GetUserNameFromId(AclId userid)
 
419
{
 
420
        HeapTuple       tuple;
 
421
        char       *result;
 
422
 
 
423
        tuple = SearchSysCache(SHADOWSYSID,
 
424
                                                   ObjectIdGetDatum(userid),
 
425
                                                   0, 0, 0);
 
426
        if (!HeapTupleIsValid(tuple))
 
427
                ereport(ERROR,
 
428
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
429
                                 errmsg("invalid user ID: %d", userid)));
 
430
 
 
431
        result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename));
 
432
 
 
433
        ReleaseSysCache(tuple);
 
434
        return result;
 
435
}
 
436
 
 
437
 
 
438
 
 
439
/*-------------------------------------------------------------------------
 
440
 *                              Interlock-file support
 
441
 *
 
442
 * These routines are used to create both a data-directory lockfile
 
443
 * ($DATADIR/postmaster.pid) and a Unix-socket-file lockfile ($SOCKFILE.lock).
 
444
 * Both kinds of files contain the same info:
 
445
 *
 
446
 *              Owning process' PID
 
447
 *              Data directory path
 
448
 *
 
449
 * By convention, the owning process' PID is negated if it is a standalone
 
450
 * backend rather than a postmaster.  This is just for informational purposes.
 
451
 * The path is also just for informational purposes (so that a socket lockfile
 
452
 * can be more easily traced to the associated postmaster).
 
453
 *
 
454
 * A data-directory lockfile can optionally contain a third line, containing
 
455
 * the key and ID for the shared memory block used by this postmaster.
 
456
 *
 
457
 * On successful lockfile creation, a proc_exit callback to remove the
 
458
 * lockfile is automatically created.
 
459
 *-------------------------------------------------------------------------
 
460
 */
 
461
 
 
462
/*
 
463
 * proc_exit callback to remove a lockfile.
 
464
 */
 
465
static void
 
466
UnlinkLockFile(int status, Datum filename)
 
467
{
 
468
        char       *fname = (char *) DatumGetPointer(filename);
 
469
 
 
470
        if (fname != NULL)
 
471
        {
 
472
                if (unlink(fname) != 0)
 
473
                {
 
474
                        /* Should we complain if the unlink fails? */
 
475
                }
 
476
                free(fname);
 
477
        }
 
478
}
 
479
 
 
480
/*
 
481
 * Create a lockfile.
 
482
 *
 
483
 * filename is the name of the lockfile to create.
 
484
 * amPostmaster is used to determine how to encode the output PID.
 
485
 * isDDLock and refName are used to determine what error message to produce.
 
486
 */
 
487
static void
 
488
CreateLockFile(const char *filename, bool amPostmaster,
 
489
                           bool isDDLock, const char *refName)
 
490
{
 
491
        int                     fd;
 
492
        char            buffer[MAXPGPATH + 100];
 
493
        int                     ntries;
 
494
        int                     len;
 
495
        int                     encoded_pid;
 
496
        pid_t           other_pid;
 
497
        pid_t           my_pid = getpid();
 
498
 
 
499
        /*
 
500
         * We need a loop here because of race conditions.      But don't loop
 
501
         * forever (for example, a non-writable $PGDATA directory might cause
 
502
         * a failure that won't go away).  100 tries seems like plenty.
 
503
         */
 
504
        for (ntries = 0;; ntries++)
 
505
        {
 
506
                /*
 
507
                 * Try to create the lock file --- O_EXCL makes this atomic.
 
508
                 *
 
509
                 * Think not to make the file protection weaker than 0600.  See
 
510
                 * comments below.
 
511
                 */
 
512
                fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
 
513
                if (fd >= 0)
 
514
                        break;                          /* Success; exit the retry loop */
 
515
 
 
516
                /*
 
517
                 * Couldn't create the pid file. Probably it already exists.
 
518
                 */
 
519
                if ((errno != EEXIST && errno != EACCES) || ntries > 100)
 
520
                        ereport(FATAL,
 
521
                                        (errcode_for_file_access(),
 
522
                                         errmsg("could not create lock file \"%s\": %m",
 
523
                                                        filename)));
 
524
 
 
525
                /*
 
526
                 * Read the file to get the old owner's PID.  Note race condition
 
527
                 * here: file might have been deleted since we tried to create it.
 
528
                 */
 
529
                fd = open(filename, O_RDONLY, 0600);
 
530
                if (fd < 0)
 
531
                {
 
532
                        if (errno == ENOENT)
 
533
                                continue;               /* race condition; try again */
 
534
                        ereport(FATAL,
 
535
                                        (errcode_for_file_access(),
 
536
                                         errmsg("could not open lock file \"%s\": %m",
 
537
                                                        filename)));
 
538
                }
 
539
                if ((len = read(fd, buffer, sizeof(buffer) - 1)) < 0)
 
540
                        ereport(FATAL,
 
541
                                        (errcode_for_file_access(),
 
542
                                         errmsg("could not read lock file \"%s\": %m",
 
543
                                                        filename)));
 
544
                close(fd);
 
545
 
 
546
                buffer[len] = '\0';
 
547
                encoded_pid = atoi(buffer);
 
548
 
 
549
                /* if pid < 0, the pid is for postgres, not postmaster */
 
550
                other_pid = (pid_t) (encoded_pid < 0 ? -encoded_pid : encoded_pid);
 
551
 
 
552
                if (other_pid <= 0)
 
553
                        elog(FATAL, "bogus data in lock file \"%s\"", filename);
 
554
 
 
555
                /*
 
556
                 * Check to see if the other process still exists
 
557
                 *
 
558
                 * If the PID in the lockfile is our own PID or our parent's PID,
 
559
                 * then the file must be stale (probably left over from a previous
 
560
                 * system boot cycle).  We need this test because of the likelihood
 
561
                 * that a reboot will assign exactly the same PID as we had in the
 
562
                 * previous reboot.  Also, if there is just one more process launch
 
563
                 * in this reboot than in the previous one, the lockfile might mention
 
564
                 * our parent's PID.  We can reject that since we'd never be launched
 
565
                 * directly by a competing postmaster.  We can't detect grandparent
 
566
                 * processes unfortunately, but if the init script is written carefully
 
567
                 * then all but the immediate parent shell will be root-owned processes
 
568
                 * and so the kill test will fail with EPERM.
 
569
                 *
 
570
                 * We can treat the EPERM-error case as okay because that error implies
 
571
                 * that the existing process has a different userid than we do, which
 
572
                 * means it cannot be a competing postmaster.  A postmaster cannot
 
573
                 * successfully attach to a data directory owned by a userid other
 
574
                 * than its own.  (This is now checked directly in checkDataDir(),
 
575
                 * but has been true for a long time because of the restriction that
 
576
                 * the data directory isn't group- or world-accessible.)  Also,
 
577
                 * since we create the lockfiles mode 600, we'd have failed above
 
578
                 * if the lockfile belonged to another userid --- which means that
 
579
                 * whatever process kill() is reporting about isn't the one that
 
580
                 * made the lockfile.  (NOTE: this last consideration is the only
 
581
                 * one that keeps us from blowing away a Unix socket file belonging
 
582
                 * to an instance of Postgres being run by someone else, at least
 
583
                 * on machines where /tmp hasn't got a stickybit.)
 
584
                 *
 
585
                 * Windows hasn't got getppid(), but doesn't need it since it's not
 
586
                 * using real kill() either...
 
587
                 *
 
588
                 * Normally kill() will fail with ESRCH if the given PID doesn't
 
589
                 * exist.  BeOS returns EINVAL for some silly reason, however.
 
590
                 */
 
591
                if (other_pid != my_pid
 
592
#ifndef WIN32
 
593
                        && other_pid != getppid()
 
594
#endif
 
595
                        )
 
596
                {
 
597
                        if (kill(other_pid, 0) == 0 ||
 
598
                                (errno != ESRCH &&
 
599
#ifdef __BEOS__
 
600
                                 errno != EINVAL &&
 
601
#endif
 
602
                                 errno != EPERM))
 
603
                        {
 
604
                                /* lockfile belongs to a live process */
 
605
                                ereport(FATAL,
 
606
                                                (errcode(ERRCODE_LOCK_FILE_EXISTS),
 
607
                                                 errmsg("lock file \"%s\" already exists",
 
608
                                                                filename),
 
609
                                                 isDDLock ?
 
610
                                                 (encoded_pid < 0 ?
 
611
                                                  errhint("Is another postgres (PID %d) running in data directory \"%s\"?",
 
612
                                                                  (int) other_pid, refName) :
 
613
                                                  errhint("Is another postmaster (PID %d) running in data directory \"%s\"?",
 
614
                                                                  (int) other_pid, refName)) :
 
615
                                                 (encoded_pid < 0 ?
 
616
                                                  errhint("Is another postgres (PID %d) using socket file \"%s\"?",
 
617
                                                                  (int) other_pid, refName) :
 
618
                                                  errhint("Is another postmaster (PID %d) using socket file \"%s\"?",
 
619
                                                                  (int) other_pid, refName))));
 
620
                        }
 
621
                }
 
622
 
 
623
                /*
 
624
                 * No, the creating process did not exist.      However, it could be
 
625
                 * that the postmaster crashed (or more likely was kill -9'd by a
 
626
                 * clueless admin) but has left orphan backends behind.  Check for
 
627
                 * this by looking to see if there is an associated shmem segment
 
628
                 * that is still in use.
 
629
                 */
 
630
                if (isDDLock)
 
631
                {
 
632
                        char       *ptr;
 
633
                        unsigned long id1,
 
634
                                                id2;
 
635
 
 
636
                        ptr = strchr(buffer, '\n');
 
637
                        if (ptr != NULL &&
 
638
                                (ptr = strchr(ptr + 1, '\n')) != NULL)
 
639
                        {
 
640
                                ptr++;
 
641
                                if (sscanf(ptr, "%lu %lu", &id1, &id2) == 2)
 
642
                                {
 
643
                                        if (PGSharedMemoryIsInUse(id1, id2))
 
644
                                                ereport(FATAL,
 
645
                                                                (errcode(ERRCODE_LOCK_FILE_EXISTS),
 
646
                                                           errmsg("pre-existing shared memory block "
 
647
                                                                          "(key %lu, ID %lu) is still in use",
 
648
                                                                          id1, id2),
 
649
                                                           errhint("If you're sure there are no old "
 
650
                                                                "server processes still running, remove "
 
651
                                                                           "the shared memory block with "
 
652
                                                                           "the command \"ipcrm\", or just delete the file \"%s\".",
 
653
                                                                           filename)));
 
654
                                }
 
655
                        }
 
656
                }
 
657
 
 
658
                /*
 
659
                 * Looks like nobody's home.  Unlink the file and try again to
 
660
                 * create it.  Need a loop because of possible race condition
 
661
                 * against other would-be creators.
 
662
                 */
 
663
                if (unlink(filename) < 0)
 
664
                        ereport(FATAL,
 
665
                                        (errcode_for_file_access(),
 
666
                                         errmsg("could not remove old lock file \"%s\": %m",
 
667
                                                        filename),
 
668
                                         errhint("The file seems accidentally left over, but "
 
669
                                           "it could not be removed. Please remove the file "
 
670
                                                         "by hand and try again.")));
 
671
        }
 
672
 
 
673
        /*
 
674
         * Successfully created the file, now fill it.
 
675
         */
 
676
        snprintf(buffer, sizeof(buffer), "%d\n%s\n",
 
677
                         amPostmaster ? (int) my_pid : -((int) my_pid),
 
678
                         DataDir);
 
679
        errno = 0;
 
680
        if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
 
681
        {
 
682
                int                     save_errno = errno;
 
683
 
 
684
                close(fd);
 
685
                unlink(filename);
 
686
                /* if write didn't set errno, assume problem is no disk space */
 
687
                errno = save_errno ? save_errno : ENOSPC;
 
688
                ereport(FATAL,
 
689
                                (errcode_for_file_access(),
 
690
                          errmsg("could not write lock file \"%s\": %m", filename)));
 
691
        }
 
692
        if (close(fd))
 
693
        {
 
694
                int                     save_errno = errno;
 
695
 
 
696
                unlink(filename);
 
697
                errno = save_errno;
 
698
                ereport(FATAL,
 
699
                                (errcode_for_file_access(),
 
700
                          errmsg("could not write lock file \"%s\": %m", filename)));
 
701
        }
 
702
 
 
703
        /*
 
704
         * Arrange for automatic removal of lockfile at proc_exit.
 
705
         */
 
706
        on_proc_exit(UnlinkLockFile, PointerGetDatum(strdup(filename)));
 
707
}
 
708
 
 
709
void
 
710
CreateDataDirLockFile(const char *datadir, bool amPostmaster)
 
711
{
 
712
        char            lockfile[MAXPGPATH];
 
713
 
 
714
        snprintf(lockfile, sizeof(lockfile), "%s/postmaster.pid", datadir);
 
715
        CreateLockFile(lockfile, amPostmaster, true, datadir);
 
716
        /* Save name of lockfile for RecordSharedMemoryInLockFile */
 
717
        strcpy(directoryLockFile, lockfile);
 
718
}
 
719
 
 
720
void
 
721
CreateSocketLockFile(const char *socketfile, bool amPostmaster)
 
722
{
 
723
        char            lockfile[MAXPGPATH];
 
724
 
 
725
        snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
 
726
        CreateLockFile(lockfile, amPostmaster, false, socketfile);
 
727
        /* Save name of lockfile for TouchSocketLockFile */
 
728
        strcpy(socketLockFile, lockfile);
 
729
}
 
730
 
 
731
/*
 
732
 * TouchSocketLockFile -- mark socket lock file as recently accessed
 
733
 *
 
734
 * This routine should be called every so often to ensure that the lock file
 
735
 * has a recent mod or access date.  That saves it
 
736
 * from being removed by overenthusiastic /tmp-directory-cleaner daemons.
 
737
 * (Another reason we should never have put the socket file in /tmp...)
 
738
 */
 
739
void
 
740
TouchSocketLockFile(void)
 
741
{
 
742
        /* Do nothing if we did not create a socket... */
 
743
        if (socketLockFile[0] != '\0')
 
744
        {
 
745
                /*
 
746
                 * utime() is POSIX standard, utimes() is a common alternative; if
 
747
                 * we have neither, fall back to actually reading the file (which
 
748
                 * only sets the access time not mod time, but that should be
 
749
                 * enough in most cases).  In all paths, we ignore errors.
 
750
                 */
 
751
#ifdef HAVE_UTIME
 
752
                utime(socketLockFile, NULL);
 
753
#else                                                   /* !HAVE_UTIME */
 
754
#ifdef HAVE_UTIMES
 
755
                utimes(socketLockFile, NULL);
 
756
#else                                                   /* !HAVE_UTIMES */
 
757
                int                     fd;
 
758
                char            buffer[1];
 
759
 
 
760
                fd = open(socketLockFile, O_RDONLY | PG_BINARY, 0);
 
761
                if (fd >= 0)
 
762
                {
 
763
                        read(fd, buffer, sizeof(buffer));
 
764
                        close(fd);
 
765
                }
 
766
#endif   /* HAVE_UTIMES */
 
767
#endif   /* HAVE_UTIME */
 
768
        }
 
769
}
 
770
 
 
771
/*
 
772
 * Append information about a shared memory segment to the data directory
 
773
 * lock file (if we have created one).
 
774
 *
 
775
 * This may be called multiple times in the life of a postmaster, if we
 
776
 * delete and recreate shmem due to backend crash.      Therefore, be prepared
 
777
 * to overwrite existing information.  (As of 7.1, a postmaster only creates
 
778
 * one shm seg at a time; but for the purposes here, if we did have more than
 
779
 * one then any one of them would do anyway.)
 
780
 */
 
781
void
 
782
RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2)
 
783
{
 
784
        int                     fd;
 
785
        int                     len;
 
786
        char       *ptr;
 
787
        char            buffer[BLCKSZ];
 
788
 
 
789
        /*
 
790
         * Do nothing if we did not create a lockfile (probably because we are
 
791
         * running standalone).
 
792
         */
 
793
        if (directoryLockFile[0] == '\0')
 
794
                return;
 
795
 
 
796
        fd = open(directoryLockFile, O_RDWR | PG_BINARY, 0);
 
797
        if (fd < 0)
 
798
        {
 
799
                ereport(LOG,
 
800
                                (errcode_for_file_access(),
 
801
                                 errmsg("could not open file \"%s\": %m",
 
802
                                                directoryLockFile)));
 
803
                return;
 
804
        }
 
805
        len = read(fd, buffer, sizeof(buffer) - 100);
 
806
        if (len < 0)
 
807
        {
 
808
                ereport(LOG,
 
809
                                (errcode_for_file_access(),
 
810
                                 errmsg("could not read from file \"%s\": %m",
 
811
                                                directoryLockFile)));
 
812
                close(fd);
 
813
                return;
 
814
        }
 
815
        buffer[len] = '\0';
 
816
 
 
817
        /*
 
818
         * Skip over first two lines (PID and path).
 
819
         */
 
820
        ptr = strchr(buffer, '\n');
 
821
        if (ptr == NULL ||
 
822
                (ptr = strchr(ptr + 1, '\n')) == NULL)
 
823
        {
 
824
                elog(LOG, "bogus data in \"%s\"", directoryLockFile);
 
825
                close(fd);
 
826
                return;
 
827
        }
 
828
        ptr++;
 
829
 
 
830
        /*
 
831
         * Append key information.      Format to try to keep it the same length
 
832
         * always (trailing junk won't hurt, but might confuse humans).
 
833
         */
 
834
        sprintf(ptr, "%9lu %9lu\n", id1, id2);
 
835
 
 
836
        /*
 
837
         * And rewrite the data.  Since we write in a single kernel call, this
 
838
         * update should appear atomic to onlookers.
 
839
         */
 
840
        len = strlen(buffer);
 
841
        errno = 0;
 
842
        if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
 
843
                (int) write(fd, buffer, len) != len)
 
844
        {
 
845
                /* if write didn't set errno, assume problem is no disk space */
 
846
                if (errno == 0)
 
847
                        errno = ENOSPC;
 
848
                ereport(LOG,
 
849
                                (errcode_for_file_access(),
 
850
                                 errmsg("could not write to file \"%s\": %m",
 
851
                                                directoryLockFile)));
 
852
                close(fd);
 
853
                return;
 
854
        }
 
855
        if (close(fd))
 
856
        {
 
857
                ereport(LOG,
 
858
                                (errcode_for_file_access(),
 
859
                                 errmsg("could not write to file \"%s\": %m",
 
860
                                                directoryLockFile)));
 
861
        }
 
862
}
 
863
 
 
864
 
 
865
/*-------------------------------------------------------------------------
 
866
 *                              Version checking support
 
867
 *-------------------------------------------------------------------------
 
868
 */
 
869
 
 
870
/*
 
871
 * Determine whether the PG_VERSION file in directory `path' indicates
 
872
 * a data version compatible with the version of this program.
 
873
 *
 
874
 * If compatible, return. Otherwise, ereport(FATAL).
 
875
 */
 
876
void
 
877
ValidatePgVersion(const char *path)
 
878
{
 
879
        char            full_path[MAXPGPATH];
 
880
        FILE       *file;
 
881
        int                     ret;
 
882
        long            file_major,
 
883
                                file_minor;
 
884
        long            my_major = 0,
 
885
                                my_minor = 0;
 
886
        char       *endptr;
 
887
        const char *version_string = PG_VERSION;
 
888
 
 
889
        my_major = strtol(version_string, &endptr, 10);
 
890
        if (*endptr == '.')
 
891
                my_minor = strtol(endptr + 1, NULL, 10);
 
892
 
 
893
        snprintf(full_path, sizeof(full_path), "%s/PG_VERSION", path);
 
894
 
 
895
        file = AllocateFile(full_path, "r");
 
896
        if (!file)
 
897
        {
 
898
                if (errno == ENOENT)
 
899
                        ereport(FATAL,
 
900
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
901
                                         errmsg("\"%s\" is not a valid data directory",
 
902
                                                        path),
 
903
                                         errdetail("File \"%s\" is missing.", full_path)));
 
904
                else
 
905
                        ereport(FATAL,
 
906
                                        (errcode_for_file_access(),
 
907
                                   errmsg("could not open file \"%s\": %m", full_path)));
 
908
        }
 
909
 
 
910
        ret = fscanf(file, "%ld.%ld", &file_major, &file_minor);
 
911
        if (ret != 2)
 
912
                ereport(FATAL,
 
913
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
914
                                 errmsg("\"%s\" is not a valid data directory",
 
915
                                                path),
 
916
                                 errdetail("File \"%s\" does not contain valid data.",
 
917
                                                   full_path),
 
918
                                 errhint("You may need to initdb.")));
 
919
 
 
920
        FreeFile(file);
 
921
 
 
922
        if (my_major != file_major || my_minor != file_minor)
 
923
                ereport(FATAL,
 
924
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
925
                                 errmsg("database files are incompatible with server"),
 
926
                                 errdetail("The data directory was initialized by PostgreSQL version %ld.%ld, "
 
927
                                                 "which is not compatible with this version %s.",
 
928
                                                   file_major, file_minor, version_string)));
 
929
}
 
930
 
 
931
/*-------------------------------------------------------------------------
 
932
 *                              Library preload support
 
933
 *-------------------------------------------------------------------------
 
934
 */
 
935
 
 
936
typedef void (*func_ptr) ();
 
937
 
 
938
/*
 
939
 * process any libraries that should be preloaded and
 
940
 * optionally pre-initialized
 
941
 */
 
942
void
 
943
process_preload_libraries(char *preload_libraries_string)
 
944
{
 
945
        char       *rawstring;
 
946
        List       *elemlist;
 
947
        ListCell   *l;
 
948
 
 
949
        if (preload_libraries_string == NULL)
 
950
                return;
 
951
 
 
952
        /* Need a modifiable copy of string */
 
953
        rawstring = pstrdup(preload_libraries_string);
 
954
 
 
955
        /* Parse string into list of identifiers */
 
956
        if (!SplitIdentifierString(rawstring, ',', &elemlist))
 
957
        {
 
958
                /* syntax error in list */
 
959
                pfree(rawstring);
 
960
                list_free(elemlist);
 
961
                ereport(LOG,
 
962
                                (errcode(ERRCODE_SYNTAX_ERROR),
 
963
                                 errmsg("invalid list syntax for parameter \"preload_libraries\"")));
 
964
                return;
 
965
        }
 
966
 
 
967
        foreach(l, elemlist)
 
968
        {
 
969
                char       *tok = (char *) lfirst(l);
 
970
                char       *sep = strstr(tok, ":");
 
971
                char       *filename = NULL;
 
972
                char       *funcname = NULL;
 
973
                func_ptr        initfunc;
 
974
 
 
975
                if (sep)
 
976
                {
 
977
                        /*
 
978
                         * a colon separator implies there is an initialization
 
979
                         * function that we need to run in addition to loading the
 
980
                         * library
 
981
                         */
 
982
                        size_t          filename_len = sep - tok;
 
983
                        size_t          funcname_len = strlen(tok) - filename_len - 1;
 
984
 
 
985
                        filename = (char *) palloc(filename_len + 1);
 
986
                        memcpy(filename, tok, filename_len);
 
987
                        filename[filename_len] = '\0';
 
988
 
 
989
                        funcname = (char *) palloc(funcname_len + 1);
 
990
                        strcpy(funcname, sep + 1);
 
991
                }
 
992
                else
 
993
                {
 
994
                        /*
 
995
                         * no separator -- just load the library
 
996
                         */
 
997
                        filename = pstrdup(tok);
 
998
                        funcname = NULL;
 
999
                }
 
1000
 
 
1001
                canonicalize_path(filename);
 
1002
                initfunc = (func_ptr) load_external_function(filename, funcname,
 
1003
                                                                                                         true, NULL);
 
1004
                if (initfunc)
 
1005
                        (*initfunc) ();
 
1006
 
 
1007
                if (funcname)
 
1008
                        ereport(LOG,
 
1009
                                        (errmsg("preloaded library \"%s\" with initialization function \"%s\"",
 
1010
                                                        filename, funcname)));
 
1011
                else
 
1012
                        ereport(LOG,
 
1013
                                        (errmsg("preloaded library \"%s\"",
 
1014
                                                        filename)));
 
1015
 
 
1016
                pfree(filename);
 
1017
                if (funcname)
 
1018
                        pfree(funcname);
 
1019
        }
 
1020
 
 
1021
        pfree(rawstring);
 
1022
        list_free(elemlist);
 
1023
}