1 /*-------------------------------------------------------------------------
4 * miscellanious initialization support stuff
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.40 2000/01/18 05:10:29 ishii Exp $
12 *-------------------------------------------------------------------------
16 #include <sys/param.h>
17 #include <sys/types.h>
26 #include "catalog/catname.h"
27 #include "catalog/pg_shadow.h"
28 #include "miscadmin.h"
29 #include "utils/syscache.h"
33 unsigned char RecodeForwTable[128];
34 unsigned char RecodeBackTable[128];
37 ProcessingMode Mode = InitProcessing;
40 /* ----------------------------------------------------------------
41 * database path / name support stuff
42 * ----------------------------------------------------------------
46 SetDatabasePath(const char *path)
49 /* use strdup since this is done before memory contexts are set up */
52 DatabasePath = strdup(path);
53 AssertState(DatabasePath);
58 SetDatabaseName(const char *name)
63 DatabaseName = strdup(name);
64 AssertState(DatabaseName);
69 /* even if MULTIBYTE is not enabled, this function is neccesary
70 * since pg_proc.h has entries for them.
75 elog(ERROR, "MultiByte support must be enabled to use this function");
79 const char *pg_encoding_to_char(int encoding)
81 elog(ERROR, "MultiByte support must be enabled to use this function");
85 int pg_char_to_encoding(const char *encoding_string)
87 elog(ERROR, "MultiByte support must be enabled to use this function");
96 /* Some standard C libraries, including GNU, have an isblank() function.
97 Others, including Solaris, do not. So we have our own.
100 isblank(const char c)
102 return c == ' ' || c == 9 /* tab */ ;
106 next_token(FILE *fp, char *buf, const int bufsz)
108 /*--------------------------------------------------------------------------
109 Grab one token out of fp. Tokens are strings of non-blank
110 characters bounded by blank characters, beginning of line, and end
111 of line. Blank means space or tab. Return the token as *buf.
112 Leave file positioned to character immediately after the token or
113 EOF, whichever comes first. If no more tokens on line, return null
114 string as *buf and position file to beginning of next line or EOF,
115 whichever comes first.
116 --------------------------------------------------------------------------*/
118 char *eb = buf + (bufsz - 1);
120 /* Move over inital token-delimiting blanks */
121 while (isblank(c = getc(fp)));
127 * build a token in buf of next characters up to EOF, eol, or
130 while (c != EOF && c != '\n' && !isblank(c))
137 * Put back the char right after the token (putting back EOF
147 read_through_eol(FILE *file)
153 while (c != '\n' && c != EOF);
166 unsigned char FromChar,
169 for (i = 0; i < 128; i++)
171 RecodeForwTable[i] = i + 128;
172 RecodeBackTable[i] = i + 128;
175 p = getenv("PG_RECODETABLE");
178 map_file = (char *) malloc((strlen(DataDir) +
179 strlen(p) + 2) * sizeof(char));
180 sprintf(map_file, "%s/%s", DataDir, p);
182 file = AllocateFile(map_file, "r");
184 file = AllocateFile(map_file, "rb");
198 read_through_eol(file);
201 /* Read the FromChar */
202 next_token(file, buf, sizeof(buf));
205 FromChar = strtoul(buf, 0, 0);
206 /* Read the ToChar */
207 next_token(file, buf, sizeof(buf));
210 ToChar = strtoul(buf, 0, 0);
211 RecodeForwTable[FromChar - 128] = ToChar;
212 RecodeBackTable[ToChar - 128] = FromChar;
214 read_through_eol(file);
225 convertstr(unsigned char *buff, int len, int dest)
230 for (i = 0; i < len; i++, buff++)
234 *buff = RecodeForwTable[*buff - 128];
236 *buff = RecodeBackTable[*buff - 128];
244 * GetPgUserName and SetPgUserName
246 * SetPgUserName must be called before InitPostgres, since the setuid()
249 * Replace GetPgUserName() with a lower-case version
250 * to allow use in new case-insensitive SQL (referenced
251 * in pg_proc.h). Define GetPgUserName() as a macro - tgl 97/04/26
267 if (IsUnderPostmaster)
269 /* use the (possibly) authenticated name that's provided */
270 if (!(p = getenv("PG_USER")))
271 elog(FATAL, "SetPgUserName: PG_USER environment variable is unset");
275 /* setuid() has not yet been done, see above comment */
276 if (!(pw = getpwuid(geteuid())))
277 elog(FATAL, "SetPgUserName: no entry in host passwd file");
282 UserName = malloc(strlen(p) + 1);
284 #endif /* NO_SECURITY */
287 /* ----------------------------------------------------------------
288 * GetUserId and SetUserId
289 * ----------------------------------------------------------------
291 static Oid UserId = InvalidOid;
296 AssertState(OidIsValid(UserId));
306 AssertState(!OidIsValid(UserId));/* only once */
309 * Don't do scans if we're bootstrapping, none of the system catalogs
310 * exist yet, and they should be owned by postgres anyway.
312 if (IsBootstrapProcessingMode())
318 userName = GetPgUserName();
319 userTup = SearchSysCacheTuple(SHADOWNAME,
320 PointerGetDatum(userName),
322 if (!HeapTupleIsValid(userTup))
323 elog(FATAL, "SetUserId: user '%s' is not in '%s'",
326 UserId = (Oid) ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
329 /*-------------------------------------------------------------------------
331 * posmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
333 * (1) postmaster starts. In this case pid > 0.
334 * (2) postgres starts in standalone mode. In this case
337 * to gain an interlock.
339 * SetPidFname(datadir)
340 * Remember the the pid file name. This is neccesary
341 * UnlinkPidFile() is called from proc_exit().
343 * GetPidFname(datadir)
344 * Get the pid file name. SetPidFname() should be called
345 * before GetPidFname() gets called.
348 * This is called from proc_exit() and unlink the pid file.
350 * SetPidFile(pid_t pid)
351 * Create the pid file. On failure, it checks if the process
352 * actually exists or not. SetPidFname() should be called
353 * in prior to calling SetPidFile().
355 *-------------------------------------------------------------------------
359 * Path to pid file. proc_exit() remember it to unlink the file.
361 static char PidFile[MAXPGPATH];
364 * Remove the pid file. This function is called from proc_exit.
366 void UnlinkPidFile(void)
372 * Set path to the pid file
374 void SetPidFname(char * datadir)
376 snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
380 * Get path to the pid file
382 char *GetPidFname(void)
388 * Create the pid file
390 int SetPidFile(pid_t pid)
402 pidfile = GetPidFname();
403 fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
406 * Couldn't create the pid file. Probably
407 * it already exists. Read the file to see if the process
410 fd = open(pidfile, O_RDONLY, 0600);
412 fprintf(stderr, "Can't open pid file: %s\n", pidfile);
413 fprintf(stderr, "Please check the permission and try again.\n");
416 if ((len = read(fd, pidstr, sizeof(pidstr)-1)) < 0) {
417 fprintf(stderr, "Can't read pid file: %s\n", pidfile);
418 fprintf(stderr, "Please check the permission and try again.\n");
425 * Check to see if the process actually exists
428 post_pid = (pid_t)atoi(pidstr);
430 /* if pid < 0, the pid is for postgres, not postmatser */
433 post_pid = -post_pid;
436 if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0)) {
438 * No, the process did not exist. Unlink
439 * the file and try to create it
441 if (unlink(pidfile) < 0) {
442 fprintf(stderr, "Can't remove pid file: %s\n", pidfile);
443 fprintf(stderr, "The file seems accidently left, but I couldn't remove it.\n");
444 fprintf(stderr, "Please remove the file by hand and try again.\n");
447 fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
449 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
450 fprintf(stderr, "Please check the permission and try again.\n");
455 * Another postmaster is running
457 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
459 fprintf(stderr, "Is another postgres (pid: %d) running?\n", post_pid);
463 fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
469 sprintf(pidstr, "%d", pid);
470 if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
471 fprintf(stderr,"Write to pid file failed\n");
472 fprintf(stderr, "Please check the permission and try again.\n");