]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/postinit.c
Remove more (void) and fix -Wall warnings.
[postgresql] / src / backend / utils / init / postinit.c
1 /*-------------------------------------------------------------------------
2  *
3  * postinit.c--
4  *    postgres initialization utilities
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.10 1997/08/12 22:54:54 momjian Exp $
11  *
12  * NOTES
13  *      InitPostgres() is the function called from PostgresMain
14  *      which does all non-trival initialization, mainly by calling
15  *      all the other initialization functions.  InitPostgres()
16  *      is only used within the "postgres" backend and so that routine
17  *      is in tcop/postgres.c  InitPostgres() is needed in cinterface.a
18  *      because things like the bootstrap backend program need it. Hence
19  *      you find that in this file...
20  *
21  *      If you feel the need to add more initialization code, it should be
22  *      done in InitPostgres() or someplace lower.  Do not start
23  *      putting stuff in PostgresMain - if you do then someone
24  *      will have to clean it up later, and it's not going to be me!
25  *      -cim 10/3/90
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/file.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <math.h>
36 #include <unistd.h>
37
38 #include "postgres.h"
39 #include "version.h"
40
41 #include <storage/ipc.h>
42 #include <storage/backendid.h>
43 #include <storage/buf_internals.h>
44 #include <storage/smgr.h>
45 #include <storage/proc.h>
46 #include <utils/relcache.h>
47
48 #include "access/heapam.h"
49 #include "access/xact.h"
50 #include "storage/bufmgr.h"
51 #include "access/transam.h"     /* XXX dependency problem */
52 #include "utils/tqual.h"
53 #include "utils/syscache.h"
54 #include "storage/bufpage.h"    /* for page layout, for InitMyDatabaseId() */
55 #include "storage/sinval.h"
56 #include "storage/sinvaladt.h"
57 #include "storage/lmgr.h"
58
59 #include "miscadmin.h"         /* for global decls */
60 #include "utils/portal.h"       /* for EnablePortalManager, etc. */
61
62 #include "utils/exc.h"          /* for EnableExceptionHandling, etc. */
63 #include "fmgr.h"               /* for EnableDynamicFunctionManager, etc. */
64 #include "utils/elog.h"
65 #include "utils/palloc.h"
66 #include "utils/mcxt.h"         /* for EnableMemoryContext, etc. */
67
68 #include "catalog/catname.h"
69 #include "catalog/pg_database.h"
70
71 #include "port-protos.h"
72 #include "libpq/libpq-be.h"
73
74
75 static IPCKey           PostgresIpcKey;
76
77
78 #ifndef private
79 #ifndef EBUG
80 #define private static
81 #else   /* !defined(EBUG) */
82 #define private
83 #endif  /* !defined(EBUG) */
84 #endif  /* !defined(private) */
85
86 /* ----------------------------------------------------------------
87  *                      InitPostgres support
88  * ----------------------------------------------------------------
89  */
90
91 /* --------------------------------
92  *  InitMyDatabaseId() -- Find and record the OID of the database we are
93  *                        to open.
94  *
95  *      The database's oid forms half of the unique key for the system
96  *      caches and lock tables.  We therefore want it initialized before
97  *      we open any relations, since opening relations puts things in the
98  *      cache.  To get around this problem, this code opens and scans the
99  *      pg_database relation by hand.
100  *
101  *      This algorithm relies on the fact that first attribute in the
102  *      pg_database relation schema is the database name.  It also knows
103  *      about the internal format of tuples on disk and the length of
104  *      the datname attribute.  It knows the location of the pg_database
105  *      file.
106  *
107  *      This code is called from InitDatabase(), after we chdir() to the
108  *      database directory but before we open any relations.
109  * --------------------------------
110  */
111 void
112 InitMyDatabaseId()
113 {
114     int         dbfd;
115     int         fileflags;
116     int         nbytes;
117     int         max, i;
118     HeapTuple   tup;
119     Page        pg;
120     PageHeader  ph;
121     char        *dbfname;
122     Form_pg_database    tup_db;
123     
124     /*
125      *  At bootstrap time, we don't need to check the oid of the database
126      *  in use, since we're not using shared memory.  This is lucky, since
127      *  the database may not be in the tables yet.
128      */
129     
130     if (IsBootstrapProcessingMode()) {
131         LockDisable(true);
132         return;
133     }
134     
135     dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2);
136     sprintf(dbfname, "%s%cpg_database", DataDir, SEP_CHAR);
137     fileflags = O_RDONLY;
138     
139     if ((dbfd = open(dbfname, O_RDONLY, 0666)) < 0)
140         elog(FATAL, "Cannot open %s", dbfname);
141     
142     pfree(dbfname);
143     
144     /* ----------------
145      *  read and examine every page in pg_database
146      *
147      *  Raw I/O! Read those tuples the hard way! Yow!
148      *
149      *  Why don't we use the access methods or move this code
150      *  someplace else?  This is really pg_database schema dependent
151      *  code.  Perhaps it should go in lib/catalog/pg_database?
152      *  -cim 10/3/90
153      *
154      *  mao replies 4 apr 91:  yeah, maybe this should be moved to
155      *  lib/catalog.  however, we CANNOT use the access methods since
156      *  those use the buffer cache, which uses the relation cache, which
157      *  requires that the dbid be set, which is what we're trying to do
158      *  here.
159      * ----------------
160      */
161     pg = (Page) palloc(BLCKSZ);
162     ph = (PageHeader) pg;
163     
164     while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ) {
165         max = PageGetMaxOffsetNumber(pg);
166         
167         /* look at each tuple on the page */
168         for (i = 0; i <= max; i++) {
169             int offset;
170             
171             /* if it's a freed tuple, ignore it */
172             if (!(ph->pd_linp[i].lp_flags & LP_USED))
173                 continue;
174             
175             /* get a pointer to the tuple itself */
176             offset = (int) ph->pd_linp[i].lp_off;
177             tup = (HeapTuple) (((char *) pg) + offset);
178             
179             /*
180              *  if the tuple has been deleted (the database was destroyed),
181              *  skip this tuple.  XXX warning, will robinson:  violation of
182              *  transaction semantics happens right here.  we should check
183              *  to be sure that the xact that deleted this tuple actually
184              *  committed.  only way to do this at init time is to paw over
185              *  the log relation by hand, too.  let's be optimistic.
186              *
187              *  XXX This is an evil type cast.  tup->t_xmax is char[5] while
188              *  TransactionId is struct * { char data[5] }.  It works but
189              *  if data is ever moved and no longer the first field this 
190              *  will be broken!! -mer 11 Nov 1991.
191              */
192             if (TransactionIdIsValid((TransactionId)tup->t_xmax))
193                 continue;
194             
195             /*
196              *  Okay, see if this is the one we want.
197              *  XXX 1 july 91:  mao and mer discover that tuples now squash
198              *                  t_bits.  Why is this?
199              *
200              *     24 july 92:  mer realizes that the t_bits field is only
201              *                  used in the event of null values.  If no
202              *                  fields are null we reduce the header size
203              *                  by doing the squash.  t_hoff tells you exactly
204              *                  how big the header actually is. use the PC
205              *                  means of getting at sys cat attrs.
206              */
207             tup_db = (Form_pg_database)GETSTRUCT(tup);
208             
209             if (strncmp(GetDatabaseName(),
210                         &(tup_db->datname.data[0]),
211                         16) == 0)
212                 {
213                     MyDatabaseId = tup->t_oid;
214                     goto done;
215                 }
216         }
217     }
218     
219  done:
220     close(dbfd);
221     pfree(pg);
222     
223     if (!OidIsValid(MyDatabaseId))
224         elog(FATAL,
225              "Database %s does not exist in %s",
226              GetDatabaseName(),
227              DatabaseRelationName);
228 }
229
230
231
232 /*
233  * DoChdirAndInitDatabaseNameAndPath --
234  *      Set current directory to the database directory for the database
235  *      named <name>.
236  *      Also set global variables DatabasePath and DatabaseName to those
237  *      values.  Also check for proper version of database system and
238  *      database.  Exit program via elog() if anything doesn't check out.
239  *
240  * Arguments:
241  *      Path and name are invalid if it invalid as a string.
242  *      Path is "badly formated" if it is not a string containing a path
243  *      to a writable directory.
244  *      Name is "badly formated" if it contains more than 16 characters or if
245  *      it is a bad file name (e.g., it contains a '/' or an 8-bit character).
246  *
247  * Exceptions:
248  *      BadState if called more than once.
249  *      BadArg if both path and name are "badly formated" or invalid.
250  *      BadArg if path and name are both "inconsistent" and valid.
251  *
252  *      This routine is inappropriate in bootstrap mode, since the directories
253  *      and version files need not exist yet if we're in bootstrap mode.
254  */
255 static void
256 DoChdirAndInitDatabaseNameAndPath(char *name) {
257     char *reason;  
258       /* Failure reason returned by some function.  NULL if no failure */
259     struct stat statbuf;
260     char errormsg[1000];
261
262     if (stat(DataDir, &statbuf) < 0) 
263         sprintf(errormsg, "Database system does not exist.  "
264                 "PGDATA directory '%s' not found.  Normally, you "
265                 "create a database system by running initdb.",
266                 DataDir);
267     else {
268         char myPath[MAXPGPATH];  /* DatabasePath points here! */
269         
270         if (strlen(DataDir) + strlen(name) + 10 > sizeof(myPath))
271             sprintf(errormsg, "Internal error in postinit.c: database "
272                     "pathname exceeds maximum allowable length.");
273         else {
274             sprintf(myPath, "%s/base/%s", DataDir, name);
275
276             if (stat(myPath, &statbuf) < 0) 
277                 sprintf(errormsg, 
278                         "Database '%s' does not exist.  "
279                         "(We know this because the directory '%s' "
280                         "does not exist).  You can create a database "
281                         "with the SQL command CREATE DATABASE.  To see "
282                         "what databases exist, look at the subdirectories "
283                         "of '%s/base/'.",
284                         name, myPath, DataDir);
285             else {
286                 ValidatePgVersion(DataDir, &reason);
287                 if (reason != NULL) 
288                     sprintf(errormsg, 
289                         "InitPostgres could not validate that the database "
290                         "system version is compatible with this level of "
291                         "Postgres.  You may need to run initdb to create "
292                         "a new database system.  %s", 
293                         reason);
294                 else {
295                     ValidatePgVersion(myPath, &reason);
296                     if (reason != NULL)
297                         sprintf(errormsg, 
298                             "InitPostgres could not validate that the "
299                             "database version is compatible with this level "
300                             "of Postgres, even though the database system "
301                             "as a whole appears to be at a compatible level.  "
302                             "You may need to recreate the database with SQL "
303                             "commands DROP DATABASE and CREATE DATABASE.  "
304                             "%s",
305                             reason);
306                     else {
307                         /* The directories and PG_VERSION files are in order.*/
308                         int rc;  /* return code from some function we call */
309                     
310                         SetDatabasePath(myPath);
311                         SetDatabaseName(name);
312                         rc = chdir(myPath);
313                         if (rc < 0)
314                            sprintf(errormsg, 
315                                "InitPostgres unable to change "
316                                "current directory to '%s', errno = %s (%d).",
317                                myPath, strerror(errno), errno);
318                         else errormsg[0] = '\0';
319                     }
320                 }
321             }
322         }
323     }
324     if (errormsg[0] != '\0')
325         elog(FATAL, errormsg);
326         /* Above does not return */
327 }
328
329
330
331 /* --------------------------------
332  *      InitUserid
333  *
334  *      initializes crap associated with the user id.
335  * --------------------------------
336  */
337 void
338 InitUserid()
339 {
340     setuid(geteuid());
341     SetUserId();
342 }
343
344 /* --------------------------------
345  *      InitCommunication
346  *
347  *      This routine initializes stuff needed for ipc, locking, etc.
348  *      it should be called something more informative.
349  *
350  * Note:
351  *      This does not set MyBackendId.  MyBackendTag is set, however.
352  * --------------------------------
353  */
354 void
355 InitCommunication()
356 {
357     char *postid;
358     char *postport;
359     IPCKey      key = 0;
360     
361     /* ----------------
362      *  try and get the backend tag from POSTID
363      * ----------------
364      */
365     MyBackendId = -1;
366     
367     postid = getenv("POSTID");
368     if (!PointerIsValid(postid)) {
369         MyBackendTag = -1;
370     } else {
371         MyBackendTag = atoi(postid);
372         Assert(MyBackendTag >= 0);
373     }
374     
375     /* ----------------
376      *  try and get the ipc key from POSTPORT
377      * ----------------
378      */
379     postport = getenv("POSTPORT");
380     
381     if (PointerIsValid(postport)) {
382         SystemPortAddress address = atoi(postport);
383         
384         if (address == 0)
385             elog(FATAL, "InitCommunication: invalid POSTPORT");
386         
387         if (MyBackendTag == -1)
388             elog(FATAL, "InitCommunication: missing POSTID");
389         
390         key = SystemPortAddressCreateIPCKey(address);
391         
392         /*
393          * Enable this if you are trying to force the backend to run as if it 
394          * is running under the postmaster.
395          *
396          * This goto forces Postgres to attach to shared memory instead of 
397          * using malloc'ed memory (which is the normal behavior if run
398          * directly).
399          *
400          * To enable emulation, run the following shell commands (in addition
401          * to enabling this goto)
402          *
403          *     % setenv POSTID 1
404          *     % setenv POSTPORT 4321
405          *     % postmaster &
406          *     % kill -9 %1
407          *
408          * Upon doing this, Postmaster will have allocated the shared memory 
409          * resources that Postgres will attach to if you enable
410          * EMULATE_UNDER_POSTMASTER.
411          *
412          * This comment may well age with time - it is current as of
413          * 8 January 1990
414          * 
415          * Greg
416          */
417         
418 #ifdef EMULATE_UNDER_POSTMASTER
419         
420         goto forcesharedmemory;
421         
422 #endif
423         
424     } else if (IsUnderPostmaster) {
425         elog(FATAL,
426              "InitCommunication: under postmaster and POSTPORT not set");
427     } else {
428         /* ----------------
429          *  assume we're running a postgres backend by itself with
430          *  no front end or postmaster.
431          * ----------------
432          */
433         if (MyBackendTag == -1) {
434             MyBackendTag = 1;
435         }
436         
437         key = PrivateIPCKey;
438     }
439     
440     /* ----------------
441      *  initialize shared memory and semaphores appropriately.
442      * ----------------
443      */
444 #ifdef EMULATE_UNDER_POSTMASTER
445     
446  forcesharedmemory:
447     
448 #endif
449     
450     PostgresIpcKey = key;
451     AttachSharedMemoryAndSemaphores(key);
452 }
453
454
455 /* --------------------------------
456  *      InitStdio
457  *
458  *      this routine consists of a bunch of code fragments
459  *      that used to be randomly scattered through cinit().
460  *      they all seem to do stuff associated with io.
461  * --------------------------------
462  */
463 void
464 InitStdio()
465 {
466     DebugFileOpen();
467 }
468
469 /* --------------------------------
470  * InitPostgres --
471  *      Initialize POSTGRES.
472  *
473  * Note:
474  *      Be very careful with the order of calls in the InitPostgres function.
475  * --------------------------------
476  */
477 bool PostgresIsInitialized = false;
478 extern int NBuffers;
479
480 /*
481  *  this global is used by wei for testing his code, but must be declared
482  *  here rather than in postgres.c so that it's defined for cinterface.a
483  *  applications.
484  */
485
486 /*int   testFlag = 0;*/
487 int     lockingOff = 0;
488
489 /*
490  */
491 void
492 InitPostgres(char *name)        /* database name */
493 {
494     bool        bootstrap;      /* true if BootstrapProcessing */
495     
496     /* ----------------
497      *  see if we're running in BootstrapProcessing mode
498      * ----------------
499      */
500     bootstrap = IsBootstrapProcessingMode();
501     
502     /* ----------------
503      *  turn on the exception handler.  Note: we cannot use elog, Assert,
504      *  AssertState, etc. until after exception handling is on.
505      * ----------------
506      */
507     EnableExceptionHandling(true);
508     
509     /* ----------------
510      *  A stupid check to make sure we don't call this more than once.
511      *  But things like ReinitPostgres() get around this by just diddling
512      *  the PostgresIsInitialized flag.
513      * ----------------
514      */
515     AssertState(!PostgresIsInitialized);
516     
517     /* ----------------
518      *  Memory system initialization.
519      *  (we may call palloc after EnableMemoryContext())
520      *
521      *  Note EnableMemoryContext() must happen before EnablePortalManager().
522      * ----------------
523      */
524     EnableMemoryContext(true);  /* initializes the "top context" */
525     EnablePortalManager(true);  /* memory for portal/transaction stuff */
526     
527     /* ----------------
528      *  initialize the backend local portal stack used by
529      *  internal PQ function calls.  see src/lib/libpq/be-dumpdata.c
530      *  This is different from the "portal manager" so this goes here.
531      *  -cim 2/12/91
532      * ----------------
533      */    
534     be_portalinit();
535     
536     /* ----------------
537      *   attach to shared memory and semaphores, and initialize our
538      *   input/output/debugging file descriptors.
539      * ----------------
540      */
541     InitCommunication();
542     InitStdio();
543     
544     /*
545      * initialize the local buffer manager
546      */
547     InitLocalBuffer();
548
549     if (!TransactionFlushEnabled())
550         on_exitpg(FlushBufferPool, (caddr_t) NULL);
551     
552     if (bootstrap) {
553         SetDatabasePath(".");
554         SetDatabaseName(name);
555     } else {
556         DoChdirAndInitDatabaseNameAndPath(name);
557     }
558     
559     /* ********************************
560      *  code after this point assumes we are in the proper directory!
561      * ********************************
562      */
563     
564     /* ----------------
565      *  initialize the database id used for system caches and lock tables
566      * ----------------
567      */
568     InitMyDatabaseId();
569     
570     smgrinit();
571     
572     /* ----------------
573      *  initialize the transaction system and the relation descriptor
574      *  cache.  Note we have to make certain the lock manager is off while
575      *  we do this.
576      * ----------------
577      */
578     AmiTransactionOverride(IsBootstrapProcessingMode());
579     LockDisable(true);
580     
581     /*
582      * Part of the initialization processing done here sets a read
583      * lock on pg_log.  Since locking is disabled the set doesn't have
584      * intended effect of locking out writers, but this is ok, since
585      * we only lock it to examine AMI transaction status, and this is
586      * never written after initdb is done. -mer 15 June 1992
587      */
588     RelationInitialize();          /* pre-allocated reldescs created here */
589     InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */
590     
591     LockDisable(false);
592     
593     /* ----------------
594      *  anyone knows what this does?  something having to do with
595      *  system catalog cache invalidation in the case of multiple
596      *  backends, I think -cim 10/3/90
597      *  Sets up MyBackendId a unique backend identifier.
598      * ----------------
599      */
600     InitSharedInvalidationState();
601     
602     /* ----------------
603      * Set up a per backend process in shared memory.  Must be done after
604      * InitSharedInvalidationState() as it relies on MyBackendId being
605      * initialized already.  XXX -mer 11 Aug 1991
606      * ----------------
607      */
608     InitProcess(PostgresIpcKey);
609     
610     if (MyBackendId > MaxBackendId || MyBackendId <= 0) {
611         elog(FATAL, "cinit2: bad backend id %d (%d)",
612              MyBackendTag,
613              MyBackendId);
614     }
615     
616     /* ----------------
617      *  initialize the access methods.
618      * ----------------
619      */
620     initam();
621     
622     /* ----------------
623      *  initialize all the system catalog caches.
624      * ----------------
625      */
626     zerocaches();
627     InitCatalogCache();
628     
629     /* ----------------
630      *   set ourselves to the proper user id and figure out our postgres
631      *   user id.  If we ever add security so that we check for valid
632      *   postgres users, we might do it here.
633      * ----------------
634      */
635     InitUserid();
636     
637     /* ----------------
638      *  ok, all done, now let's make sure we don't do it again.
639      * ----------------
640      */
641     PostgresIsInitialized = true;
642 /*    on_exitpg(DestroyLocalRelList, (caddr_t) NULL); */
643     
644     /* ----------------
645      *  Done with "InitPostgres", now change to NormalProcessing unless
646      *  we're in BootstrapProcessing mode.
647      * ----------------
648      */
649     if (!bootstrap)
650         SetProcessingMode(NormalProcessing);
651 /*    if (testFlag || lockingOff) */
652     if (lockingOff)
653         LockDisable(true);
654 }
655
656