]> granicus.if.org Git - postgresql/blob - src/backend/commands/dbcommands.c
Update #include cleanups
[postgresql] / src / backend / commands / dbcommands.c
1 /*-------------------------------------------------------------------------
2  *
3  * dbcommands.c
4  *
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.37 1999/07/16 03:12:48 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <sys/stat.h>
18
19 #include "postgres.h"
20
21 #include "access/heapam.h"
22 #include "catalog/catname.h"
23 #include "catalog/pg_database.h"
24 #include "catalog/pg_shadow.h"
25 #include "miscadmin.h"
26 #include "tcop/tcopprot.h"
27 #include "commands/dbcommands.h"
28 #include "utils/syscache.h"
29
30
31 /* non-export function prototypes */
32 static void check_permissions(char *command, char *dbpath, char *dbname,
33                                   Oid *dbIdP, int4 *userIdP);
34 static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel);
35 static void stop_vacuum(char *dbpath, char *dbname);
36
37 void
38 createdb(char *dbname, char *dbpath, int encoding, CommandDest dest)
39 {
40         Oid                     db_id;
41         int4            user_id;
42         char            buf[512];
43         char       *lp,
44                                 loc[512];
45
46         /*
47          * If this call returns, the database does not exist and we're allowed
48          * to create databases.
49          */
50         check_permissions("createdb", dbpath, dbname, &db_id, &user_id);
51
52         /* close virtual file descriptors so we can do system() calls */
53         closeAllVfds();
54
55         /* Now create directory for this new database */
56         if ((dbpath != NULL) && (strcmp(dbpath, dbname) != 0))
57         {
58                 if (*(dbpath + strlen(dbpath) - 1) == SEP_CHAR)
59                         *(dbpath + strlen(dbpath) - 1) = '\0';
60                 snprintf(loc, 512, "%s%c%s", dbpath, SEP_CHAR, dbname);
61         }
62         else
63                 strcpy(loc, dbname);
64
65         lp = ExpandDatabasePath(loc);
66
67         if (lp == NULL)
68                 elog(ERROR, "Unable to locate path '%s'"
69                          "\n\tThis may be due to a missing environment variable"
70                          " in the server", loc);
71
72         if (mkdir(lp, S_IRWXU) != 0)
73                 elog(ERROR, "Unable to create database directory '%s'", lp);
74
75         snprintf(buf, 512, "%s %s%cbase%ctemplate1%c* %s",
76                          COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, lp);
77         system(buf);
78
79         snprintf(buf, 512,
80                    "insert into pg_database (datname, datdba, encoding, datpath)"
81                   " values ('%s', '%d', '%d', '%s');", dbname, user_id, encoding,
82                          loc);
83
84         pg_exec_query_dest(buf, dest, false);
85 }
86
87 void
88 destroydb(char *dbname, CommandDest dest)
89 {
90         int4            user_id;
91         Oid                     db_id;
92         char       *path,
93                                 dbpath[MAXPGPATH + 1],
94                                 buf[512];
95
96         /*
97          * If this call returns, the database exists and we're allowed to
98          * remove it.
99          */
100         check_permissions("destroydb", dbpath, dbname, &db_id, &user_id);
101
102         if (!OidIsValid(db_id))
103                 elog(FATAL, "pg_database instance has an invalid OID");
104
105         /* stop the vacuum daemon */
106         stop_vacuum(dbpath, dbname);
107
108         path = ExpandDatabasePath(dbpath);
109         if (path == NULL)
110                 elog(ERROR, "Unable to locate path '%s'"
111                          "\n\tThis may be due to a missing environment variable"
112                          " in the server", dbpath);
113
114         /*
115          * remove the pg_database tuple FIRST, this may fail due to
116          * permissions problems
117          */
118         snprintf(buf, 512,
119         "delete from pg_database where pg_database.oid = \'%u\'::oid", db_id);
120         pg_exec_query_dest(buf, dest, false);
121
122         /* drop pages for this database that are in the shared buffer cache */
123         DropBuffers(db_id);
124
125         /*
126          * remove the data directory. If the DELETE above failed, this will
127          * not be reached
128          */
129         snprintf(buf, 512, "rm -r %s", path);
130         system(buf);
131 }
132
133 static HeapTuple
134 get_pg_dbtup(char *command, char *dbname, Relation dbrel)
135 {
136         HeapTuple       dbtup;
137         HeapTuple       tup;
138         HeapScanDesc scan;
139         ScanKeyData scanKey;
140
141         ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
142                                                    F_NAMEEQ, NameGetDatum(dbname));
143
144         scan = heap_beginscan(dbrel, 0, SnapshotNow, 1, &scanKey);
145         if (!HeapScanIsValid(scan))
146                 elog(ERROR, "%s: cannot begin scan of pg_database", command);
147
148         /*
149          * since we want to return the tuple out of this proc, and we're going
150          * to close the relation, copy the tuple and return the copy.
151          */
152         tup = heap_getnext(scan, 0);
153
154         if (HeapTupleIsValid(tup))
155                 dbtup = heap_copytuple(tup);
156         else
157                 dbtup = tup;
158
159         heap_endscan(scan);
160         return dbtup;
161 }
162
163 /*
164  *      check_permissions() -- verify that the user is permitted to do this.
165  *
166  *      If the user is not allowed to carry out this operation, this routine
167  *      elog(ERROR, ...)s, which will abort the xact.  As a side effect, the
168  *      user's pg_user tuple OID is returned in userIdP and the target database's
169  *      OID is returned in dbIdP.
170  */
171
172 static void
173 check_permissions(char *command,
174                                   char *dbpath,
175                                   char *dbname,
176                                   Oid *dbIdP,
177                                   int4 *userIdP)
178 {
179         Relation        dbrel;
180         HeapTuple       dbtup,
181                                 utup;
182         int4            dbowner = 0;
183         char            use_createdb;
184         bool            dbfound;
185         bool            use_super;
186         char       *userName;
187         text       *dbtext;
188         char            path[MAXPGPATH + 1];
189
190         userName = GetPgUserName();
191         utup = SearchSysCacheTuple(USENAME,
192                                                            PointerGetDatum(userName),
193                                                            0, 0, 0);
194         *userIdP = ((Form_pg_shadow) GETSTRUCT(utup))->usesysid;
195         use_super = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
196         use_createdb = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;
197
198         /* Check to make sure user has permission to use createdb */
199         if (!use_createdb)
200         {
201                 elog(ERROR, "user '%s' is not allowed to create/destroy databases",
202                          userName);
203         }
204
205         /* Make sure we are not mucking with the template database */
206         if (!strcmp(dbname, "template1"))
207                 elog(ERROR, "%s: cannot be executed on the template database", command);
208
209         /* Check to make sure database is not the currently open database */
210         if (!strcmp(dbname, DatabaseName))
211                 elog(ERROR, "%s: cannot be executed on an open database", command);
212
213         /* Check to make sure database is owned by this user */
214
215         /*
216          * need the reldesc to get the database owner out of dbtup and to set
217          * a write lock on it.
218          */
219         dbrel = heap_openr(DatabaseRelationName);
220
221         if (!RelationIsValid(dbrel))
222                 elog(FATAL, "%s: cannot open relation \"%-.*s\"",
223                          command, DatabaseRelationName);
224
225         /*
226          * Acquire a write lock on pg_database from the beginning to avoid
227          * upgrading a read lock to a write lock.  Upgrading causes long
228          * delays when multiple 'createdb's or 'destroydb's are run simult.
229          * -mer 7/3/91
230          */
231         LockRelation(dbrel, AccessExclusiveLock);
232         dbtup = get_pg_dbtup(command, dbname, dbrel);
233         dbfound = HeapTupleIsValid(dbtup);
234
235         if (dbfound)
236         {
237                 dbowner = (int4) heap_getattr(dbtup,
238                                                                           Anum_pg_database_datdba,
239                                                                           RelationGetDescr(dbrel),
240                                                                           (char *) NULL);
241                 *dbIdP = dbtup->t_data->t_oid;
242                 dbtext = (text *) heap_getattr(dbtup,
243                                                                            Anum_pg_database_datpath,
244                                                                            RelationGetDescr(dbrel),
245                                                                            (char *) NULL);
246
247                 strncpy(path, VARDATA(dbtext), (VARSIZE(dbtext) - VARHDRSZ));
248                 *(path + VARSIZE(dbtext) - VARHDRSZ) = '\0';
249         }
250         else
251                 *dbIdP = InvalidOid;
252
253         heap_close(dbrel);
254
255         /*
256          * Now be sure that the user is allowed to do this.
257          */
258
259         if (dbfound && !strcmp(command, "createdb"))
260         {
261
262                 elog(ERROR, "createdb: database '%s' already exists", dbname);
263
264         }
265         else if (!dbfound && !strcmp(command, "destroydb"))
266         {
267
268                 elog(ERROR, "destroydb: database '%s' does not exist", dbname);
269
270         }
271         else if (dbfound && !strcmp(command, "destroydb")
272                          && dbowner != *userIdP && use_super == false)
273         {
274
275                 elog(ERROR, "%s: database '%s' is not owned by you", command, dbname);
276
277         }
278
279         if (dbfound && !strcmp(command, "destroydb"))
280                 strcpy(dbpath, path);
281 }       /* check_permissions() */
282
283 /*
284  *      stop_vacuum() -- stop the vacuum daemon on the database, if one is running.
285  */
286 static void
287 stop_vacuum(char *dbpath, char *dbname)
288 {
289         char            filename[256];
290         FILE       *fp;
291         int                     pid;
292
293         if (strchr(dbpath, SEP_CHAR) != 0)
294         {
295                 snprintf(filename, 256, "%s%cbase%c%s%c%s.vacuum",
296                                  DataDir, SEP_CHAR, SEP_CHAR, dbname, SEP_CHAR, dbname);
297         }
298         else
299                 snprintf(filename, 256, "%s%c%s.vacuum", dbpath, SEP_CHAR, dbname);
300
301 #ifndef __CYGWIN32__
302         if ((fp = AllocateFile(filename, "r")) != NULL)
303 #else
304         if ((fp = AllocateFile(filename, "rb")) != NULL)
305 #endif
306         {
307                 fscanf(fp, "%d", &pid);
308                 FreeFile(fp);
309                 if (kill(pid, SIGKILLDAEMON1) < 0)
310                 {
311                         elog(ERROR, "can't kill vacuum daemon (pid %d) on '%s'",
312                                  pid, dbname);
313                 }
314         }
315 }