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