1 /*-------------------------------------------------------------------------
4 * miscellanious initialization support stuff
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.57 2000/11/16 22:30:39 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include <sys/param.h>
18 #include <sys/types.h>
29 #include "catalog/catname.h"
30 #include "catalog/pg_shadow.h"
31 #include "miscadmin.h"
32 #include "utils/builtins.h"
33 #include "utils/syscache.h"
35 static char *GetPidFname(void);
39 unsigned char RecodeForwTable[128];
40 unsigned char RecodeBackTable[128];
44 ProcessingMode Mode = InitProcessing;
46 /* ----------------------------------------------------------------
47 * ignoring system indexes support stuff
48 * ----------------------------------------------------------------
51 static bool isIgnoringSystemIndexes = false;
54 * IsIgnoringSystemIndexes
55 * True if ignoring system indexes.
58 IsIgnoringSystemIndexes()
60 return isIgnoringSystemIndexes;
65 * Set true or false whether PostgreSQL ignores system indexes.
69 IgnoreSystemIndexes(bool mode)
71 isIgnoringSystemIndexes = mode;
74 /* ----------------------------------------------------------------
75 * database path / name support stuff
76 * ----------------------------------------------------------------
80 SetDatabasePath(const char *path)
83 /* use strdup since this is done before memory contexts are set up */
86 DatabasePath = strdup(path);
87 AssertState(DatabasePath);
92 SetDatabaseName(const char *name)
97 DatabaseName = strdup(name);
98 AssertState(DatabaseName);
103 /* even if MULTIBYTE is not enabled, these functions are necessary
104 * since pg_proc.h has references to them.
108 getdatabaseencoding(PG_FUNCTION_ARGS)
110 PG_RETURN_NAME("SQL_ASCII");
114 PG_encoding_to_char(PG_FUNCTION_ARGS)
116 PG_RETURN_NAME("SQL_ASCII");
120 PG_char_to_encoding(PG_FUNCTION_ARGS)
130 /* Some standard C libraries, including GNU, have an isblank() function.
131 Others, including Solaris, do not. So we have our own.
134 isblank(const char c)
136 return c == ' ' || c == 9 /* tab */ ;
140 next_token(FILE *fp, char *buf, const int bufsz)
142 /*--------------------------------------------------------------------------
143 Grab one token out of fp. Tokens are strings of non-blank
144 characters bounded by blank characters, beginning of line, and end
145 of line. Blank means space or tab. Return the token as *buf.
146 Leave file positioned to character immediately after the token or
147 EOF, whichever comes first. If no more tokens on line, return null
148 string as *buf and position file to beginning of next line or EOF,
149 whichever comes first.
150 --------------------------------------------------------------------------*/
152 char *eb = buf + (bufsz - 1);
154 /* Move over inital token-delimiting blanks */
155 while (isblank(c = getc(fp)));
161 * build a token in buf of next characters up to EOF, eol, or
164 while (c != EOF && c != '\n' && !isblank(c))
171 * Put back the char right after the token (putting back EOF
181 read_through_eol(FILE *file)
187 while (c != '\n' && c != EOF);
200 unsigned char FromChar,
203 for (i = 0; i < 128; i++)
205 RecodeForwTable[i] = i + 128;
206 RecodeBackTable[i] = i + 128;
209 p = getenv("PG_RECODETABLE");
212 map_file = (char *) malloc((strlen(DataDir) +
213 strlen(p) + 2) * sizeof(char));
214 sprintf(map_file, "%s/%s", DataDir, p);
215 file = AllocateFile(map_file, PG_BINARY_R);
228 read_through_eol(file);
231 /* Read the FromChar */
232 next_token(file, buf, sizeof(buf));
235 FromChar = strtoul(buf, 0, 0);
236 /* Read the ToChar */
237 next_token(file, buf, sizeof(buf));
240 ToChar = strtoul(buf, 0, 0);
241 RecodeForwTable[FromChar - 128] = ToChar;
242 RecodeBackTable[ToChar - 128] = FromChar;
244 read_through_eol(file);
255 convertstr(unsigned char *buff, int len, int dest)
260 for (i = 0; i < len; i++, buff++)
265 *buff = RecodeForwTable[*buff - 128];
267 *buff = RecodeBackTable[*buff - 128];
277 /* ----------------------------------------------------------------
280 * The session user is determined at connection start and never
281 * changes. The current user may change when "setuid" functions
282 * are implemented. Conceptually there is a stack, whose bottom
283 * is the session user. You are yourself responsible to save and
284 * restore the current user id if you need to change it.
285 * ----------------------------------------------------------------
287 static Oid CurrentUserId = InvalidOid;
288 static Oid SessionUserId = InvalidOid;
292 * This function is relevant for all privilege checks.
297 AssertState(OidIsValid(CurrentUserId));
298 return CurrentUserId;
305 AssertArg(OidIsValid(newid));
306 CurrentUserId = newid;
311 * This value is only relevant for informational purposes.
314 GetSessionUserId(void)
316 AssertState(OidIsValid(SessionUserId));
317 return SessionUserId;
322 SetSessionUserId(Oid newid)
324 AssertArg(OidIsValid(newid));
325 SessionUserId = newid;
326 /* Current user defaults to session user. */
327 if (!OidIsValid(CurrentUserId))
328 CurrentUserId = newid;
333 SetSessionUserIdFromUserName(const char *username)
338 * Don't do scans if we're bootstrapping, none of the system catalogs
339 * exist yet, and they should be owned by postgres anyway.
341 AssertState(!IsBootstrapProcessingMode());
343 userTup = SearchSysCache(SHADOWNAME,
344 PointerGetDatum(username),
346 if (!HeapTupleIsValid(userTup))
347 elog(FATAL, "user \"%s\" does not exist", username);
349 SetSessionUserId( ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid );
351 ReleaseSysCache(userTup);
356 * Get user name from user id
359 GetUserName(Oid userid)
364 tuple = SearchSysCache(SHADOWSYSID,
365 ObjectIdGetDatum(userid),
367 if (!HeapTupleIsValid(tuple))
368 elog(ERROR, "invalid user id %u", (unsigned) userid);
370 result = pstrdup( NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename) );
372 ReleaseSysCache(tuple);
378 /*-------------------------------------------------------------------------
379 * Set data directory, but make sure it's an absolute path. Use this,
380 * never set DataDir directly.
381 *-------------------------------------------------------------------------
384 SetDataDir(const char *dir)
400 buf = malloc(buflen);
402 elog(FATAL, "out of memory");
404 if (getcwd(buf, buflen))
406 else if (errno == ERANGE)
415 elog(FATAL, "cannot get current working directory: %m");
419 new = malloc(strlen(buf) + 1 + strlen(dir) + 1);
420 sprintf(new, "%s/%s", buf, dir);
428 elog(FATAL, "out of memory");
434 /*-------------------------------------------------------------------------
436 * postmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
438 * (1) postmaster starts. In this case pid > 0.
439 * (2) postgres starts in standalone mode. In this case
442 * to gain an interlock.
444 * SetPidFname(datadir)
445 * Remember the the pid file name. This is neccesary
446 * UnlinkPidFile() is called from proc_exit().
448 * GetPidFname(datadir)
449 * Get the pid file name. SetPidFname() should be called
450 * before GetPidFname() gets called.
453 * This is called from proc_exit() and unlink the pid file.
455 * SetPidFile(pid_t pid)
456 * Create the pid file. On failure, it checks if the process
457 * actually exists or not. SetPidFname() should be called
458 * in prior to calling SetPidFile().
460 *-------------------------------------------------------------------------
464 * Path to pid file. proc_exit() remember it to unlink the file.
466 static char PidFile[MAXPGPATH];
469 * Remove the pid file. This function is called from proc_exit.
478 * Set path to the pid file
481 SetPidFname(char *datadir)
483 snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
487 * Get path to the pid file
496 * Create the pid file
499 SetPidFile(pid_t pid)
511 pidfile = GetPidFname();
512 fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
517 * Couldn't create the pid file. Probably it already exists. Read
518 * the file to see if the process actually exists
520 fd = open(pidfile, O_RDONLY, 0600);
523 fprintf(stderr, "Can't open pid file: %s\n", pidfile);
524 fprintf(stderr, "Please check the permission and try again.\n");
527 if ((len = read(fd, pidstr, sizeof(pidstr) - 1)) < 0)
529 fprintf(stderr, "Can't read pid file: %s\n", pidfile);
530 fprintf(stderr, "Please check the permission and try again.\n");
537 * Check to see if the process actually exists
540 post_pid = (pid_t) atoi(pidstr);
542 /* if pid < 0, the pid is for postgres, not postmatser */
546 post_pid = -post_pid;
549 if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0))
553 * No, the process did not exist. Unlink the file and try to
556 if (unlink(pidfile) < 0)
558 fprintf(stderr, "Can't remove pid file: %s\n", pidfile);
559 fprintf(stderr, "The file seems accidently left, but I couldn't remove it.\n");
560 fprintf(stderr, "Please remove the file by hand and try again.\n");
563 fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
566 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
567 fprintf(stderr, "Please check the permission and try again.\n");
575 * Another postmaster is running
577 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
579 fprintf(stderr, "Is another postgres (pid: %d) running?\n", (int) post_pid);
581 fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
586 sprintf(pidstr, "%d", (int) pid);
587 if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr))
589 fprintf(stderr, "Write to pid file failed\n");
590 fprintf(stderr, "Please check the permission and try again.\n");
603 * Determine whether the PG_VERSION file in directory `path' indicates
604 * a data version compatible with the version of this program.
606 * If compatible, return. Otherwise, elog(FATAL).
609 ValidatePgVersion(const char *path)
611 char full_path[MAXPGPATH];
614 long file_major, file_minor;
615 long my_major = 0, my_minor = 0;
617 const char *version_string = PG_VERSION;
619 my_major = strtol(version_string, &endptr, 10);
621 my_minor = strtol(endptr+1, NULL, 10);
623 snprintf(full_path, MAXPGPATH, "%s/PG_VERSION", path);
625 file = AllocateFile(full_path, "r");
629 elog(FATAL, "File %s is missing. This is not a valid data directory.", full_path);
631 elog(FATAL, "cannot open %s: %s", full_path, strerror(errno));
634 ret = fscanf(file, "%ld.%ld", &file_major, &file_minor);
636 elog(FATAL, "cannot read %s: %s", full_path, strerror(errno));
638 elog(FATAL, "`%s' does not have a valid format. You need to initdb.", full_path);
642 if (my_major != file_major || my_minor != file_minor)
643 elog(FATAL, "The data directory was initalized by PostgreSQL version %ld.%ld, "
644 "which is not compatible with this verion %s.",
645 file_major, file_minor, version_string);