]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/miscinit.c
Modify getdatabaseencoding(), pg_encoding_to_char()
[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.46 2000/05/02 08:13:08 ishii 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         return ("SQL_ASCII");
106 }
107
108 const char *
109 pg_encoding_to_char(int encoding)
110 {
111         return ("SQL_ASCII");
112 }
113
114 int
115 pg_char_to_encoding(const char *encoding_string)
116 {
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
396 UnlinkPidFile(void)
397 {
398         unlink(PidFile);
399 }
400
401 /*
402  * Set path to the pid file
403  */
404 void
405 SetPidFname(char *datadir)
406 {
407         snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
408 }
409
410 /*
411  * Get path to the pid file
412  */
413 char *
414 GetPidFname(void)
415 {
416         return (PidFile);
417 }
418
419 /*
420  * Create the pid file
421  */
422 int
423 SetPidFile(pid_t pid)
424 {
425         int                     fd;
426         char       *pidfile;
427         char            pidstr[32];
428         int                     len;
429         pid_t           post_pid;
430         int                     is_postgres = 0;
431
432         /*
433          * Creating pid file
434          */
435         pidfile = GetPidFname();
436         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
437         if (fd < 0)
438         {
439
440                 /*
441                  * Couldn't create the pid file. Probably it already exists. Read
442                  * the file to see if the process actually exists
443                  */
444                 fd = open(pidfile, O_RDONLY, 0600);
445                 if (fd < 0)
446                 {
447                         fprintf(stderr, "Can't open pid file: %s\n", pidfile);
448                         fprintf(stderr, "Please check the permission and try again.\n");
449                         return (-1);
450                 }
451                 if ((len = read(fd, pidstr, sizeof(pidstr) - 1)) < 0)
452                 {
453                         fprintf(stderr, "Can't read pid file: %s\n", pidfile);
454                         fprintf(stderr, "Please check the permission and try again.\n");
455                         close(fd);
456                         return (-1);
457                 }
458                 close(fd);
459
460                 /*
461                  * Check to see if the process actually exists
462                  */
463                 pidstr[len] = '\0';
464                 post_pid = (pid_t) atoi(pidstr);
465
466                 /* if pid < 0, the pid is for postgres, not postmatser */
467                 if (post_pid < 0)
468                 {
469                         is_postgres++;
470                         post_pid = -post_pid;
471                 }
472
473                 if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0))
474                 {
475
476                         /*
477                          * No, the process did not exist. Unlink the file and try to
478                          * create it
479                          */
480                         if (unlink(pidfile) < 0)
481                         {
482                                 fprintf(stderr, "Can't remove pid file: %s\n", pidfile);
483                                 fprintf(stderr, "The file seems accidently left, but I couldn't remove it.\n");
484                                 fprintf(stderr, "Please remove the file by hand and try again.\n");
485                                 return (-1);
486                         }
487                         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
488                         if (fd < 0)
489                         {
490                                 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
491                                 fprintf(stderr, "Please check the permission and try again.\n");
492                                 return (-1);
493                         }
494                 }
495                 else
496                 {
497
498                         /*
499                          * Another postmaster is running
500                          */
501                         fprintf(stderr, "Can't create pid file: %s\n", pidfile);
502                         if (is_postgres)
503                                 fprintf(stderr, "Is another postgres (pid: %d) running?\n", post_pid);
504                         else
505                                 fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
506                         return (-1);
507                 }
508         }
509
510         sprintf(pidstr, "%d", pid);
511         if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr))
512         {
513                 fprintf(stderr, "Write to pid file failed\n");
514                 fprintf(stderr, "Please check the permission and try again.\n");
515                 close(fd);
516                 unlink(pidfile);
517                 return (-1);
518         }
519         close(fd);
520
521         return (0);
522 }