]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/miscinit.c
Remove dangling else warning (Cyrillic recode stuff)
[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.52 2000/07/14 16:41:44 petere 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 #include <errno.h>
28
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"
34
35 static char *GetPidFname(void);
36
37
38 #ifdef CYR_RECODE
39 unsigned char RecodeForwTable[128];
40 unsigned char RecodeBackTable[128];
41
42 #endif
43
44 ProcessingMode Mode = InitProcessing;
45
46 /* ----------------------------------------------------------------
47  *              ignoring system indexes support stuff
48  * ----------------------------------------------------------------
49  */
50
51 static bool isIgnoringSystemIndexes = false;
52
53 /*
54  * IsIgnoringSystemIndexes
55  *              True if ignoring system indexes.
56  */
57 bool
58 IsIgnoringSystemIndexes()
59 {
60         return isIgnoringSystemIndexes;
61 }
62
63 /*
64  * IgnoreSystemIndexes
65  *      Set true or false whether PostgreSQL ignores system indexes.
66  *
67  */
68 void
69 IgnoreSystemIndexes(bool mode)
70 {
71         isIgnoringSystemIndexes = mode;
72 }
73
74 /* ----------------------------------------------------------------
75  *                              database path / name support stuff
76  * ----------------------------------------------------------------
77  */
78
79 void
80 SetDatabasePath(const char *path)
81 {
82         free(DatabasePath);
83         /* use strdup since this is done before memory contexts are set up */
84         if (path)
85         {
86                 DatabasePath = strdup(path);
87                 AssertState(DatabasePath);
88         }
89 }
90
91 void
92 SetDatabaseName(const char *name)
93 {
94         free(DatabaseName);
95         if (name)
96         {
97                 DatabaseName = strdup(name);
98                 AssertState(DatabaseName);
99         }
100 }
101
102 #ifndef MULTIBYTE
103 /* even if MULTIBYTE is not enabled, these functions are necessary
104  * since pg_proc.h has references to them.
105  */
106
107 Datum
108 getdatabaseencoding(PG_FUNCTION_ARGS)
109 {
110         PG_RETURN_NAME("SQL_ASCII");
111 }
112
113 Datum
114 PG_encoding_to_char(PG_FUNCTION_ARGS)
115 {
116         PG_RETURN_NAME("SQL_ASCII");
117 }
118
119 Datum
120 PG_char_to_encoding(PG_FUNCTION_ARGS)
121 {
122         PG_RETURN_INT32(0);
123 }
124
125 #endif
126
127 #ifdef CYR_RECODE
128 #define MAX_TOKEN       80
129
130 /* Some standard C libraries, including GNU, have an isblank() function.
131    Others, including Solaris, do not.  So we have our own.
132 */
133 static bool
134 isblank(const char c)
135 {
136         return c == ' ' || c == 9 /* tab */ ;
137 }
138
139 static void
140 next_token(FILE *fp, char *buf, const int bufsz)
141 {
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 --------------------------------------------------------------------------*/
151         int                     c;
152         char       *eb = buf + (bufsz - 1);
153
154         /* Move over inital token-delimiting blanks */
155         while (isblank(c = getc(fp)));
156
157         if (c != '\n')
158         {
159
160                 /*
161                  * build a token in buf of next characters up to EOF, eol, or
162                  * blank.
163                  */
164                 while (c != EOF && c != '\n' && !isblank(c))
165                 {
166                         if (buf < eb)
167                                 *buf++ = c;
168                         c = getc(fp);
169
170                         /*
171                          * Put back the char right after the token (putting back EOF
172                          * is ok)
173                          */
174                 }
175                 ungetc(c, fp);
176         }
177         *buf = '\0';
178 }
179
180 static void
181 read_through_eol(FILE *file)
182 {
183         int                     c;
184
185         do
186                 c = getc(file);
187         while (c != '\n' && c != EOF);
188 }
189
190 void
191 SetCharSet()
192 {
193         FILE       *file;
194         char       *p,
195                                 c,
196                                 eof = false;
197         char       *map_file;
198         char            buf[MAX_TOKEN];
199         int                     i;
200         unsigned char FromChar,
201                                 ToChar;
202
203         for (i = 0; i < 128; i++)
204         {
205                 RecodeForwTable[i] = i + 128;
206                 RecodeBackTable[i] = i + 128;
207         }
208
209         p = getenv("PG_RECODETABLE");
210         if (p && *p != '\0')
211         {
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);
216                 if (file == NULL)
217                         return;
218                 eof = false;
219                 while (!eof)
220                 {
221                         c = getc(file);
222                         ungetc(c, file);
223                         if (c == EOF)
224                                 eof = true;
225                         else
226                         {
227                                 if (c == '#')
228                                         read_through_eol(file);
229                                 else
230                                 {
231                                         /* Read the FromChar */
232                                         next_token(file, buf, sizeof(buf));
233                                         if (buf[0] != '\0')
234                                         {
235                                                 FromChar = strtoul(buf, 0, 0);
236                                                 /* Read the ToChar */
237                                                 next_token(file, buf, sizeof(buf));
238                                                 if (buf[0] != '\0')
239                                                 {
240                                                         ToChar = strtoul(buf, 0, 0);
241                                                         RecodeForwTable[FromChar - 128] = ToChar;
242                                                         RecodeBackTable[ToChar - 128] = FromChar;
243                                                 }
244                                                 read_through_eol(file);
245                                         }
246                                 }
247                         }
248                 }
249                 FreeFile(file);
250                 free(map_file);
251         }
252 }
253
254 char *
255 convertstr(unsigned char *buff, int len, int dest)
256 {
257         int                     i;
258         char       *ch = buff;
259
260         for (i = 0; i < len; i++, buff++)
261         {
262                 if (*buff > 127)
263                 {
264                         if (dest)
265                                 *buff = RecodeForwTable[*buff - 128];
266                         else
267                                 *buff = RecodeBackTable[*buff - 128];
268                 }
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 static 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", (int) 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", (int) 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 }
526
527
528
529 /*
530  * Determine whether the PG_VERSION file in directory `path' indicates
531  * a data version compatible with the version of this program.
532  *
533  * If compatible, return. Otherwise, elog(FATAL).
534  */
535 void
536 ValidatePgVersion(const char *path)
537 {
538         char            full_path[MAXPGPATH];
539         FILE       *file;
540         int                     ret;
541         long        file_major, file_minor;
542         long        my_major = 0, my_minor = 0;
543         char       *endptr;
544         const char *version_string = PG_VERSION;
545
546         my_major = strtol(version_string, &endptr, 10);
547         if (*endptr == '.')
548                 my_minor = strtol(endptr+1, NULL, 10);
549
550         snprintf(full_path, MAXPGPATH, "%s/PG_VERSION", path);
551
552         file = AllocateFile(full_path, "r");
553         if (!file)
554         {
555                 if (errno == ENOENT)
556                         elog(FATAL, "File %s is missing. This is not a valid data directory.", full_path);
557                 else
558                         elog(FATAL, "cannot open %s: %s", full_path, strerror(errno));
559         }
560
561         ret = fscanf(file, "%ld.%ld", &file_major, &file_minor);
562         if (ret == EOF)
563                 elog(FATAL, "cannot read %s: %s", full_path, strerror(errno));
564         else if (ret != 2)
565                 elog(FATAL, "`%s' does not have a valid format. You need to initdb.", full_path);
566
567         FreeFile(file);
568
569         if (my_major != file_major || my_minor != file_minor)
570                 elog(FATAL, "The data directory was initalized by PostgreSQL version %ld.%ld, "
571                          "which is not compatible with this verion %s.",
572                          file_major, file_minor, version_string);
573 }