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