]> granicus.if.org Git - postgresql/blob - src/backend/utils/init/miscinit.c
Add builtin functions:
[postgresql] / src / backend / utils / init / miscinit.c
1 /*-------------------------------------------------------------------------
2  *
3  * miscinit.c
4  *        miscellanious initialization support stuff
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.40 2000/01/18 05:10:29 ishii Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <signal.h>
19 #include <sys/stat.h>
20 #include <sys/file.h>
21 #include <unistd.h>
22 #include <grp.h>
23 #include <pwd.h>
24 #include <stdlib.h>
25
26 #include "catalog/catname.h"
27 #include "catalog/pg_shadow.h"
28 #include "miscadmin.h"
29 #include "utils/syscache.h"
30
31
32 #ifdef CYR_RECODE
33 unsigned char RecodeForwTable[128];
34 unsigned char RecodeBackTable[128];
35 #endif
36
37 ProcessingMode Mode = InitProcessing;
38
39
40 /* ----------------------------------------------------------------
41  *                              database path / name support stuff
42  * ----------------------------------------------------------------
43  */
44
45 void
46 SetDatabasePath(const char *path)
47 {
48     free(DatabasePath);
49         /* use strdup since this is done before memory contexts are set up */
50     if (path)
51     {
52         DatabasePath = strdup(path);
53         AssertState(DatabasePath);
54     }
55 }
56
57 void
58 SetDatabaseName(const char *name)
59 {
60     free(DatabaseName);
61     if (name)
62     {
63         DatabaseName = strdup(name);
64         AssertState(DatabaseName);
65     }
66 }
67
68 #ifndef MULTIBYTE
69 /* even if MULTIBYTE is not enabled, this function is neccesary
70  * since pg_proc.h has entries for them.
71  */
72 const char *
73 getdatabaseencoding()
74 {
75         elog(ERROR, "MultiByte support must be enabled to use this function");
76         return ("");
77 }
78
79 const char *pg_encoding_to_char(int encoding)
80 {
81         elog(ERROR, "MultiByte support must be enabled to use this function");
82         return ("");
83 }
84
85 int     pg_char_to_encoding(const char *encoding_string)
86 {
87         elog(ERROR, "MultiByte support must be enabled to use this function");
88         return ("");
89 }
90
91 #endif
92
93 #ifdef CYR_RECODE
94 #define MAX_TOKEN       80
95
96 /* Some standard C libraries, including GNU, have an isblank() function.
97    Others, including Solaris, do not.  So we have our own.
98 */
99 static bool
100 isblank(const char c)
101 {
102         return c == ' ' || c == 9 /* tab */ ;
103 }
104
105 static void
106 next_token(FILE *fp, char *buf, const int bufsz)
107 {
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 --------------------------------------------------------------------------*/
117         int                     c;
118         char       *eb = buf + (bufsz - 1);
119
120         /* Move over inital token-delimiting blanks */
121         while (isblank(c = getc(fp)));
122
123         if (c != '\n')
124         {
125
126                 /*
127                  * build a token in buf of next characters up to EOF, eol, or
128                  * blank.
129                  */
130                 while (c != EOF && c != '\n' && !isblank(c))
131                 {
132                         if (buf < eb)
133                                 *buf++ = c;
134                         c = getc(fp);
135
136                         /*
137                          * Put back the char right after the token (putting back EOF
138                          * is ok)
139                          */
140                 }
141                 ungetc(c, fp);
142         }
143         *buf = '\0';
144 }
145
146 static void
147 read_through_eol(FILE *file)
148 {
149         int                     c;
150
151         do
152                 c = getc(file);
153         while (c != '\n' && c != EOF);
154 }
155
156 void
157 SetCharSet()
158 {
159         FILE       *file;
160         char       *p,
161                                 c,
162                                 eof = false;
163         char       *map_file;
164         char            buf[MAX_TOKEN];
165         int                     i;
166         unsigned char FromChar,
167                                 ToChar;
168
169         for (i = 0; i < 128; i++)
170         {
171                 RecodeForwTable[i] = i + 128;
172                 RecodeBackTable[i] = i + 128;
173         }
174
175         p = getenv("PG_RECODETABLE");
176         if (p && *p != '\0')
177         {
178                 map_file = (char *) malloc((strlen(DataDir) +
179                                                                         strlen(p) + 2) * sizeof(char));
180                 sprintf(map_file, "%s/%s", DataDir, p);
181 #ifndef __CYGWIN32__
182                 file = AllocateFile(map_file, "r");
183 #else
184                 file = AllocateFile(map_file, "rb");
185 #endif
186                 if (file == NULL)
187                         return;
188                 eof = false;
189                 while (!eof)
190                 {
191                         c = getc(file);
192                         ungetc(c, file);
193                         if (c == EOF)
194                                 eof = true;
195                         else
196                         {
197                                 if (c == '#')
198                                         read_through_eol(file);
199                                 else
200                                 {
201                                         /* Read the FromChar */
202                                         next_token(file, buf, sizeof(buf));
203                                         if (buf[0] != '\0')
204                                         {
205                                                 FromChar = strtoul(buf, 0, 0);
206                                                 /* Read the ToChar */
207                                                 next_token(file, buf, sizeof(buf));
208                                                 if (buf[0] != '\0')
209                                                 {
210                                                         ToChar = strtoul(buf, 0, 0);
211                                                         RecodeForwTable[FromChar - 128] = ToChar;
212                                                         RecodeBackTable[ToChar - 128] = FromChar;
213                                                 }
214                                                 read_through_eol(file);
215                                         }
216                                 }
217                         }
218                 }
219                 FreeFile(file);
220                 free(map_file);
221         }
222 }
223
224 char *
225 convertstr(unsigned char *buff, int len, int dest)
226 {
227         int                     i;
228         char       *ch = buff;
229
230         for (i = 0; i < len; i++, buff++)
231         {
232                 if (*buff > 127)
233                         if (dest)
234                                 *buff = RecodeForwTable[*buff - 128];
235                         else
236                                 *buff = RecodeBackTable[*buff - 128];
237         }
238         return ch;
239 }
240
241 #endif
242
243 /* ----------------
244  *              GetPgUserName and SetPgUserName
245  *
246  *              SetPgUserName must be called before InitPostgres, since the setuid()
247  *              is done there.
248  *
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
252  * ----------------
253  */
254 char *
255 getpgusername()
256 {
257         return UserName;
258 }
259
260 void
261 SetPgUserName()
262 {
263 #ifndef NO_SECURITY
264         char       *p;
265         struct passwd *pw;
266
267         if (IsUnderPostmaster)
268         {
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");
272         }
273         else
274         {
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");
278                 p = pw->pw_name;
279         }
280         if (UserName)
281                 free(UserName);
282         UserName = malloc(strlen(p) + 1);
283         strcpy(UserName, p);
284 #endif   /* NO_SECURITY */
285 }
286
287 /* ----------------------------------------------------------------
288  *              GetUserId and SetUserId
289  * ----------------------------------------------------------------
290  */
291 static Oid      UserId = InvalidOid;
292
293 int
294 GetUserId()
295 {
296         AssertState(OidIsValid(UserId));
297         return UserId;
298 }
299
300 void
301 SetUserId()
302 {
303         HeapTuple       userTup;
304         char       *userName;
305
306         AssertState(!OidIsValid(UserId));/* only once */
307
308         /*
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.
311          */
312         if (IsBootstrapProcessingMode())
313         {
314                 UserId = geteuid();
315                 return;
316         }
317
318         userName = GetPgUserName();
319         userTup = SearchSysCacheTuple(SHADOWNAME,
320                                                                   PointerGetDatum(userName),
321                                                                   0, 0, 0);
322         if (!HeapTupleIsValid(userTup))
323                 elog(FATAL, "SetUserId: user '%s' is not in '%s'",
324                          userName,
325                          ShadowRelationName);
326         UserId = (Oid) ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
327 }
328
329 /*-------------------------------------------------------------------------
330  *
331  * posmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
332  *
333  *      (1) postmaster starts. In this case pid > 0.
334  *      (2) postgres starts in standalone mode. In this case
335  *          pid < 0
336  *
337  * to gain an interlock.
338  * 
339  *      SetPidFname(datadir)
340  *              Remember the the pid file name. This is neccesary
341  *              UnlinkPidFile() is called from proc_exit().
342  *
343  *      GetPidFname(datadir)
344  *              Get the pid file name. SetPidFname() should be called
345  *              before GetPidFname() gets called.
346  *
347  *      UnlinkPidFile()
348  *              This is called from proc_exit() and unlink the pid file.
349  *
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().
354  *
355  *-------------------------------------------------------------------------
356  */
357
358 /*
359  * Path to pid file. proc_exit() remember it to unlink the file.
360  */
361 static char PidFile[MAXPGPATH];
362
363 /*
364  * Remove the pid file. This function is called from proc_exit.
365  */
366 void UnlinkPidFile(void)
367 {
368         unlink(PidFile);
369 }
370
371 /*
372  * Set path to the pid file
373  */
374 void SetPidFname(char * datadir)
375 {
376         snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
377 }
378
379 /*
380  * Get path to the pid file
381  */
382 char *GetPidFname(void)
383 {
384         return(PidFile);
385 }
386
387 /*
388  * Create the pid file
389  */
390 int SetPidFile(pid_t pid)
391 {
392         int fd;
393         char *pidfile;
394         char pidstr[32];
395         int len;
396         pid_t post_pid;
397         int is_postgres = 0;
398
399         /*
400          * Creating pid file
401          */
402         pidfile = GetPidFname();
403         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
404         if (fd < 0) {
405                 /*
406                  * Couldn't create the pid file. Probably
407                  * it already exists. Read the file to see if the process
408                  * actually exists
409                  */
410                 fd = open(pidfile, O_RDONLY, 0600);
411                 if (fd < 0) {
412                         fprintf(stderr, "Can't open pid file: %s\n", pidfile);
413                         fprintf(stderr, "Please check the permission and try again.\n");
414                         return(-1);
415                 }
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");
419                         close(fd);
420                         return(-1);
421                 }
422                 close(fd);
423
424                 /*
425                  * Check to see if the process actually exists
426                  */
427                 pidstr[len] = '\0';
428                 post_pid = (pid_t)atoi(pidstr);
429
430                 /* if pid < 0, the pid is for postgres, not postmatser */
431                 if (post_pid < 0) {
432                         is_postgres++;
433                         post_pid = -post_pid;
434                 }
435
436                 if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0)) {
437                         /*
438                          * No, the process did not exist. Unlink
439                          * the file and try to create it
440                          */
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");
445                                 return(-1);
446                         }
447                         fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
448                         if (fd < 0) {
449                                 fprintf(stderr, "Can't create pid file: %s\n", pidfile);
450                                 fprintf(stderr, "Please check the permission and try again.\n");
451                                 return(-1);
452                         }
453                 } else {
454                         /*
455                          * Another postmaster is running
456                          */
457                         fprintf(stderr, "Can't create pid file: %s\n", pidfile);
458                         if (is_postgres) {
459                           fprintf(stderr, "Is another postgres (pid: %d) running?\n", post_pid);
460                         }
461                         else
462                         {
463                           fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
464                         }
465                         return(-1);
466                 }
467         }
468
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");
473                 close(fd);
474                 unlink(pidfile);
475                 return(-1);
476         }
477         close(fd);
478
479         return(0);
480 }