]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/miscinit.c
Ye-old pgindent run. Same 4-space tabs.
[postgresql] / src / backend / utils / init / miscinit.c
1 /*-------------------------------------------------------------------------
2  *
3  * miscinit.c
4  *        miscellanious initialization support stuff
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.45 2000/04/12 17:16:02 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <signal.h>
20 #include <sys/stat.h>
21 #include <sys/file.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <grp.h>
25 #include <pwd.h>
26 #include <stdlib.h>
27
28 #include "catalog/catname.h"
29 #include "catalog/pg_shadow.h"
30 #include "miscadmin.h"
31 #include "utils/syscache.h"
32
33
34 #ifdef CYR_RECODE
35 unsigned char RecodeForwTable[128];
36 unsigned char RecodeBackTable[128];
37
38 #endif
39
40 ProcessingMode Mode = InitProcessing;
41
42 /* ----------------------------------------------------------------
43  *              ignoring system indexes support stuff
44  * ----------------------------------------------------------------
45  */
46
47 static bool isIgnoringSystemIndexes = false;
48
49 /*
50  * IsIgnoringSystemIndexes
51  *              True if ignoring system indexes.
52  */
53 bool
54 IsIgnoringSystemIndexes()
55 {
56         return isIgnoringSystemIndexes;
57 }
58
59 /*
60  * IgnoreSystemIndexes
61  *      Set true or false whether PostgreSQL ignores system indexes.
62  *
63  */
64 void
65 IgnoreSystemIndexes(bool mode)
66 {
67         isIgnoringSystemIndexes = mode;
68 }
69
70 /* ----------------------------------------------------------------
71  *                              database path / name support stuff
72  * ----------------------------------------------------------------
73  */
74
75 void
76 SetDatabasePath(const char *path)
77 {
78         free(DatabasePath);
79         /* use strdup since this is done before memory contexts are set up */
80         if (path)
81         {
82                 DatabasePath = strdup(path);
83                 AssertState(DatabasePath);
84         }
85 }
86
87 void
88 SetDatabaseName(const char *name)
89 {
90         free(DatabaseName);
91         if (name)
92         {
93                 DatabaseName = strdup(name);
94                 AssertState(DatabaseName);
95         }
96 }
97
98 #ifndef MULTIBYTE
99 /* even if MULTIBYTE is not enabled, this function is neccesary
100  * since pg_proc.h has entries for them.
101  */
102 const char *
103 getdatabaseencoding()
104 {
105         elog(ERROR, "MultiByte support must be enabled to use this function");
106         return ("");
107 }
108
109 const char *
110 pg_encoding_to_char(int encoding)
111 {
112         elog(ERROR, "MultiByte support must be enabled to use this function");
113         return ("");
114 }
115
116 int
117 pg_char_to_encoding(const char *encoding_string)
118 {
119         elog(ERROR, "MultiByte support must be enabled to use this function");
120         return (0);
121 }
122
123 #endif
124
125 #ifdef CYR_RECODE
126 #define MAX_TOKEN       80
127
128 /* Some standard C libraries, including GNU, have an isblank() function.
129    Others, including Solaris, do not.  So we have our own.
130 */
131 static bool
132 isblank(const char c)
133 {
134         return c == ' ' || c == 9 /* tab */ ;
135 }
136
137 static void
138 next_token(FILE *fp, char *buf, const int bufsz)
139 {
140 /*--------------------------------------------------------------------------
141   Grab one token out of fp.  Tokens are strings of non-blank
142   characters bounded by blank characters, beginning of line, and end
143   of line.      Blank means space or tab.  Return the token as *buf.
144   Leave file positioned to character immediately after the token or
145   EOF, whichever comes first.  If no more tokens on line, return null
146   string as *buf and position file to beginning of next line or EOF,
147   whichever comes first.
148 --------------------------------------------------------------------------*/
149         int                     c;
150         char       *eb = buf + (bufsz - 1);
151
152         /* Move over inital token-delimiting blanks */
153         while (isblank(c = getc(fp)));
154
155         if (c != '\n')
156         {
157
158                 /*
159                  * build a token in buf of next characters up to EOF, eol, or
160                  * blank.
161                  */
162                 while (c != EOF && c != '\n' && !isblank(c))
163                 {
164                         if (buf < eb)
165                                 *buf++ = c;
166                         c = getc(fp);
167
168                         /*
169                          * Put back the char right after the token (putting back EOF
170                          * is ok)
171                          */
172                 }
173                 ungetc(c, fp);
174         }
175         *buf = '\0';
176 }
177
178 static void
179 read_through_eol(FILE *file)
180 {
181         int                     c;
182
183         do
184                 c = getc(file);
185         while (c != '\n' && c != EOF);
186 }
187
188 void
189 SetCharSet()
190 {
191         FILE       *file;
192         char       *p,
193                                 c,
194                                 eof = false;
195         char       *map_file;
196         char            buf[MAX_TOKEN];
197         int                     i;
198         unsigned char FromChar,
199                                 ToChar;
200
201         for (i = 0; i < 128; i++)
202         {
203                 RecodeForwTable[i] = i + 128;
204                 RecodeBackTable[i] = i + 128;
205         }
206
207         p = getenv("PG_RECODETABLE");
208         if (p && *p != '\0')
209         {
210                 map_file = (char *) malloc((strlen(DataDir) +
211                                                                         strlen(p) + 2) * sizeof(char));
212                 sprintf(map_file, "%s/%s", DataDir, p);
213 #ifndef __CYGWIN32__
214                 file = AllocateFile(map_file, "r");
215 #else
216                 file = AllocateFile(map_file, "rb");
217 #endif
218                 if (file == NULL)
219                         return;
220                 eof = false;
221                 while (!eof)
222                 {
223                         c = getc(file);
224                         ungetc(c, file);
225                         if (c == EOF)
226                                 eof = true;
227                         else
228                         {
229                                 if (c == '#')
230                                         read_through_eol(file);
231                                 else
232                                 {
233                                         /* Read the FromChar */
234                                         next_token(file, buf, sizeof(buf));
235                                         if (buf[0] != '\0')
236                                         {
237                                                 FromChar = strtoul(buf, 0, 0);
238                                                 /* Read the ToChar */
239                                                 next_token(file, buf, sizeof(buf));
240                                                 if (buf[0] != '\0')
241                                                 {
242                                                         ToChar = strtoul(buf, 0, 0);
243                                                         RecodeForwTable[FromChar - 128] = ToChar;
244                                                         RecodeBackTable[ToChar - 128] = FromChar;
245                                                 }
246                                                 read_through_eol(file);
247                                         }
248                                 }
249                         }
250                 }
251                 FreeFile(file);
252                 free(map_file);
253         }
254 }
255
256 char *
257 convertstr(unsigned char *buff, int len, int dest)
258 {
259         int                     i;
260         char       *ch = buff;
261
262         for (i = 0; i < len; i++, buff++)
263         {
264                 if (*buff > 127)
265                         if (dest)
266                                 *buff = RecodeForwTable[*buff - 128];
267                         else
268                                 *buff = RecodeBackTable[*buff - 128];
269         }
270         return ch;
271 }
272
273 #endif
274
275 /* ----------------
276  *              GetPgUserName and SetPgUserName
277  *
278  *              SetPgUserName must be called before InitPostgres, since the setuid()
279  *              is done there.
280  *
281  *              Replace GetPgUserName() with a lower-case version
282  *              to allow use in new case-insensitive SQL (referenced
283  *              in pg_proc.h). Define GetPgUserName() as a macro - tgl 97/04/26
284  * ----------------
285  */
286 char *
287 getpgusername()
288 {
289         return UserName;
290 }
291
292 void
293 SetPgUserName()
294 {
295 #ifndef NO_SECURITY
296         char       *p;
297         struct passwd *pw;
298
299         if (IsUnderPostmaster)
300         {
301                 /* use the (possibly) authenticated name that's provided */
302                 if (!(p = getenv("PG_USER")))
303                         elog(FATAL, "SetPgUserName: PG_USER environment variable is unset");
304         }
305         else
306         {
307                 /* setuid() has not yet been done, see above comment */
308                 if (!(pw = getpwuid(geteuid())))
309                         elog(FATAL, "SetPgUserName: no entry in host passwd file");
310                 p = pw->pw_name;
311         }
312         if (UserName)
313                 free(UserName);
314         UserName = malloc(strlen(p) + 1);
315         strcpy(UserName, p);
316 #endif   /* NO_SECURITY */
317 }
318
319 /* ----------------------------------------------------------------
320  *              GetUserId and SetUserId
321  * ----------------------------------------------------------------
322  */
323 static Oid      UserId = InvalidOid;
324
325 int
326 GetUserId()
327 {
328         AssertState(OidIsValid(UserId));
329         return UserId;
330 }
331
332 void
333 SetUserId()
334 {
335         HeapTuple       userTup;
336         char       *userName;
337
338         AssertState(!OidIsValid(UserId));       /* only once */
339
340         /*
341          * Don't do scans if we're bootstrapping, none of the system catalogs
342          * exist yet, and they should be owned by postgres anyway.
343          */
344         if (IsBootstrapProcessingMode())
345         {
346                 UserId = geteuid();
347                 return;
348         }
349
350         userName = GetPgUserName();
351         userTup = SearchSysCacheTuple(SHADOWNAME,
352                                                                   PointerGetDatum(userName),
353                                                                   0, 0, 0);
354         if (!HeapTupleIsValid(userTup))
355                 elog(FATAL, "SetUserId: user '%s' is not in '%s'",
356                          userName,
357                          ShadowRelationName);
358         UserId = (Oid) ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
359 }
360
361 /*-------------------------------------------------------------------------
362  *
363  * posmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
364  *
365  *      (1) postmaster starts. In this case pid > 0.
366  *      (2) postgres starts in standalone mode. In this case
367  *              pid < 0
368  *
369  * to gain an interlock.
370  *
371  *      SetPidFname(datadir)
372  *              Remember the the pid file name. This is neccesary
373  *              UnlinkPidFile() is called from proc_exit().
374  *
375  *      GetPidFname(datadir)
376  *              Get the pid file name. SetPidFname() should be called
377  *              before GetPidFname() gets called.
378  *
379  *      UnlinkPidFile()
380  *              This is called from proc_exit() and unlink the pid file.
381  *
382  *      SetPidFile(pid_t pid)
383  *              Create the pid file. On failure, it checks if the process
384  *              actually exists or not. SetPidFname() should be called
385  *              in prior to calling SetPidFile().
386  *
387  *-------------------------------------------------------------------------
388  */
389
390 /*
391  * Path to pid file. proc_exit() remember it to unlink the file.
392  */
393 static char PidFile[MAXPGPATH];
394
395 /*
396  * Remove the pid file. This function is called from proc_exit.
397  */
398 void
399 UnlinkPidFile(void)
400 {
401         unlink(PidFile);
402 }
403
404 /*
405  * Set path to the pid file
406  */
407 void
408 SetPidFname(char *datadir)
409 {
410         snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
411 }
412
413 /*
414  * Get path to the pid file
415  */
416 char *
417 GetPidFname(void)
418 {
419         return (PidFile);
420 }
421
422 /*
423  * Create the pid file
424  */
425 int
426 SetPidFile(pid_t pid)
427 {
428         int                     fd;
429         char       *pidfile;
430         char            pidstr[32];
431         int                     len;
432         pid_t           post_pid;
433         int                     is_postgres = 0;
434
435         /*
436          * Creating pid file
437          */
438         pidfile = GetPidFname();
439         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
440         if (fd < 0)
441         {
442
443                 /*
444                  * Couldn't create the pid file. Probably it already exists. Read
445                  * the file to see if the process actually exists
446                  */
447                 fd = open(pidfile, O_RDONLY, 0600);
448                 if (fd < 0)
449                 {
450                         fprintf(stderr, "Can't open pid file: %s\n", pidfile);
451                         fprintf(stderr, "Please check the permission and try again.\n");
452                         return (-1);
453                 }
454                 if ((len = read(fd, pidstr, sizeof(pidstr) - 1)) < 0)
455                 {
456                         fprintf(stderr, "Can't read pid file: %s\n", pidfile);
457                         fprintf(stderr, "Please check the permission and try again.\n");
458                         close(fd);
459                         return (-1);
460                 }
461                 close(fd);
462
463                 /*
464                  * Check to see if the process actually exists
465                  */
466                 pidstr[len] = '\0';
467                 post_pid = (pid_t) atoi(pidstr);
468
469                 /* if pid < 0, the pid is for postgres, not postmatser */
470                 if (post_pid < 0)
471                 {
472                         is_postgres++;
473                         post_pid = -post_pid;
474                 }
475
476                 if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0))
477                 {
478
479                         /*
480                          * No, the process did not exist. Unlink the file and try to
481                          * create it
482                          */
483                         if (unlink(pidfile) < 0)
484                         {
485                                 fprintf(stderr, "Can't remove pid file: %s\n", pidfile);
486                                 fprintf(stderr, "The file seems accidently left, but I couldn't remove it.\n");
487                                 fprintf(stderr, "Please remove the file by hand and try again.\n");
488                                 return (-1);
489                         }
490                         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
491                         if (fd < 0)
492                         {
493                                 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
494                                 fprintf(stderr, "Please check the permission and try again.\n");
495                                 return (-1);
496                         }
497                 }
498                 else
499                 {
500
501                         /*
502                          * Another postmaster is running
503                          */
504                         fprintf(stderr, "Can't create pid file: %s\n", pidfile);
505                         if (is_postgres)
506                                 fprintf(stderr, "Is another postgres (pid: %d) running?\n", post_pid);
507                         else
508                                 fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
509                         return (-1);
510                 }
511         }
512
513         sprintf(pidstr, "%d", pid);
514         if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr))
515         {
516                 fprintf(stderr, "Write to pid file failed\n");
517                 fprintf(stderr, "Please check the permission and try again.\n");
518                 close(fd);
519                 unlink(pidfile);
520                 return (-1);
521         }
522         close(fd);
523
524         return (0);
525 }