8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.63 2000/10/28 16:20:54 vadim Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.64 2000/11/08 16:59:49 petere Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
17
17
18
18
#include <errno.h>
19
19
#include <fcntl.h>
20
- #include <stdlib.h>
21
- #include <string.h>
22
20
#include <unistd.h>
23
21
#include <sys/stat.h>
24
22
#include <sys/types.h>
37
35
38
36
39
37
/* non-export function prototypes */
40
- static bool
41
- get_user_info (Oid use_sysid , bool * use_super , bool * use_createdb );
42
-
43
- static bool
44
- get_db_info (const char * name , char * dbpath , Oid * dbIdP , int4 * ownerIdP );
45
-
38
+ static bool get_user_info (Oid use_sysid , bool * use_super , bool * use_createdb );
39
+ static bool get_db_info (const char * name , char * dbpath , Oid * dbIdP , int4 * ownerIdP );
40
+ static char * resolve_alt_dbpath (const char * dbpath , Oid dboid );
41
+ static bool remove_dbdirs (const char * real_loc , const char * altloc );
46
42
47
43
/*
48
44
* CREATE DATABASE
52
48
createdb (const char * dbname , const char * dbpath , int encoding )
53
49
{
54
50
char buf [2 * MAXPGPATH + 100 ];
55
- char * loc ;
56
- char locbuf [ 512 ] ;
51
+ char * altloc ;
52
+ char * real_loc ;
57
53
int ret ;
58
54
bool use_super ,
59
55
use_createdb ;
@@ -77,24 +73,6 @@ createdb(const char *dbname, const char *dbpath, int encoding)
77
73
if (IsTransactionBlock ())
78
74
elog (ERROR , "CREATE DATABASE: may not be called in a transaction block" );
79
75
80
- #ifdef OLD_FILE_NAMING
81
- /* Generate directory name for the new database */
82
- if (dbpath == NULL || strcmp (dbpath , dbname ) == 0 )
83
- strcpy (locbuf , dbname );
84
- else
85
- snprintf (locbuf , sizeof (locbuf ), "%s/%s" , dbpath , dbname );
86
-
87
- loc = ExpandDatabasePath (locbuf );
88
-
89
- if (loc == NULL )
90
- elog (ERROR ,
91
- "The database path '%s' is invalid. "
92
- "This may be due to a character that is not allowed or because the chosen "
93
- "path isn't permitted for databases" , dbpath );
94
- #else
95
- locbuf [0 ] = 0 ; /* Avoid junk in strings */
96
- #endif
97
-
98
76
/*
99
77
* Insert a new tuple into pg_database
100
78
*/
@@ -108,13 +86,15 @@ createdb(const char *dbname, const char *dbpath, int encoding)
108
86
dboid = newoid ();
109
87
110
88
/* Form tuple */
111
- new_record [Anum_pg_database_datname - 1 ] = DirectFunctionCall1 ( namein ,
112
- CStringGetDatum (dbname ));
89
+ new_record [Anum_pg_database_datname - 1 ] =
90
+ DirectFunctionCall1 ( namein , CStringGetDatum (dbname ));
113
91
new_record [Anum_pg_database_datdba - 1 ] = Int32GetDatum (GetUserId ());
114
92
new_record [Anum_pg_database_encoding - 1 ] = Int32GetDatum (encoding );
115
- new_record [Anum_pg_database_datlastsysoid - 1 ] = ObjectIdGetDatum (dboid ); /* Save current OID val */
116
- new_record [Anum_pg_database_datpath - 1 ] = DirectFunctionCall1 (textin ,
117
- CStringGetDatum (locbuf ));
93
+ /* Save current OID val */
94
+ new_record [Anum_pg_database_datlastsysoid - 1 ] = ObjectIdGetDatum (dboid );
95
+ /* no nulls here, GetRawDatabaseInfo doesn't like them */
96
+ new_record [Anum_pg_database_datpath - 1 ] =
97
+ DirectFunctionCall1 (textin , CStringGetDatum (dbpath ? dbpath : "" ));
118
98
119
99
tuple = heap_formtuple (pg_database_dsc , new_record , new_record_nulls );
120
100
@@ -126,9 +106,12 @@ createdb(const char *dbname, const char *dbpath, int encoding)
126
106
*/
127
107
heap_insert (pg_database_rel , tuple );
128
108
129
- #ifndef OLD_FILE_NAMING
130
- loc = GetDatabasePath (tuple -> t_data -> t_oid );
131
- #endif
109
+ real_loc = GetDatabasePath (tuple -> t_data -> t_oid );
110
+ altloc = resolve_alt_dbpath (dbpath , tuple -> t_data -> t_oid );
111
+
112
+ if (strchr (real_loc , '\'' ) && strchr (altloc , '\'' ))
113
+ elog (ERROR , "database path may not contain single quotes" );
114
+ /* ... otherwise we'd be open to shell exploits below */
132
115
133
116
/*
134
117
* Update indexes (there aren't any currently)
@@ -156,41 +139,28 @@ createdb(const char *dbname, const char *dbpath, int encoding)
156
139
157
140
/* Copy the template database to the new location */
158
141
159
- if (mkdir (loc , S_IRWXU ) != 0 )
160
- elog (ERROR , "CREATE DATABASE: unable to create database directory '%s': %s" , loc , strerror (errno ));
142
+ if (mkdir ((altloc ? altloc : real_loc ), S_IRWXU ) != 0 )
143
+ elog (ERROR , "CREATE DATABASE: unable to create database directory '%s': %s" ,
144
+ (altloc ? altloc : real_loc ), strerror (errno ));
161
145
162
- #ifdef OLD_FILE_NAMING
163
- snprintf (buf , sizeof (buf ), "cp %s%cbase%ctemplate1%c* '%s'" ,
164
- DataDir , SEP_CHAR , SEP_CHAR , SEP_CHAR , loc );
165
- #else
146
+ if (altloc )
166
147
{
167
- char * tmpl = GetDatabasePath (TemplateDbOid );
168
-
169
- snprintf (buf , sizeof (buf ), "cp %s%c* '%s'" ,
170
- tmpl , SEP_CHAR , loc );
171
- pfree (tmpl );
148
+ if (symlink (altloc , real_loc ) != 0 )
149
+ elog (ERROR , "CREATE DATABASE: could not link %s to %s: %s" ,
150
+ real_loc , altloc , strerror (errno ));
172
151
}
173
- #endif
152
+
153
+ snprintf (buf , sizeof (buf ), "cp '%s'/* '%s'" ,
154
+ GetDatabasePath (TemplateDbOid ), real_loc );
174
155
175
156
ret = system (buf );
176
157
/* Some versions of SunOS seem to return ECHILD after a system() call */
177
- #if defined(sun )
178
158
if (ret != 0 && errno != ECHILD )
179
- #else
180
- if (ret != 0 )
181
- #endif
182
159
{
183
- /* Failed, so try to clean up the created directory ... */
184
- snprintf (buf , sizeof (buf ), "rm -rf '%s'" , loc );
185
- ret = system (buf );
186
- #if defined(sun )
187
- if (ret == 0 || errno == ECHILD )
188
- #else
189
- if (ret == 0 )
190
- #endif
160
+ if (remove_dbdirs (real_loc , altloc ))
191
161
elog (ERROR , "CREATE DATABASE: could not initialize database directory" );
192
162
else
193
- elog (ERROR , "CREATE DATABASE: Could not initialize database directory. Delete failed as well" );
163
+ elog (ERROR , "CREATE DATABASE: could not initialize database directory; delete failed as well" );
194
164
}
195
165
196
166
#ifdef XLOG
@@ -210,9 +180,9 @@ dropdb(const char *dbname)
210
180
int4 db_owner ;
211
181
bool use_super ;
212
182
Oid db_id ;
213
- char * path ,
214
- dbpath [ MAXPGPATH ],
215
- buf [ MAXPGPATH + 100 ];
183
+ char * altloc ;
184
+ char * real_loc ;
185
+ char dbpath [ MAXPGPATH ];
216
186
Relation pgdbrel ;
217
187
HeapScanDesc pgdbscan ;
218
188
ScanKeyData key ;
@@ -221,33 +191,25 @@ dropdb(const char *dbname)
221
191
AssertArg (dbname );
222
192
223
193
if (strcmp (dbname , "template1" ) == 0 )
224
- elog (ERROR , "DROP DATABASE: May not be executed on the template1 database" );
194
+ elog (ERROR , "DROP DATABASE: may not be executed on the template1 database" );
225
195
226
196
if (strcmp (dbname , DatabaseName ) == 0 )
227
- elog (ERROR , "DROP DATABASE: Cannot be executed on the currently open database" );
197
+ elog (ERROR , "DROP DATABASE: cannot be executed on the currently open database" );
228
198
229
199
if (IsTransactionBlock ())
230
- elog (ERROR , "DROP DATABASE: May not be called in a transaction block" );
200
+ elog (ERROR , "DROP DATABASE: may not be called in a transaction block" );
231
201
232
202
if (!get_user_info (GetUserId (), & use_super , NULL ))
233
- elog (ERROR , "Current user name is invalid" );
203
+ elog (ERROR , "current user name is invalid" );
234
204
235
205
if (!get_db_info (dbname , dbpath , & db_id , & db_owner ))
236
- elog (ERROR , "DROP DATABASE: Database \"%s\" does not exist" , dbname );
206
+ elog (ERROR , "DROP DATABASE: database \"%s\" does not exist" , dbname );
237
207
238
208
if (GetUserId () != db_owner && !use_super )
239
- elog (ERROR , "DROP DATABASE: Permission denied" );
240
-
241
- #ifdef OLD_FILE_NAMING
242
- path = ExpandDatabasePath (dbpath );
243
- if (path == NULL )
244
- elog (ERROR ,
245
- "The database path '%s' is invalid. "
246
- "This may be due to a character that is not allowed or because the chosen "
247
- "path isn't permitted for databases" , path );
248
- #else
249
- path = GetDatabasePath (db_id );
250
- #endif
209
+ elog (ERROR , "DROP DATABASE: permission denied" );
210
+
211
+ real_loc = GetDatabasePath (db_id );
212
+ altloc = resolve_alt_dbpath (dbpath , db_id );
251
213
252
214
/*
253
215
* Obtain exclusive lock on pg_database. We need this to ensure that
@@ -266,7 +228,7 @@ dropdb(const char *dbname)
266
228
if (DatabaseHasActiveBackends (db_id ))
267
229
{
268
230
heap_close (pgdbrel , AccessExclusiveLock );
269
- elog (ERROR , "DROP DATABASE: Database \"%s\" is being accessed by other users" , dbname );
231
+ elog (ERROR , "DROP DATABASE: database \"%s\" is being accessed by other users" , dbname );
270
232
}
271
233
272
234
/*
@@ -320,13 +282,7 @@ dropdb(const char *dbname)
320
282
/*
321
283
* Remove the database's subdirectory and everything in it.
322
284
*/
323
- snprintf (buf , sizeof (buf ), "rm -rf '%s'" , path );
324
- #if defined(sun )
325
- if (system (buf ) != 0 && errno != ECHILD )
326
- #else
327
- if (system (buf ) != 0 )
328
- #endif
329
- elog (NOTICE , "DROP DATABASE: The database directory '%s' could not be removed" , path );
285
+ remove_dbdirs (real_loc , altloc );
330
286
}
331
287
332
288
@@ -426,3 +382,66 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
426
382
427
383
return true;
428
384
}
385
+
386
+
387
+ static char *
388
+ resolve_alt_dbpath (const char * dbpath , Oid dboid )
389
+ {
390
+ char * prefix ;
391
+ char * ret ;
392
+ size_t len ;
393
+
394
+ if (dbpath == NULL || dbpath [0 ] == '\0' )
395
+ return NULL ;
396
+
397
+ if (strchr (dbpath , '/' ))
398
+ {
399
+ #ifdef ALLOW_ABSOLUTE_DBPATHS
400
+ prefix = dbpath ;
401
+ #else
402
+ elog (ERROR , "Absolute paths are not allowed as database locations" );
403
+ #endif
404
+ }
405
+ else
406
+ {
407
+ /* must be environment variable */
408
+ char * var = getenv (dbpath );
409
+ if (!var )
410
+ elog (ERROR , "environment variable %s not set" , dbpath );
411
+ if (var [0 ] != '/' )
412
+ elog (ERROR , "environment variable %s must be absolute path" , dbpath );
413
+ prefix = var ;
414
+ }
415
+
416
+ len = strlen (prefix ) + 6 + sizeof (Oid ) * 8 + 1 ;
417
+ ret = palloc (len );
418
+ snprintf (ret , len , "%s/base/%u" , prefix , dboid );
419
+
420
+ return ret ;
421
+ }
422
+
423
+
424
+ static bool
425
+ remove_dbdirs (const char * real_loc , const char * altloc )
426
+ {
427
+ char buf [MAXPGPATH + 100 ];
428
+ bool success = true;
429
+
430
+ if (altloc )
431
+ /* remove symlink */
432
+ if (unlink (real_loc ) != 0 )
433
+ {
434
+ elog (NOTICE , "could not remove '%s': %s" , real_loc , strerror (errno ));
435
+ success = false;
436
+ }
437
+
438
+ snprintf (buf , sizeof (buf ), "rm -rf '%s'" , altloc ? altloc : real_loc );
439
+ if (system (buf ) != 0 && errno != ECHILD )
440
+ {
441
+ elog (NOTICE , "database directory '%s' could not be removed" ,
442
+ altloc ? altloc : real_loc );
443
+ success = false;
444
+ }
445
+
446
+ return success ;
447
+ }
0 commit comments