xref: /illumos-gate/usr/src/cmd/svc/configd/backend.c (revision bbf21555)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * sqlite is not compatible with _FILE_OFFSET_BITS=64, but we need to
29  * be able to statvfs(2) possibly large systems.  This define gives us
30  * access to the transitional interfaces.  See lfcompile64(7) for how
31  * _LARGEFILE64_SOURCE works.
32  */
33 #define	_LARGEFILE64_SOURCE
34 
35 #include <assert.h>
36 #include <atomic.h>
37 #include <door.h>
38 #include <dirent.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <pthread.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <sys/stat.h>
49 #include <sys/statvfs.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <zone.h>
53 #include <libscf_priv.h>
54 
55 #include "configd.h"
56 #include "repcache_protocol.h"
57 
58 #include <sqlite.h>
59 #include <sqlite-misc.h>
60 
61 /*
62  * This file has two purposes:
63  *
64  * 1. It contains the database schema, and the code for setting up our backend
65  *    databases, including installing said schema.
66  *
67  * 2. It provides a simplified interface to the SQL database library, and
68  *    synchronizes MT access to the database.
69  */
70 
71 #define	IS_VOLATILE(be)		((be)->be_ppath != NULL)
72 #define	MAX_FLIGHT_RECORDER_EVENTS	100
73 
74 typedef enum backend_switch_results {
75 	BACKEND_SWITCH_FATAL =	-1,
76 	BACKEND_SWITCH_OK =	0,
77 	BACKEND_SWITCH_RO
78 } backend_switch_results_t;
79 
80 typedef struct backend_spent {
81 	uint64_t bs_count;
82 	hrtime_t bs_time;
83 	hrtime_t bs_vtime;
84 } backend_spent_t;
85 
86 typedef struct backend_totals {
87 	backend_spent_t	bt_lock;	/* waiting for lock */
88 	backend_spent_t	bt_exec;	/* time spent executing SQL */
89 } backend_totals_t;
90 
91 /*
92  * There are times when svcadm asks configd to move the BACKEND_TYPE_NORMAL
93  * repository to volatile storage.  See backend_switch().  When the
94  * repository is on volatile storage, we save the location of the permanent
95  * repository in be_ppath.  We use the saved path when the time comes to
96  * move the repository back.  When the repository is on permanent storage,
97  * be_ppath is set to NULL.  Also see the definition of IS_VOLATILE() above
98  * for testing if the repository is on volatile storage.
99  */
100 typedef struct sqlite_backend {
101 	pthread_mutex_t	be_lock;
102 	pthread_t	be_thread;	/* thread holding lock */
103 	struct sqlite	*be_db;
104 	const char	*be_path;	/* path to db */
105 	const char	*be_ppath;	/* saved path to persistent db when */
106 					/* backend is volatile */
107 	const char	*be_checkpoint;	/* path to repository checkpoint */
108 	int		be_readonly;	/* readonly at start, and still is */
109 	int		be_writing;	/* held for writing */
110 	backend_type_t	be_type;	/* type of db */
111 	hrtime_t	be_lastcheck;	/* time of last read-only check */
112 	backend_totals_t be_totals[2];	/* one for reading, one for writing */
113 } sqlite_backend_t;
114 
115 struct backend_tx {
116 	sqlite_backend_t	*bt_be;
117 	int			bt_readonly;
118 	int			bt_type;
119 	int			bt_full;	/* SQLITE_FULL during tx */
120 };
121 
122 #define	UPDATE_TOTALS_WR(sb, writing, field, ts, vts) { \
123 	backend_spent_t *__bsp = &(sb)->be_totals[!!(writing)].field; \
124 	__bsp->bs_count++;						\
125 	__bsp->bs_time += (gethrtime() - ts);				\
126 	__bsp->bs_vtime += (gethrvtime() - vts);			\
127 }
128 
129 #define	UPDATE_TOTALS(sb, field, ts, vts) \
130 	UPDATE_TOTALS_WR(sb, (sb)->be_writing, field, ts, vts)
131 
132 struct backend_query {
133 	char	*bq_buf;
134 	size_t	bq_size;
135 };
136 
137 struct backend_tbl_info {
138 	const char *bti_name;
139 	const char *bti_cols;
140 };
141 
142 struct backend_idx_info {
143 	const char *bxi_tbl;
144 	const char *bxi_idx;
145 	const char *bxi_cols;
146 };
147 
148 /* Definitions for the flight recorder: */
149 
150 typedef enum be_flight_type {
151 	BE_FLIGHT_EV_NOEVENT = 0,	/* No event yet recorded. */
152 	BE_FLIGHT_EV_BACKUP,		/* Information about repo. backup */
153 	BE_FLIGHT_EV_BACKUP_ENTER,	/* Enter */
154 					/* backend_create_backup_locked() */
155 	BE_FLIGHT_EV_CHECKPOINT,	/* Request to checkpoint repository */
156 					/* for boot time backup */
157 	BE_FLIGHT_EV_CHECKPOINT_EXISTS,	/* Existing checkpoint detected on */
158 					/* restart */
159 	BE_FLIGHT_EV_LINGERING_FAST,	/* Use lingering fast repository */
160 	BE_FLIGHT_EV_NO_BACKUP,		/* Requested backup not made */
161 	BE_FLIGHT_EV_REPO_CREATE,	/* Main repository created */
162 	BE_FLIGHT_EV_RESTART,		/* This is a restart of configd */
163 	BE_FLIGHT_EV_SWITCH,		/* Switch repositories */
164 	BE_FLIGHT_EV_TRANS_RW		/* Root transitioned to read/write */
165 } be_flight_type_t;
166 
167 typedef enum be_flight_status {
168 	BE_FLIGHT_ST_INFO = 0,		/* No status.  Event is informative */
169 	BE_FLIGHT_ST_BOOT_BACKUP,	/* Boot time backup */
170 	BE_FLIGHT_ST_CHECKPOINT_BACKUP,	/* Backup from checkpoint */
171 	BE_FLIGHT_ST_CLIENT,		/* Request form client as opposed to */
172 					/* internal call */
173 	BE_FLIGHT_ST_DUPLICATE,		/* Backup duplicates existing one */
174 	BE_FLIGHT_ST_FAIL,		/* Operation failed. */
175 	BE_FLIGHT_ST_FAST,		/* Fast repository (tmpfs) */
176 	BE_FLIGHT_ST_MI_BACKUP,		/* Manifest-import backup */
177 	BE_FLIGHT_ST_NO_SWITCH,		/* Don't switch repositories */
178 	BE_FLIGHT_ST_OTHER_BACKUP,	/* Other type of backup */
179 	BE_FLIGHT_ST_PERMANENT,		/* Repository on permanet storage */
180 	BE_FLIGHT_ST_REPO_BACKUP,	/* Backup from repository */
181 	BE_FLIGHT_ST_RO,		/* Main repository is read-only */
182 	BE_FLIGHT_ST_RW,		/* Main repository is read/write */
183 	BE_FLIGHT_ST_SUCCESS,		/* Operation was successful */
184 	BE_FLIGHT_ST_SWITCH		/* Switch repository */
185 } be_flight_status_t;
186 
187 typedef struct be_flight_event {
188 	be_flight_type_t	bfe_type;	/* Type of event. */
189 	be_flight_status_t	bfe_status;	/* Result of the event. */
190 	time_t			bfe_time;	/* Time of the event. */
191 	uint_t			bfe_sequence;	/* Sequence number. */
192 } be_flight_event_t;
193 
194 static pthread_mutex_t backend_panic_lock = PTHREAD_MUTEX_INITIALIZER;
195 static pthread_cond_t backend_panic_cv = PTHREAD_COND_INITIALIZER;
196 pthread_t backend_panic_thread = 0;
197 
198 int backend_do_trace = 0;		/* invoke tracing callback */
199 int backend_print_trace = 0;		/* tracing callback prints SQL */
200 int backend_panic_abort = 0;		/* abort when panicking */
201 
202 /* Data for the flight_recorder. */
203 
204 static pthread_mutex_t backend_flight_recorder_lock = PTHREAD_MUTEX_INITIALIZER;
205 static be_flight_event_t flight_recorder[MAX_FLIGHT_RECORDER_EVENTS];
206 static uint_t flight_recorder_next = 0;
207 static uint_t flight_recorder_missed = 0;
208 static uint_t flight_recorder_sequence = 0;
209 
210 /* interval between read-only checks while starting up */
211 #define	BACKEND_READONLY_CHECK_INTERVAL	(2 * (hrtime_t)NANOSEC)
212 
213 /*
214  * Any incompatible change to the below schema should bump the version number.
215  * The schema has been changed to support value ordering,  but this change
216  * is backwards-compatible - i.e. a previous svc.configd can use a
217  * repository database with the new schema perfectly well.  As a result,
218  * the schema version has not been updated,  allowing downgrade of systems
219  * without losing repository data.
220  */
221 #define	BACKEND_SCHEMA_VERSION		5
222 
223 static struct backend_tbl_info tbls_normal[] = { /* BACKEND_TYPE_NORMAL */
224 	/*
225 	 * service_tbl holds all services.  svc_id is the identifier of the
226 	 * service.
227 	 */
228 	{
229 		"service_tbl",
230 		"svc_id          INTEGER PRIMARY KEY,"
231 		"svc_name        CHAR(256) NOT NULL"
232 	},
233 
234 	/*
235 	 * instance_tbl holds all of the instances.  The parent service id
236 	 * is instance_svc.
237 	 */
238 	{
239 		"instance_tbl",
240 		"instance_id     INTEGER PRIMARY KEY,"
241 		"instance_name   CHAR(256) NOT NULL,"
242 		"instance_svc    INTEGER NOT NULL"
243 	},
244 
245 	/*
246 	 * snapshot_lnk_tbl links (instance, snapshot name) with snapshots.
247 	 */
248 	{
249 		"snapshot_lnk_tbl",
250 		"lnk_id          INTEGER PRIMARY KEY,"
251 		"lnk_inst_id     INTEGER NOT NULL,"
252 		"lnk_snap_name   CHAR(256) NOT NULL,"
253 		"lnk_snap_id     INTEGER NOT NULL"
254 	},
255 
256 	/*
257 	 * snaplevel_tbl maps a snapshot id to a set of named, ordered
258 	 * snaplevels.
259 	 */
260 	{
261 		"snaplevel_tbl",
262 		"snap_id                 INTEGER NOT NULL,"
263 		"snap_level_num          INTEGER NOT NULL,"
264 		"snap_level_id           INTEGER NOT NULL,"
265 		"snap_level_service_id   INTEGER NOT NULL,"
266 		"snap_level_service      CHAR(256) NOT NULL,"
267 		"snap_level_instance_id  INTEGER NULL,"
268 		"snap_level_instance     CHAR(256) NULL"
269 	},
270 
271 	/*
272 	 * snaplevel_lnk_tbl links snaplevels to property groups.
273 	 * snaplvl_pg_* is identical to the original property group,
274 	 * and snaplvl_gen_id overrides the generation number.
275 	 * The service/instance ids are as in the snaplevel.
276 	 */
277 	{
278 		"snaplevel_lnk_tbl",
279 		"snaplvl_level_id INTEGER NOT NULL,"
280 		"snaplvl_pg_id    INTEGER NOT NULL,"
281 		"snaplvl_pg_name  CHAR(256) NOT NULL,"
282 		"snaplvl_pg_type  CHAR(256) NOT NULL,"
283 		"snaplvl_pg_flags INTEGER NOT NULL,"
284 		"snaplvl_gen_id   INTEGER NOT NULL"
285 	},
286 
287 	{ NULL, NULL }
288 };
289 
290 static struct backend_idx_info idxs_normal[] = { /* BACKEND_TYPE_NORMAL */
291 	{ "service_tbl",	"name",	"svc_name" },
292 	{ "instance_tbl",	"name",	"instance_svc, instance_name" },
293 	{ "snapshot_lnk_tbl",	"name",	"lnk_inst_id, lnk_snap_name" },
294 	{ "snapshot_lnk_tbl",	"snapid", "lnk_snap_id" },
295 	{ "snaplevel_tbl",	"id",	"snap_id" },
296 	{ "snaplevel_lnk_tbl",	"id",	"snaplvl_pg_id" },
297 	{ "snaplevel_lnk_tbl",	"level", "snaplvl_level_id" },
298 	{ NULL, NULL, NULL }
299 };
300 
301 static struct backend_tbl_info tbls_np[] = { /* BACKEND_TYPE_NONPERSIST */
302 	{ NULL, NULL }
303 };
304 
305 static struct backend_idx_info idxs_np[] = {	/* BACKEND_TYPE_NONPERSIST */
306 	{ NULL, NULL, NULL }
307 };
308 
309 static struct backend_tbl_info tbls_common[] = { /* all backend types */
310 	/*
311 	 * pg_tbl defines property groups.  They are associated with a single
312 	 * service or instance.  The pg_gen_id links them with the latest
313 	 * "edited" version of its properties.
314 	 */
315 	{
316 		"pg_tbl",
317 		"pg_id           INTEGER PRIMARY KEY,"
318 		"pg_parent_id    INTEGER NOT NULL,"
319 		"pg_name         CHAR(256) NOT NULL,"
320 		"pg_type         CHAR(256) NOT NULL,"
321 		"pg_flags        INTEGER NOT NULL,"
322 		"pg_gen_id       INTEGER NOT NULL"
323 	},
324 
325 	/*
326 	 * prop_lnk_tbl links a particular pg_id and gen_id to a set of
327 	 * (prop_name, prop_type, val_id) trios.
328 	 */
329 	{
330 		"prop_lnk_tbl",
331 		"lnk_prop_id     INTEGER PRIMARY KEY,"
332 		"lnk_pg_id       INTEGER NOT NULL,"
333 		"lnk_gen_id      INTEGER NOT NULL,"
334 		"lnk_prop_name   CHAR(256) NOT NULL,"
335 		"lnk_prop_type   CHAR(2) NOT NULL,"
336 		"lnk_val_id      INTEGER"
337 	},
338 
339 	/*
340 	 * value_tbl maps a value_id to a set of values.  For any given
341 	 * value_id, value_type is constant.  The table definition here
342 	 * is repeated in backend_check_upgrade(),  and must be kept in-sync.
343 	 */
344 	{
345 		"value_tbl",
346 		"value_id        INTEGER NOT NULL,"
347 		"value_type      CHAR(1) NOT NULL,"
348 		"value_value     VARCHAR NOT NULL,"
349 		"value_order     INTEGER DEFAULT 0"
350 	},
351 
352 	/*
353 	 * id_tbl has one row per id space
354 	 */
355 	{
356 		"id_tbl",
357 		"id_name         STRING NOT NULL,"
358 		"id_next         INTEGER NOT NULL"
359 	},
360 
361 	/*
362 	 * schema_version has a single row, which contains
363 	 * BACKEND_SCHEMA_VERSION at the time of creation.
364 	 */
365 	{
366 		"schema_version",
367 		"schema_version  INTEGER"
368 	},
369 	{ NULL, NULL }
370 };
371 
372 /*
373  * The indexing of value_tbl is repeated in backend_check_upgrade() and
374  * must be kept in sync with the indexing specification here.
375  */
376 static struct backend_idx_info idxs_common[] = { /* all backend types */
377 	{ "pg_tbl",		"parent", "pg_parent_id" },
378 	{ "pg_tbl",		"name",	"pg_parent_id, pg_name" },
379 	{ "pg_tbl",		"type",	"pg_parent_id, pg_type" },
380 	{ "prop_lnk_tbl",	"base",	"lnk_pg_id, lnk_gen_id" },
381 	{ "prop_lnk_tbl",	"val",	"lnk_val_id" },
382 	{ "value_tbl",		"id",	"value_id" },
383 	{ "id_tbl",		"id",	"id_name" },
384 	{ NULL, NULL, NULL }
385 };
386 
387 struct run_single_int_info {
388 	uint32_t	*rs_out;
389 	int		rs_result;
390 };
391 
392 static rep_protocol_responseid_t backend_copy_repository(const char *,
393     const char *, int);
394 static rep_protocol_responseid_t backend_do_copy(const char *, int,
395     const char *, int, size_t *);
396 
397 /*
398  * The flight recorder keeps track of events that happen primarily while
399  * the system is booting.  Once the system is up an running, one can take a
400  * gcore(1) of configd and examine the events with mdb.  Since we're most
401  * interested in early boot events, we stop recording events when the
402  * recorder is full.
403  */
404 static void
flight_recorder_event(be_flight_type_t type,be_flight_status_t res)405 flight_recorder_event(be_flight_type_t type, be_flight_status_t res)
406 {
407 	be_flight_event_t *data;
408 	uint_t item;
409 	uint_t sequence;
410 
411 	if (pthread_mutex_lock(&backend_flight_recorder_lock) != 0) {
412 		atomic_inc_uint(&flight_recorder_missed);
413 		return;
414 	}
415 	if (flight_recorder_next >= MAX_FLIGHT_RECORDER_EVENTS) {
416 		/* Hit end of the array.  No more event recording. */
417 		item = flight_recorder_next;
418 	} else {
419 		item = flight_recorder_next++;
420 		sequence = flight_recorder_sequence++;
421 	}
422 	(void) pthread_mutex_unlock(&backend_flight_recorder_lock);
423 
424 	if (item >= MAX_FLIGHT_RECORDER_EVENTS) {
425 		/* Array is filled.  Stop recording events */
426 		atomic_inc_uint(&flight_recorder_missed);
427 		return;
428 	}
429 	data = &flight_recorder[item];
430 	(void) memset(data, 0, sizeof (*data));
431 	data->bfe_type = type;
432 	data->bfe_status = res;
433 	data->bfe_sequence = sequence;
434 	data->bfe_time = time(NULL);
435 }
436 
437 /*ARGSUSED*/
438 static int
run_single_int_callback(void * arg,int columns,char ** vals,char ** names)439 run_single_int_callback(void *arg, int columns, char **vals, char **names)
440 {
441 	struct run_single_int_info *info = arg;
442 	uint32_t val;
443 
444 	char *endptr = vals[0];
445 
446 	assert(info->rs_result != REP_PROTOCOL_SUCCESS);
447 	assert(columns == 1);
448 
449 	if (vals[0] == NULL)
450 		return (BACKEND_CALLBACK_CONTINUE);
451 
452 	errno = 0;
453 	val = strtoul(vals[0], &endptr, 10);
454 	if ((val == 0 && endptr == vals[0]) || *endptr != 0 || errno != 0)
455 		backend_panic("malformed integer \"%20s\"", vals[0]);
456 
457 	*info->rs_out = val;
458 	info->rs_result = REP_PROTOCOL_SUCCESS;
459 	return (BACKEND_CALLBACK_CONTINUE);
460 }
461 
462 /*ARGSUSED*/
463 int
backend_fail_if_seen(void * arg,int columns,char ** vals,char ** names)464 backend_fail_if_seen(void *arg, int columns, char **vals, char **names)
465 {
466 	return (BACKEND_CALLBACK_ABORT);
467 }
468 
469 /*
470  * check to see if we can successfully start a transaction;  if not, the
471  * filesystem is mounted read-only.
472  */
473 static int
backend_is_readonly(struct sqlite * db,const char * path)474 backend_is_readonly(struct sqlite *db, const char *path)
475 {
476 	int r;
477 	statvfs64_t stat;
478 
479 	if (statvfs64(path, &stat) == 0 && (stat.f_flag & ST_RDONLY))
480 		return (SQLITE_READONLY);
481 
482 	r = sqlite_exec(db,
483 	    "BEGIN TRANSACTION; "
484 	    "UPDATE schema_version SET schema_version = schema_version; ",
485 	    NULL, NULL, NULL);
486 	(void) sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
487 	return (r);
488 }
489 
490 static void
backend_trace_sql(void * arg,const char * sql)491 backend_trace_sql(void *arg, const char *sql)
492 {
493 	sqlite_backend_t *be = arg;
494 
495 	if (backend_print_trace) {
496 		(void) fprintf(stderr, "%d: %s\n", be->be_type, sql);
497 	}
498 }
499 
500 static sqlite_backend_t be_info[BACKEND_TYPE_TOTAL];
501 static sqlite_backend_t *bes[BACKEND_TYPE_TOTAL];
502 
503 /*
504  * For a native build,  repositories are created from scratch, so upgrade
505  * is not an issue.  This variable is implicitly protected by
506  * bes[BACKEND_TYPE_NORMAL]->be_lock.
507  */
508 #ifdef NATIVE_BUILD
509 static boolean_t be_normal_upgraded = B_TRUE;
510 #else
511 static boolean_t be_normal_upgraded = B_FALSE;
512 #endif	/* NATIVE_BUILD */
513 
514 /*
515  * Has backend been upgraded? In nonpersistent case, answer is always
516  * yes.
517  */
518 boolean_t
backend_is_upgraded(backend_tx_t * bt)519 backend_is_upgraded(backend_tx_t *bt)
520 {
521 	if (bt->bt_type == BACKEND_TYPE_NONPERSIST)
522 		return (B_TRUE);
523 	return (be_normal_upgraded);
524 }
525 
526 #define	BACKEND_PANIC_TIMEOUT	(50 * MILLISEC)
527 /*
528  * backend_panic() -- some kind of database problem or corruption has been hit.
529  * We attempt to quiesce the other database users -- all of the backend sql
530  * entry points will call backend_panic(NULL) if a panic is in progress, as
531  * will any attempt to start a transaction.
532  *
533  * We give threads holding a backend lock 50ms (BACKEND_PANIC_TIMEOUT) to
534  * either drop the lock or call backend_panic().  If they don't respond in
535  * time, we'll just exit anyway.
536  */
537 void
backend_panic(const char * format,...)538 backend_panic(const char *format, ...)
539 {
540 	int i;
541 	va_list args;
542 	int failed = 0;
543 
544 	(void) pthread_mutex_lock(&backend_panic_lock);
545 	if (backend_panic_thread != 0) {
546 		(void) pthread_mutex_unlock(&backend_panic_lock);
547 		/*
548 		 * first, drop any backend locks we're holding, then
549 		 * sleep forever on the panic_cv.
550 		 */
551 		for (i = 0; i < BACKEND_TYPE_TOTAL; i++) {
552 			if (bes[i] != NULL &&
553 			    bes[i]->be_thread == pthread_self())
554 				(void) pthread_mutex_unlock(&bes[i]->be_lock);
555 		}
556 		(void) pthread_mutex_lock(&backend_panic_lock);
557 		for (;;)
558 			(void) pthread_cond_wait(&backend_panic_cv,
559 			    &backend_panic_lock);
560 	}
561 	backend_panic_thread = pthread_self();
562 	(void) pthread_mutex_unlock(&backend_panic_lock);
563 
564 	for (i = 0; i < BACKEND_TYPE_TOTAL; i++) {
565 		if (bes[i] != NULL && bes[i]->be_thread == pthread_self())
566 			(void) pthread_mutex_unlock(&bes[i]->be_lock);
567 	}
568 
569 	va_start(args, format);
570 	configd_vcritical(format, args);
571 	va_end(args);
572 
573 	for (i = 0; i < BACKEND_TYPE_TOTAL; i++) {
574 		timespec_t rel;
575 
576 		rel.tv_sec = 0;
577 		rel.tv_nsec = BACKEND_PANIC_TIMEOUT;
578 
579 		if (bes[i] != NULL && bes[i]->be_thread != pthread_self()) {
580 			if (pthread_mutex_reltimedlock_np(&bes[i]->be_lock,
581 			    &rel) != 0)
582 				failed++;
583 		}
584 	}
585 	if (failed) {
586 		configd_critical("unable to quiesce database\n");
587 	}
588 
589 	if (backend_panic_abort)
590 		abort();
591 
592 	exit(CONFIGD_EXIT_DATABASE_BAD);
593 }
594 
595 /*
596  * Returns
597  *   _SUCCESS
598  *   _DONE - callback aborted query
599  *   _NO_RESOURCES - out of memory (_FULL & _TOOBIG?)
600  */
601 static int
backend_error(sqlite_backend_t * be,int error,char * errmsg)602 backend_error(sqlite_backend_t *be, int error, char *errmsg)
603 {
604 	if (error == SQLITE_OK)
605 		return (REP_PROTOCOL_SUCCESS);
606 
607 	switch (error) {
608 	case SQLITE_ABORT:
609 		free(errmsg);
610 		return (REP_PROTOCOL_DONE);
611 
612 	case SQLITE_NOMEM:
613 	case SQLITE_FULL:
614 	case SQLITE_TOOBIG:
615 		free(errmsg);
616 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
617 
618 	default:
619 		backend_panic("%s: db error: %s", be->be_path, errmsg);
620 		/*NOTREACHED*/
621 	}
622 }
623 
624 static void
backend_backup_cleanup(const char ** out_arg,ssize_t out_sz)625 backend_backup_cleanup(const char **out_arg, ssize_t out_sz)
626 {
627 	char **out = (char **)out_arg;
628 
629 	while (out_sz-- > 0)
630 		free(*out++);
631 	free(out_arg);
632 }
633 
634 /*
635  * builds a inverse-time-sorted array of backup files.  The path is a
636  * a single buffer, and the pointers look like:
637  *
638  *	/this/is/a/full/path/to/repository-name-YYYYMMDDHHMMSS
639  *	^pathname		^	       ^(pathname+pathlen)
640  *				basename
641  *
642  * dirname will either be pathname, or ".".
643  *
644  * Returns the number of elements in the array, 0 if there are no previous
645  * backups, or -1 on error.
646  */
647 static ssize_t
backend_backup_get_prev(char * pathname,size_t pathlen,const char *** out_arg)648 backend_backup_get_prev(char *pathname, size_t pathlen, const char ***out_arg)
649 {
650 	char b_start, b_end;
651 	DIR *dir;
652 	char **out = NULL;
653 	char *name, *p;
654 	char *dirname, *basename;
655 	char *pathend;
656 	struct dirent *ent;
657 
658 	size_t count = 0;
659 	size_t baselen;
660 
661 	/*
662 	 * year, month, day, hour, min, sec, plus an '_'.
663 	 */
664 	const size_t ndigits = 4 + 5*2 + 1;
665 	const size_t baroffset = 4 + 2*2;
666 
667 	size_t idx;
668 
669 	pathend = pathname + pathlen;
670 	b_end = *pathend;
671 	*pathend = '\0';
672 
673 	basename = strrchr(pathname, '/');
674 
675 	if (basename != NULL) {
676 		assert(pathend > pathname && basename < pathend);
677 		basename++;
678 		dirname = pathname;
679 	} else {
680 		basename = pathname;
681 		dirname = ".";
682 	}
683 
684 	baselen = strlen(basename);
685 
686 	/*
687 	 * munge the string temporarily for the opendir(), then restore it.
688 	 */
689 	b_start = basename[0];
690 
691 	basename[0] = '\0';
692 	dir = opendir(dirname);
693 	basename[0] = b_start;		/* restore path */
694 
695 	if (dir == NULL)
696 		goto fail;
697 
698 
699 	while ((ent = readdir(dir)) != NULL) {
700 		/*
701 		 * Must match:
702 		 *	basename-YYYYMMDD_HHMMSS
703 		 * or we ignore it.
704 		 */
705 		if (strncmp(ent->d_name, basename, baselen) != 0)
706 			continue;
707 
708 		name = ent->d_name;
709 		if (name[baselen] != '-')
710 			continue;
711 
712 		p = name + baselen + 1;
713 
714 		for (idx = 0; idx < ndigits; idx++) {
715 			char c = p[idx];
716 			if (idx == baroffset && c != '_')
717 				break;
718 			if (idx != baroffset && (c < '0' || c > '9'))
719 				break;
720 		}
721 		if (idx != ndigits || p[idx] != '\0')
722 			continue;
723 
724 		/*
725 		 * We have a match.  insertion-sort it into our list.
726 		 */
727 		name = strdup(name);
728 		if (name == NULL)
729 			goto fail_closedir;
730 		p = strrchr(name, '-');
731 
732 		for (idx = 0; idx < count; idx++) {
733 			char *tmp = out[idx];
734 			char *tp = strrchr(tmp, '-');
735 
736 			int cmp = strcmp(p, tp);
737 			if (cmp == 0)
738 				cmp = strcmp(name, tmp);
739 
740 			if (cmp == 0) {
741 				free(name);
742 				name = NULL;
743 				break;
744 			} else if (cmp > 0) {
745 				out[idx] = name;
746 				name = tmp;
747 				p = tp;
748 			}
749 		}
750 
751 		if (idx == count) {
752 			char **new_out = realloc(out,
753 			    (count + 1) * sizeof (*out));
754 
755 			if (new_out == NULL) {
756 				free(name);
757 				goto fail_closedir;
758 			}
759 
760 			out = new_out;
761 			out[count++] = name;
762 		} else {
763 			assert(name == NULL);
764 		}
765 	}
766 	(void) closedir(dir);
767 
768 	basename[baselen] = b_end;
769 
770 	*out_arg = (const char **)out;
771 	return (count);
772 
773 fail_closedir:
774 	(void) closedir(dir);
775 fail:
776 	basename[0] = b_start;
777 	*pathend = b_end;
778 
779 	backend_backup_cleanup((const char **)out, count);
780 
781 	*out_arg = NULL;
782 	return (-1);
783 }
784 
785 /*
786  * Copies the repository path into out, a buffer of out_len bytes,
787  * removes the ".db" (or whatever) extension, and, if name is non-NULL,
788  * appends "-name" to it.  If name is non-NULL, it can fail with:
789  *
790  *	_TRUNCATED	will not fit in buffer.
791  *	_BAD_REQUEST	name is not a valid identifier
792  */
793 static rep_protocol_responseid_t
backend_backup_base(sqlite_backend_t * be,const char * name,char * out,size_t out_len)794 backend_backup_base(sqlite_backend_t *be, const char *name,
795     char *out, size_t out_len)
796 {
797 	char *p, *q;
798 	size_t len;
799 
800 	/*
801 	 * for paths of the form /path/to/foo.db, we truncate at the final
802 	 * '.'.
803 	 */
804 	(void) strlcpy(out, IS_VOLATILE(be) ? be->be_ppath : be->be_path,
805 	    out_len);
806 
807 	p = strrchr(out, '/');
808 	q = strrchr(out, '.');
809 
810 	if (p != NULL && q != NULL && q > p)
811 		*q = 0;
812 
813 	if (name != NULL) {
814 		len = strlen(out);
815 		assert(len < out_len);
816 
817 		out += len;
818 		out_len -= len;
819 
820 		len = strlen(name);
821 
822 		/*
823 		 * verify that the name tag is entirely alphabetic,
824 		 * non-empty, and not too long.
825 		 */
826 		if (len == 0 || len >= REP_PROTOCOL_NAME_LEN ||
827 		    uu_check_name(name, UU_NAME_DOMAIN) < 0)
828 			return (REP_PROTOCOL_FAIL_BAD_REQUEST);
829 
830 		if (snprintf(out, out_len, "-%s", name) >= out_len)
831 			return (REP_PROTOCOL_FAIL_TRUNCATED);
832 	}
833 
834 	return (REP_PROTOCOL_SUCCESS);
835 }
836 
837 /*
838  * Make a checkpoint of the repository, so that we can use it for a backup
839  * when the root file system becomes read/write.  We'll first copy the
840  * repository into a temporary file and then rename it to
841  * REPOSITORY_CHECKPOINT.  This is protection against configd crashing in
842  * the middle of the copy and leaving a partial copy at
843  * REPOSITORY_CHECKPOINT.  Renames are atomic.
844  */
845 static rep_protocol_responseid_t
backend_checkpoint_repository(sqlite_backend_t * be)846 backend_checkpoint_repository(sqlite_backend_t *be)
847 {
848 	rep_protocol_responseid_t r;
849 
850 	assert(be->be_readonly);	/* Only need a checkpoint if / is ro */
851 	assert(be->be_type == BACKEND_TYPE_NORMAL);
852 	assert(be->be_checkpoint == NULL); /* Only 1 checkpoint */
853 
854 	r = backend_copy_repository(be->be_path, REPOSITORY_CHECKPOINT, 0);
855 	if (r == REP_PROTOCOL_SUCCESS)
856 		be->be_checkpoint = REPOSITORY_CHECKPOINT;
857 
858 	flight_recorder_event(BE_FLIGHT_EV_CHECKPOINT,
859 	    r == REP_PROTOCOL_SUCCESS ? BE_FLIGHT_ST_SUCCESS :
860 	    BE_FLIGHT_ST_FAIL);
861 
862 	return (r);
863 }
864 
865 /*
866  * See if a backup is needed.  We do a backup unless both files are
867  * byte-for-byte identical.
868  */
869 static int
backend_check_backup_needed(const char * rep_name,const char * backup_name)870 backend_check_backup_needed(const char *rep_name, const char *backup_name)
871 {
872 	int repfd = open(rep_name, O_RDONLY);
873 	int fd = open(backup_name, O_RDONLY);
874 	struct stat s_rep, s_backup;
875 	int c1, c2;
876 
877 	FILE *f_rep = NULL;
878 	FILE *f_backup = NULL;
879 
880 	if (repfd < 0 || fd < 0)
881 		goto fail;
882 
883 	if (fstat(repfd, &s_rep) < 0 || fstat(fd, &s_backup) < 0)
884 		goto fail;
885 
886 	/*
887 	 * if they are the same file, we need to do a backup to break the
888 	 * hard link or symlink involved.
889 	 */
890 	if (s_rep.st_ino == s_backup.st_ino && s_rep.st_dev == s_backup.st_dev)
891 		goto fail;
892 
893 	if (s_rep.st_size != s_backup.st_size)
894 		goto fail;
895 
896 	if ((f_rep = fdopen(repfd, "r")) == NULL ||
897 	    (f_backup = fdopen(fd, "r")) == NULL)
898 		goto fail;
899 
900 	do {
901 		c1 = getc(f_rep);
902 		c2 = getc(f_backup);
903 		if (c1 != c2)
904 			goto fail;
905 	} while (c1 != EOF);
906 
907 	if (!ferror(f_rep) && !ferror(f_backup)) {
908 		(void) fclose(f_rep);
909 		(void) fclose(f_backup);
910 		(void) close(repfd);
911 		(void) close(fd);
912 		return (0);
913 	}
914 
915 fail:
916 	if (f_rep != NULL)
917 		(void) fclose(f_rep);
918 	if (f_backup != NULL)
919 		(void) fclose(f_backup);
920 	if (repfd >= 0)
921 		(void) close(repfd);
922 	if (fd >= 0)
923 		(void) close(fd);
924 	return (1);
925 }
926 
927 /*
928  * This interface is called to perform the actual copy
929  *
930  * Return:
931  *	_FAIL_UNKNOWN		read/write fails
932  *	_FAIL_NO_RESOURCES	out of memory
933  *	_SUCCESS		copy succeeds
934  */
935 static rep_protocol_responseid_t
backend_do_copy(const char * src,int srcfd,const char * dst,int dstfd,size_t * sz)936 backend_do_copy(const char *src, int srcfd, const char *dst,
937     int dstfd, size_t *sz)
938 {
939 	char *buf;
940 	off_t nrd, nwr, n, r_off = 0, w_off = 0;
941 
942 	if ((buf = malloc(8192)) == NULL)
943 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
944 
945 	while ((nrd = read(srcfd, buf, 8192)) != 0) {
946 		if (nrd < 0) {
947 			if (errno == EINTR)
948 				continue;
949 
950 			configd_critical(
951 			    "Backend copy failed: fails to read from %s "
952 			    "at offset %d: %s\n", src, r_off, strerror(errno));
953 			free(buf);
954 			return (REP_PROTOCOL_FAIL_UNKNOWN);
955 		}
956 
957 		r_off += nrd;
958 
959 		nwr = 0;
960 		do {
961 			if ((n = write(dstfd, &buf[nwr], nrd - nwr)) < 0) {
962 				if (errno == EINTR)
963 					continue;
964 
965 				configd_critical(
966 				    "Backend copy failed: fails to write to %s "
967 				    "at offset %d: %s\n", dst, w_off,
968 				    strerror(errno));
969 				free(buf);
970 				return (REP_PROTOCOL_FAIL_UNKNOWN);
971 			}
972 
973 			nwr += n;
974 			w_off += n;
975 
976 		} while (nwr < nrd);
977 	}
978 
979 	if (sz)
980 		*sz = w_off;
981 
982 	free(buf);
983 	return (REP_PROTOCOL_SUCCESS);
984 }
985 
986 /*
987  * Can return:
988  *	_BAD_REQUEST		name is not valid
989  *	_TRUNCATED		name is too long for current repository path
990  *	_UNKNOWN		failed for unknown reason (details written to
991  *				console)
992  *	_BACKEND_READONLY	backend is not writable
993  *	_NO_RESOURCES		out of memory
994  *	_SUCCESS		Backup completed successfully.
995  */
996 static rep_protocol_responseid_t
backend_create_backup_locked(sqlite_backend_t * be,const char * name)997 backend_create_backup_locked(sqlite_backend_t *be, const char *name)
998 {
999 	const char **old_list;
1000 	ssize_t old_sz;
1001 	ssize_t old_max = max_repository_backups;
1002 	ssize_t cur;
1003 	char *finalname;
1004 	char *finalpath;
1005 	char *tmppath;
1006 	int infd, outfd;
1007 	size_t len;
1008 	time_t now;
1009 	struct tm now_tm;
1010 	be_flight_status_t backup_type;
1011 	rep_protocol_responseid_t result;
1012 	const char *src;
1013 	int use_checkpoint;
1014 
1015 	if (strcmp(name, REPOSITORY_BOOT_BACKUP) == 0) {
1016 		backup_type = BE_FLIGHT_ST_BOOT_BACKUP;
1017 	} else if (strcmp(name, "manifest_import") ==  0) {
1018 		backup_type = BE_FLIGHT_ST_MI_BACKUP;
1019 	} else {
1020 		backup_type = BE_FLIGHT_ST_OTHER_BACKUP;
1021 	}
1022 	flight_recorder_event(BE_FLIGHT_EV_BACKUP_ENTER, backup_type);
1023 
1024 	if ((finalpath = malloc(PATH_MAX)) == NULL)
1025 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1026 
1027 	if ((tmppath = malloc(PATH_MAX)) == NULL) {
1028 		free(finalpath);
1029 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1030 	}
1031 
1032 	if (be->be_readonly) {
1033 		flight_recorder_event(BE_FLIGHT_EV_NO_BACKUP, BE_FLIGHT_ST_RO);
1034 		result = REP_PROTOCOL_FAIL_BACKEND_READONLY;
1035 		goto out;
1036 	}
1037 
1038 	result = backend_backup_base(be, name, finalpath, PATH_MAX);
1039 	if (result != REP_PROTOCOL_SUCCESS)
1040 		goto out;
1041 
1042 	/*
1043 	 * If this is a boot backup and if we made a checkpoint before the
1044 	 * root file system became read/write, then we should use the
1045 	 * checkpoint as the source.  Otherwise, we'll use the actual
1046 	 * repository as the source.
1047 	 */
1048 	if (be->be_checkpoint && name &&
1049 	    strcmp(REPOSITORY_BOOT_BACKUP, name) == 0) {
1050 		backup_type = BE_FLIGHT_ST_CHECKPOINT_BACKUP;
1051 		use_checkpoint = 1;
1052 		src = be->be_checkpoint;
1053 	} else {
1054 		backup_type = BE_FLIGHT_ST_REPO_BACKUP;
1055 		use_checkpoint = 0;
1056 		src = be->be_path;
1057 	}
1058 	flight_recorder_event(BE_FLIGHT_EV_BACKUP, backup_type);
1059 	if (!backend_check_backup_needed(src, finalpath)) {
1060 		/*
1061 		 * No changes, so there is no need for a backup.
1062 		 */
1063 		flight_recorder_event(BE_FLIGHT_EV_NO_BACKUP,
1064 		    BE_FLIGHT_ST_DUPLICATE);
1065 		result = REP_PROTOCOL_SUCCESS;
1066 		goto out;
1067 	}
1068 
1069 	/*
1070 	 * remember the original length, and the basename location
1071 	 */
1072 	len = strlen(finalpath);
1073 	finalname = strrchr(finalpath, '/');
1074 	if (finalname != NULL)
1075 		finalname++;
1076 	else
1077 		finalname = finalpath;
1078 
1079 	(void) strlcpy(tmppath, finalpath, PATH_MAX);
1080 	if (strlcat(tmppath, "-tmpXXXXXX", PATH_MAX) >= PATH_MAX) {
1081 		result = REP_PROTOCOL_FAIL_TRUNCATED;
1082 		goto out;
1083 	}
1084 
1085 	now = time(NULL);
1086 	if (localtime_r(&now, &now_tm) == NULL) {
1087 		configd_critical(
1088 		    "\"%s\" backup failed: localtime(3C) failed: %s\n", name,
1089 		    strerror(errno));
1090 		result = REP_PROTOCOL_FAIL_UNKNOWN;
1091 		goto out;
1092 	}
1093 
1094 	if (strftime(finalpath + len, PATH_MAX - len,
1095 	    "-%Y""%m""%d""_""%H""%M""%S", &now_tm) >= PATH_MAX - len) {
1096 		result = REP_PROTOCOL_FAIL_TRUNCATED;
1097 		goto out;
1098 	}
1099 
1100 	infd = open(src, O_RDONLY);
1101 	if (infd < 0) {
1102 		configd_critical("\"%s\" backup failed: opening %s: %s\n", name,
1103 		    src, strerror(errno));
1104 		result = REP_PROTOCOL_FAIL_UNKNOWN;
1105 		goto out;
1106 	}
1107 
1108 	outfd = mkstemp(tmppath);
1109 	if (outfd < 0) {
1110 		configd_critical("\"%s\" backup failed: mkstemp(%s): %s\n",
1111 		    name, tmppath, strerror(errno));
1112 		(void) close(infd);
1113 		result = REP_PROTOCOL_FAIL_UNKNOWN;
1114 		goto out;
1115 	}
1116 
1117 	if ((result = backend_do_copy(src, infd, (const char *)tmppath,
1118 	    outfd, NULL)) != REP_PROTOCOL_SUCCESS)
1119 		goto fail;
1120 
1121 	/*
1122 	 * grab the old list before doing our re-name.
1123 	 */
1124 	if (old_max > 0)
1125 		old_sz = backend_backup_get_prev(finalpath, len, &old_list);
1126 
1127 	if (rename(tmppath, finalpath) < 0) {
1128 		configd_critical(
1129 		    "\"%s\" backup failed: rename(%s, %s): %s\n",
1130 		    name, tmppath, finalpath, strerror(errno));
1131 		result = REP_PROTOCOL_FAIL_UNKNOWN;
1132 		goto fail;
1133 	}
1134 
1135 	tmppath[len] = 0;	/* strip -XXXXXX, for reference symlink */
1136 
1137 	(void) unlink(tmppath);
1138 	if (symlink(finalname, tmppath) < 0) {
1139 		configd_critical(
1140 		    "\"%s\" backup completed, but updating "
1141 		    "\"%s\" symlink to \"%s\" failed: %s\n",
1142 		    name, tmppath, finalname, strerror(errno));
1143 	}
1144 
1145 	if (old_max > 0 && old_sz > 0) {
1146 		/* unlink all but the first (old_max - 1) files */
1147 		for (cur = old_max - 1; cur < old_sz; cur++) {
1148 			(void) strlcpy(finalname, old_list[cur],
1149 			    PATH_MAX - (finalname - finalpath));
1150 			if (unlink(finalpath) < 0)
1151 				configd_critical(
1152 				    "\"%s\" backup completed, but removing old "
1153 				    "file \"%s\" failed: %s\n",
1154 				    name, finalpath, strerror(errno));
1155 		}
1156 
1157 		backend_backup_cleanup(old_list, old_sz);
1158 	}
1159 
1160 	result = REP_PROTOCOL_SUCCESS;
1161 	flight_recorder_event(BE_FLIGHT_EV_BACKUP, BE_FLIGHT_ST_SUCCESS);
1162 
1163 fail:
1164 	(void) close(infd);
1165 	(void) close(outfd);
1166 	if (result != REP_PROTOCOL_SUCCESS) {
1167 		flight_recorder_event(BE_FLIGHT_EV_BACKUP, BE_FLIGHT_ST_FAIL);
1168 		(void) unlink(tmppath);
1169 	}
1170 
1171 out:
1172 	/* Get rid of the checkpoint file now that we've used it. */
1173 	if (use_checkpoint && (result == REP_PROTOCOL_SUCCESS)) {
1174 		(void) unlink(be->be_checkpoint);
1175 		be->be_checkpoint = NULL;
1176 	}
1177 	free(finalpath);
1178 	free(tmppath);
1179 
1180 	return (result);
1181 }
1182 
1183 /*
1184  * Check if value_tbl has been upgraded in the main database,  and
1185  * if not (if the value_order column is not present),  and do_upgrade is true,
1186  * upgrade value_tbl in repository to contain the additional value_order
1187  * column. The version of sqlite used means ALTER TABLE is not
1188  * available, so we cannot simply use "ALTER TABLE value_tbl ADD COLUMN".
1189  * Rather we need to create a temporary table with the additional column,
1190  * import the value_tbl, drop the original value_tbl, recreate the value_tbl
1191  * with the additional column, import the values from value_tbl_tmp,
1192  * reindex and finally drop value_tbl_tmp.  During boot, we wish to check
1193  * if the repository has been upgraded before it is writable,  so that
1194  * property value retrieval can use the appropriate form of the SELECT
1195  * statement that retrieves property values.  As a result, we need to check
1196  * if the repository has been upgraded prior to the point when we can
1197  * actually carry out the update.
1198  */
1199 void
backend_check_upgrade(sqlite_backend_t * be,boolean_t do_upgrade)1200 backend_check_upgrade(sqlite_backend_t *be, boolean_t do_upgrade)
1201 {
1202 	char *errp;
1203 	int r;
1204 
1205 	if (be_normal_upgraded)
1206 		return;
1207 	/*
1208 	 * Test if upgrade is needed. If value_order column does not exist,
1209 	 * we need to upgrade the schema.
1210 	 */
1211 	r = sqlite_exec(be->be_db, "SELECT value_order FROM value_tbl LIMIT 1;",
1212 	    NULL, NULL, NULL);
1213 	if (r == SQLITE_ERROR && do_upgrade) {
1214 		/* No value_order column - needs upgrade */
1215 		configd_info("Upgrading SMF repository format...");
1216 		r = sqlite_exec(be->be_db,
1217 		    "BEGIN TRANSACTION; "
1218 		    "CREATE TABLE value_tbl_tmp ( "
1219 		    "value_id   INTEGER NOT NULL, "
1220 		    "value_type CHAR(1) NOT NULL, "
1221 		    "value_value VARCHAR NOT NULL, "
1222 		    "value_order INTEGER DEFAULT 0); "
1223 		    "INSERT INTO value_tbl_tmp "
1224 		    "(value_id, value_type, value_value) "
1225 		    "SELECT value_id, value_type, value_value FROM value_tbl; "
1226 		    "DROP TABLE value_tbl; "
1227 		    "CREATE TABLE value_tbl( "
1228 		    "value_id   INTEGER NOT NULL, "
1229 		    "value_type CHAR(1) NOT NULL, "
1230 		    "value_value VARCHAR NOT NULL, "
1231 		    "value_order INTEGER DEFAULT 0); "
1232 		    "INSERT INTO value_tbl SELECT * FROM value_tbl_tmp; "
1233 		    "CREATE INDEX value_tbl_id ON value_tbl (value_id); "
1234 		    "DROP TABLE value_tbl_tmp; "
1235 		    "COMMIT TRANSACTION; "
1236 		    "VACUUM; ",
1237 		    NULL, NULL, &errp);
1238 		if (r == SQLITE_OK) {
1239 			configd_info("SMF repository upgrade is complete.");
1240 		} else {
1241 			backend_panic("%s: repository upgrade failed: %s",
1242 			    be->be_path, errp);
1243 			/* NOTREACHED */
1244 		}
1245 	}
1246 	if (r == SQLITE_OK)
1247 		be_normal_upgraded = B_TRUE;
1248 	else
1249 		be_normal_upgraded = B_FALSE;
1250 }
1251 
1252 static int
backend_check_readonly(sqlite_backend_t * be,int writing,hrtime_t t)1253 backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t)
1254 {
1255 	const char *check_path;
1256 	char *errp;
1257 	struct sqlite *new;
1258 	int r;
1259 
1260 	assert(be->be_readonly);
1261 	assert(be == bes[BACKEND_TYPE_NORMAL]);
1262 
1263 	/*
1264 	 * If we don't *need* to be writable, only check every once in a
1265 	 * while.
1266 	 */
1267 	if (!writing) {
1268 		if ((uint64_t)(t - be->be_lastcheck) <
1269 		    BACKEND_READONLY_CHECK_INTERVAL)
1270 			return (REP_PROTOCOL_SUCCESS);
1271 		be->be_lastcheck = t;
1272 	}
1273 
1274 	/*
1275 	 * It could be that the repository has been moved to non-persistent
1276 	 * storage for performance reasons.  In this case we need to check
1277 	 * the persistent path to see if it is writable.  The
1278 	 * non-persistent path will always be writable.
1279 	 */
1280 	check_path = IS_VOLATILE(be) ? be->be_ppath : be->be_path;
1281 
1282 	new = sqlite_open(check_path, 0600, &errp);
1283 	if (new == NULL) {
1284 		backend_panic("reopening %s: %s\n", check_path, errp);
1285 		/*NOTREACHED*/
1286 	}
1287 	r = backend_is_readonly(new, check_path);
1288 
1289 	if (r != SQLITE_OK) {
1290 		/*
1291 		 * The underlying storage for the permanent repository is
1292 		 * still read-only, so we don't want to change the state or
1293 		 * move the checkpointed backup if it exists.  On the other
1294 		 * hand if the repository has been copied to volatile
1295 		 * storage, we'll let our caller go ahead and write to the
1296 		 * database.
1297 		 */
1298 		sqlite_close(new);
1299 		if (writing && (IS_VOLATILE(be) == 0))
1300 			return (REP_PROTOCOL_FAIL_BACKEND_READONLY);
1301 		return (REP_PROTOCOL_SUCCESS);
1302 	}
1303 
1304 	/*
1305 	 * We can write!  If the repository is not on volatile storage,
1306 	 * swap the db handles.  Mark ourself as writable, upgrade the
1307 	 * repository if necessary and make a backup.
1308 	 */
1309 	be->be_readonly = 0;
1310 	flight_recorder_event(BE_FLIGHT_EV_TRANS_RW, BE_FLIGHT_ST_RW);
1311 	if (IS_VOLATILE(be)) {
1312 		/*
1313 		 * If the repository is on volatile storage, don't switch
1314 		 * the handles.  We'll continue to use the repository that
1315 		 * is on tmpfs until we're told to move it back by one of
1316 		 * our clients.  Clients, specifically manifest_import,
1317 		 * move the repository to tmpfs for performance reasons,
1318 		 * and that is the reason to not switch it back until we're
1319 		 * told to do so.
1320 		 */
1321 		flight_recorder_event(BE_FLIGHT_EV_TRANS_RW,
1322 		    BE_FLIGHT_ST_NO_SWITCH);
1323 		sqlite_close(new);
1324 	} else {
1325 		flight_recorder_event(BE_FLIGHT_EV_TRANS_RW,
1326 		    BE_FLIGHT_ST_SWITCH);
1327 		sqlite_close(be->be_db);
1328 		be->be_db = new;
1329 	}
1330 
1331 	if (be->be_type == BACKEND_TYPE_NORMAL)
1332 		backend_check_upgrade(be, B_TRUE);
1333 
1334 	if (backend_create_backup_locked(be, REPOSITORY_BOOT_BACKUP) !=
1335 	    REP_PROTOCOL_SUCCESS) {
1336 		configd_critical(
1337 		    "unable to create \"%s\" backup of \"%s\"\n",
1338 		    REPOSITORY_BOOT_BACKUP, be->be_path);
1339 	}
1340 
1341 	return (REP_PROTOCOL_SUCCESS);
1342 }
1343 
1344 /*
1345  * If t is not BACKEND_TYPE_NORMAL, can fail with
1346  *   _BACKEND_ACCESS - backend does not exist
1347  *
1348  * If writing is nonzero, can also fail with
1349  *   _BACKEND_READONLY - backend is read-only
1350  */
1351 static int
backend_lock(backend_type_t t,int writing,sqlite_backend_t ** bep)1352 backend_lock(backend_type_t t, int writing, sqlite_backend_t **bep)
1353 {
1354 	sqlite_backend_t *be = NULL;
1355 	hrtime_t ts, vts;
1356 
1357 	*bep = NULL;
1358 
1359 	assert(t == BACKEND_TYPE_NORMAL ||
1360 	    t == BACKEND_TYPE_NONPERSIST);
1361 
1362 	be = bes[t];
1363 	if (t == BACKEND_TYPE_NORMAL)
1364 		assert(be != NULL);		/* should always be there */
1365 
1366 	if (be == NULL)
1367 		return (REP_PROTOCOL_FAIL_BACKEND_ACCESS);
1368 
1369 	if (backend_panic_thread != 0)
1370 		backend_panic(NULL);		/* don't proceed */
1371 
1372 	ts = gethrtime();
1373 	vts = gethrvtime();
1374 	(void) pthread_mutex_lock(&be->be_lock);
1375 	UPDATE_TOTALS_WR(be, writing, bt_lock, ts, vts);
1376 
1377 	if (backend_panic_thread != 0) {
1378 		(void) pthread_mutex_unlock(&be->be_lock);
1379 		backend_panic(NULL);		/* don't proceed */
1380 	}
1381 	be->be_thread = pthread_self();
1382 
1383 	if (be->be_readonly) {
1384 		int r;
1385 		assert(t == BACKEND_TYPE_NORMAL);
1386 
1387 		r = backend_check_readonly(be, writing, ts);
1388 		if (r != REP_PROTOCOL_SUCCESS) {
1389 			be->be_thread = 0;
1390 			(void) pthread_mutex_unlock(&be->be_lock);
1391 			return (r);
1392 		}
1393 	}
1394 
1395 	if (backend_do_trace)
1396 		(void) sqlite_trace(be->be_db, backend_trace_sql, be);
1397 	else
1398 		(void) sqlite_trace(be->be_db, NULL, NULL);
1399 
1400 	be->be_writing = writing;
1401 	*bep = be;
1402 	return (REP_PROTOCOL_SUCCESS);
1403 }
1404 
1405 static void
backend_unlock(sqlite_backend_t * be)1406 backend_unlock(sqlite_backend_t *be)
1407 {
1408 	be->be_writing = 0;
1409 	be->be_thread = 0;
1410 	(void) pthread_mutex_unlock(&be->be_lock);
1411 }
1412 
1413 static void
backend_destroy(sqlite_backend_t * be)1414 backend_destroy(sqlite_backend_t *be)
1415 {
1416 	if (be->be_db != NULL) {
1417 		sqlite_close(be->be_db);
1418 		be->be_db = NULL;
1419 	}
1420 	be->be_thread = 0;
1421 	(void) pthread_mutex_unlock(&be->be_lock);
1422 	(void) pthread_mutex_destroy(&be->be_lock);
1423 }
1424 
1425 static void
backend_create_finish(backend_type_t backend_id,sqlite_backend_t * be)1426 backend_create_finish(backend_type_t backend_id, sqlite_backend_t *be)
1427 {
1428 	assert(MUTEX_HELD(&be->be_lock));
1429 	assert(be == &be_info[backend_id]);
1430 
1431 	bes[backend_id] = be;
1432 	(void) pthread_mutex_unlock(&be->be_lock);
1433 }
1434 
1435 static int
backend_fd_write(int fd,const char * mess)1436 backend_fd_write(int fd, const char *mess)
1437 {
1438 	int len = strlen(mess);
1439 	int written;
1440 
1441 	while (len > 0) {
1442 		if ((written = write(fd, mess, len)) < 0)
1443 			return (-1);
1444 		mess += written;
1445 		len -= written;
1446 	}
1447 	return (0);
1448 }
1449 
1450 /*
1451  * Can return:
1452  *	_BAD_REQUEST		name is not valid
1453  *	_TRUNCATED		name is too long for current repository path
1454  *	_UNKNOWN		failed for unknown reason (details written to
1455  *				console)
1456  *	_BACKEND_READONLY	backend is not writable
1457  *	_NO_RESOURCES		out of memory
1458  *	_SUCCESS		Backup completed successfully.
1459  */
1460 rep_protocol_responseid_t
backend_create_backup(const char * name)1461 backend_create_backup(const char *name)
1462 {
1463 	rep_protocol_responseid_t result;
1464 	sqlite_backend_t *be;
1465 
1466 	flight_recorder_event(BE_FLIGHT_EV_BACKUP, BE_FLIGHT_ST_CLIENT);
1467 	result = backend_lock(BACKEND_TYPE_NORMAL, 0, &be);
1468 	assert(result == REP_PROTOCOL_SUCCESS);
1469 
1470 	result = backend_create_backup_locked(be, name);
1471 	backend_unlock(be);
1472 
1473 	return (result);
1474 }
1475 
1476 /*
1477  * This function makes a copy of the repository at src, placing the copy at
1478  * dst.  It is used to copy a repository on permanent storage to volatile
1479  * storage or vice versa.  If the source file is on volatile storage, it is
1480  * often times desirable to delete it after the copy has been made and
1481  * verified.  To remove the source repository, set remove_src to 1.
1482  *
1483  * Can return:
1484  *
1485  *	REP_PROTOCOL_SUCCESS		successful copy and rename
1486  *	REP_PROTOCOL_FAIL_UNKNOWN	file operation error
1487  *	REP_PROTOCOL_FAIL_NO_RESOURCES	out of memory
1488  */
1489 static rep_protocol_responseid_t
backend_copy_repository(const char * src,const char * dst,int remove_src)1490 backend_copy_repository(const char *src, const char *dst, int remove_src)
1491 {
1492 	int srcfd, dstfd;
1493 	char *tmppath = malloc(PATH_MAX);
1494 	rep_protocol_responseid_t res = REP_PROTOCOL_SUCCESS;
1495 	struct stat s_buf;
1496 	size_t cpsz, sz;
1497 
1498 	if (tmppath == NULL) {
1499 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
1500 		goto out;
1501 	}
1502 
1503 	/*
1504 	 * Create and open the related db files
1505 	 */
1506 	(void) strlcpy(tmppath, dst, PATH_MAX);
1507 	sz = strlcat(tmppath, "-XXXXXX", PATH_MAX);
1508 	assert(sz < PATH_MAX);
1509 	if (sz >= PATH_MAX) {
1510 		configd_critical(
1511 		    "Backend copy failed: strlcat %s: overflow\n", tmppath);
1512 		abort();
1513 	}
1514 
1515 	if ((dstfd = mkstemp(tmppath)) < 0) {
1516 		configd_critical("Backend copy failed: mkstemp %s: %s\n",
1517 		    tmppath, strerror(errno));
1518 		res = REP_PROTOCOL_FAIL_UNKNOWN;
1519 		goto out;
1520 	}
1521 
1522 	if ((srcfd = open(src, O_RDONLY)) < 0) {
1523 		configd_critical("Backend copy failed: opening %s: %s\n",
1524 		    src, strerror(errno));
1525 		res = REP_PROTOCOL_FAIL_UNKNOWN;
1526 		goto errexit;
1527 	}
1528 
1529 	/*
1530 	 * fstat the backend before copy for sanity check.
1531 	 */
1532 	if (fstat(srcfd, &s_buf) < 0) {
1533 		configd_critical("Backend copy failed: fstat %s: %s\n",
1534 		    src, strerror(errno));
1535 		res = REP_PROTOCOL_FAIL_UNKNOWN;
1536 		goto errexit;
1537 	}
1538 
1539 	if ((res = backend_do_copy(src, srcfd, dst, dstfd, &cpsz)) !=
1540 	    REP_PROTOCOL_SUCCESS)
1541 		goto errexit;
1542 
1543 	if (cpsz != s_buf.st_size) {
1544 		configd_critical("Backend copy failed: incomplete copy\n");
1545 		res = REP_PROTOCOL_FAIL_UNKNOWN;
1546 		goto errexit;
1547 	}
1548 
1549 	/*
1550 	 * Rename tmppath to dst
1551 	 */
1552 	if (rename(tmppath, dst) < 0) {
1553 		configd_critical(
1554 		    "Backend copy failed: rename %s to %s: %s\n",
1555 		    tmppath, dst, strerror(errno));
1556 		res = REP_PROTOCOL_FAIL_UNKNOWN;
1557 	}
1558 
1559 errexit:
1560 	if (res != REP_PROTOCOL_SUCCESS && unlink(tmppath) < 0)
1561 		configd_critical(
1562 		    "Backend copy failed: remove %s: %s\n",
1563 		    tmppath, strerror(errno));
1564 
1565 	(void) close(srcfd);
1566 	(void) close(dstfd);
1567 
1568 out:
1569 	free(tmppath);
1570 	if (remove_src) {
1571 		if (unlink(src) < 0)
1572 			configd_critical(
1573 			    "Backend copy failed: remove %s: %s\n",
1574 			    src, strerror(errno));
1575 	}
1576 
1577 	return (res);
1578 }
1579 
1580 /*
1581  * Perform sanity check on the repository.
1582  * Return 0 if check succeeds or -1 if fails.
1583  */
1584 static int
backend_switch_check(struct sqlite * be_db,char ** errp)1585 backend_switch_check(struct sqlite *be_db, char **errp)
1586 {
1587 	struct run_single_int_info info;
1588 	uint32_t val = -1UL;
1589 	int r;
1590 
1591 	info.rs_out = &val;
1592 	info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND;
1593 
1594 	r = sqlite_exec(be_db,
1595 	    "SELECT schema_version FROM schema_version;",
1596 	    run_single_int_callback, &info, errp);
1597 
1598 	if (r == SQLITE_OK &&
1599 	    info.rs_result != REP_PROTOCOL_FAIL_NOT_FOUND &&
1600 	    val == BACKEND_SCHEMA_VERSION)
1601 		return (0);
1602 	else
1603 		return (-1);
1604 }
1605 
1606 /*
1607  * backend_switch() implements the REP_PROTOCOL_SWITCH request from
1608  * clients.  First, it blocks all other clients from accessing the
1609  * repository by calling backend_lock to lock the repository.  It either
1610  * copies the repository from it's permanent storage location
1611  * (REPOSITORY_DB) to its fast volatile location (FAST_REPOSITORY_DB), or
1612  * vice versa.  dir determines the direction of the copy.
1613  *
1614  *	dir = 0	Copy from permanent location to volatile location.
1615  *	dir = 1	Copy from volatile location to permanent location.
1616  *
1617  * Can return:
1618  *	REP_PROTOCOL_SUCCESS			successful switch
1619  *	REP_PROTOCOL_FAIL_BACKEND_ACCESS	backen access fails
1620  *	REP_PROTOCOL_FAIL_BACKEND_READONLY	backend is not writable
1621  *	REP_PROTOCOL_FAIL_UNKNOWN		file operation error
1622  *	REP_PROTOCOL_FAIL_NO_RESOURCES		out of memory
1623  */
1624 rep_protocol_responseid_t
backend_switch(int dir)1625 backend_switch(int dir)
1626 {
1627 	rep_protocol_responseid_t result;
1628 	sqlite_backend_t *be;
1629 	struct sqlite *new;
1630 	char *errp;
1631 	const char *dst;
1632 
1633 	flight_recorder_event(BE_FLIGHT_EV_SWITCH, BE_FLIGHT_ST_CLIENT);
1634 
1635 	/*
1636 	 * If switching back to the main repository, lock for writing.
1637 	 * Otherwise, lock for reading.
1638 	 */
1639 	result = backend_lock(BACKEND_TYPE_NORMAL, dir ? 1 : 0,
1640 	    &be);
1641 	if (result != REP_PROTOCOL_SUCCESS)
1642 		return (result);
1643 
1644 	if (dir) {
1645 		flight_recorder_event(BE_FLIGHT_EV_SWITCH,
1646 		    BE_FLIGHT_ST_PERMANENT);
1647 		dst = REPOSITORY_DB;
1648 	} else {
1649 		flight_recorder_event(BE_FLIGHT_EV_SWITCH,
1650 		    BE_FLIGHT_ST_FAST);
1651 		dst = FAST_REPOSITORY_DB;
1652 	}
1653 
1654 	/*
1655 	 * Do the actual copy and rename
1656 	 */
1657 	if (strcmp(be->be_path, dst) == 0) {
1658 		flight_recorder_event(BE_FLIGHT_EV_SWITCH,
1659 		    BE_FLIGHT_ST_DUPLICATE);
1660 		result = REP_PROTOCOL_SUCCESS;
1661 		goto errout;
1662 	}
1663 
1664 	result = backend_copy_repository(be->be_path, dst, dir);
1665 	if (result != REP_PROTOCOL_SUCCESS) {
1666 		goto errout;
1667 	}
1668 
1669 	/*
1670 	 * Do the backend sanity check and switch
1671 	 */
1672 	new = sqlite_open(dst, 0600, &errp);
1673 	if (new != NULL) {
1674 		/*
1675 		 * Sanity check
1676 		 */
1677 		if (backend_switch_check(new, &errp) == 0) {
1678 			free((char *)be->be_path);
1679 			be->be_path = strdup(dst);
1680 			if (be->be_path == NULL) {
1681 				configd_critical(
1682 				    "Backend switch failed: strdup %s: %s\n",
1683 				    dst, strerror(errno));
1684 				result = REP_PROTOCOL_FAIL_NO_RESOURCES;
1685 				sqlite_close(new);
1686 			} else {
1687 				sqlite_close(be->be_db);
1688 				be->be_db = new;
1689 				if (dir) {
1690 					/* We're back on permanent storage. */
1691 					be->be_ppath = NULL;
1692 				} else {
1693 					/*
1694 					 * Repository is now on volatile
1695 					 * storage.  Save the location of
1696 					 * the persistent repository.
1697 					 */
1698 					be->be_ppath = REPOSITORY_DB;
1699 				}
1700 			}
1701 		} else {
1702 			configd_critical(
1703 			    "Backend switch failed: integrity check %s: %s\n",
1704 			    dst, errp);
1705 			result = REP_PROTOCOL_FAIL_BACKEND_ACCESS;
1706 		}
1707 	} else {
1708 		configd_critical("Backend switch failed: sqlite_open %s: %s\n",
1709 		    dst, errp);
1710 		result = REP_PROTOCOL_FAIL_BACKEND_ACCESS;
1711 	}
1712 
1713 errout:
1714 	if (result == REP_PROTOCOL_SUCCESS) {
1715 		flight_recorder_event(BE_FLIGHT_EV_SWITCH,
1716 		    BE_FLIGHT_ST_SUCCESS);
1717 	} else {
1718 		flight_recorder_event(BE_FLIGHT_EV_SWITCH, BE_FLIGHT_ST_FAIL);
1719 	}
1720 	backend_unlock(be);
1721 	return (result);
1722 }
1723 
1724 /*
1725  * This routine is called to attempt the recovery of
1726  * the most recent valid repository if possible when configd
1727  * is restarted for some reasons or when system crashes
1728  * during the switch operation.  The repository databases
1729  * referenced here are indicators of successful switch
1730  * operations.
1731  */
1732 static backend_switch_results_t
backend_switch_recovery(void)1733 backend_switch_recovery(void)
1734 {
1735 	const char *fast_db = FAST_REPOSITORY_DB;
1736 	char *errp = NULL;
1737 	struct stat s_buf;
1738 	struct sqlite *be_db;
1739 	int r;
1740 	backend_switch_results_t res = BACKEND_SWITCH_OK;
1741 
1742 	/*
1743 	 * A good transient db containing most recent data can
1744 	 * exist if svc.configd crashes during the
1745 	 * switch operation.  If that is the case, check its
1746 	 * integrity and use it.
1747 	 */
1748 	if (stat(fast_db, &s_buf) < 0) {
1749 		return (BACKEND_SWITCH_OK);
1750 	}
1751 
1752 	/* Determine if persistent repository is read-only */
1753 	be_db = sqlite_open(REPOSITORY_DB, 0600, &errp);
1754 	if (be_db == NULL) {
1755 		configd_critical("Unable to open \"%s\".  %s\n",
1756 		    REPOSITORY_DB, errp == NULL ? "" : errp);
1757 		free(errp);
1758 		return (BACKEND_SWITCH_FATAL);
1759 	}
1760 	r = backend_is_readonly(be_db, REPOSITORY_DB);
1761 	sqlite_close(be_db);
1762 	if (r != SQLITE_OK) {
1763 		if (r == SQLITE_READONLY) {
1764 			return (BACKEND_SWITCH_RO);
1765 		}
1766 		return (BACKEND_SWITCH_FATAL);
1767 	}
1768 
1769 	/*
1770 	 * Do sanity check on the db
1771 	 */
1772 	be_db = sqlite_open(fast_db, 0600, &errp);
1773 
1774 	if (be_db != NULL) {
1775 		if (backend_switch_check(be_db, &errp) == 0) {
1776 			if (backend_copy_repository(fast_db,
1777 			    REPOSITORY_DB, 1) != REP_PROTOCOL_SUCCESS) {
1778 				res = BACKEND_SWITCH_FATAL;
1779 			}
1780 		}
1781 		sqlite_close(be_db);
1782 	}
1783 	free(errp);
1784 
1785 	/*
1786 	 * If we get to this point, the fast_db has either been copied or
1787 	 * it is useless.  Either way, get rid of it.
1788 	 */
1789 	(void) unlink(fast_db);
1790 
1791 	return (res);
1792 }
1793 
1794 /*ARGSUSED*/
1795 static int
backend_integrity_callback(void * private,int narg,char ** vals,char ** cols)1796 backend_integrity_callback(void *private, int narg, char **vals, char **cols)
1797 {
1798 	char **out = private;
1799 	char *old = *out;
1800 	char *new;
1801 	const char *info;
1802 	size_t len;
1803 	int x;
1804 
1805 	for (x = 0; x < narg; x++) {
1806 		if ((info = vals[x]) != NULL &&
1807 		    strcmp(info, "ok") != 0) {
1808 			len = (old == NULL)? 0 : strlen(old);
1809 			len += strlen(info) + 2;	/* '\n' + '\0' */
1810 
1811 			new = realloc(old, len);
1812 			if (new == NULL)
1813 				return (BACKEND_CALLBACK_ABORT);
1814 			if (old == NULL)
1815 				new[0] = 0;
1816 			old = *out = new;
1817 			(void) strlcat(new, info, len);
1818 			(void) strlcat(new, "\n", len);
1819 		}
1820 	}
1821 	return (BACKEND_CALLBACK_CONTINUE);
1822 }
1823 
1824 #define	BACKEND_CREATE_LOCKED		-2
1825 #define	BACKEND_CREATE_FAIL		-1
1826 #define	BACKEND_CREATE_SUCCESS		0
1827 #define	BACKEND_CREATE_READONLY		1
1828 #define	BACKEND_CREATE_NEED_INIT	2
1829 static int
backend_create(backend_type_t backend_id,const char * db_file,sqlite_backend_t ** bep)1830 backend_create(backend_type_t backend_id, const char *db_file,
1831     sqlite_backend_t **bep)
1832 {
1833 	char *errp;
1834 	char *integrity_results = NULL;
1835 	sqlite_backend_t *be;
1836 	int r;
1837 	uint32_t val = -1UL;
1838 	struct run_single_int_info info;
1839 	int fd;
1840 
1841 	assert(backend_id >= 0 && backend_id < BACKEND_TYPE_TOTAL);
1842 
1843 	be = &be_info[backend_id];
1844 
1845 	assert(be->be_db == NULL);
1846 
1847 	(void) pthread_mutex_init(&be->be_lock, NULL);
1848 	(void) pthread_mutex_lock(&be->be_lock);
1849 
1850 	be->be_type = backend_id;
1851 	be->be_path = strdup(db_file);
1852 	if (be->be_path == NULL) {
1853 		perror("malloc");
1854 		goto fail;
1855 	}
1856 
1857 	be->be_db = sqlite_open(be->be_path, 0600, &errp);
1858 
1859 	if (be->be_db == NULL) {
1860 		if (strstr(errp, "out of memory") != NULL) {
1861 			configd_critical("%s: %s\n", db_file, errp);
1862 			free(errp);
1863 
1864 			goto fail;
1865 		}
1866 
1867 		/* report it as an integrity failure */
1868 		integrity_results = errp;
1869 		errp = NULL;
1870 		goto integrity_fail;
1871 	}
1872 
1873 	/*
1874 	 * check if we are inited and of the correct schema version
1875 	 *
1876 	 */
1877 	info.rs_out = &val;
1878 	info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND;
1879 
1880 	r = sqlite_exec(be->be_db, "SELECT schema_version FROM schema_version;",
1881 	    run_single_int_callback, &info, &errp);
1882 	if (r == SQLITE_ERROR &&
1883 	    strcmp("no such table: schema_version", errp) == 0) {
1884 		free(errp);
1885 		/*
1886 		 * Could be an empty repository, could be pre-schema_version
1887 		 * schema.  Check for id_tbl, which has always been there.
1888 		 */
1889 		r = sqlite_exec(be->be_db, "SELECT count() FROM id_tbl;",
1890 		    NULL, NULL, &errp);
1891 		if (r == SQLITE_ERROR &&
1892 		    strcmp("no such table: id_tbl", errp) == 0) {
1893 			free(errp);
1894 			*bep = be;
1895 			return (BACKEND_CREATE_NEED_INIT);
1896 		}
1897 
1898 		configd_critical("%s: schema version mismatch\n", db_file);
1899 		goto fail;
1900 	}
1901 	if (r == SQLITE_BUSY || r == SQLITE_LOCKED) {
1902 		free(errp);
1903 		*bep = NULL;
1904 		backend_destroy(be);
1905 		return (BACKEND_CREATE_LOCKED);
1906 	}
1907 	if (r == SQLITE_OK) {
1908 		if (info.rs_result == REP_PROTOCOL_FAIL_NOT_FOUND ||
1909 		    val != BACKEND_SCHEMA_VERSION) {
1910 			configd_critical("%s: schema version mismatch\n",
1911 			    db_file);
1912 			goto fail;
1913 		}
1914 	}
1915 
1916 	/*
1917 	 * pull in the whole database sequentially.
1918 	 */
1919 	if ((fd = open(db_file, O_RDONLY)) >= 0) {
1920 		size_t sz = 64 * 1024;
1921 		char *buffer = malloc(sz);
1922 		if (buffer != NULL) {
1923 			while (read(fd, buffer, sz) > 0)
1924 				;
1925 			free(buffer);
1926 		}
1927 		(void) close(fd);
1928 	}
1929 
1930 	/*
1931 	 * run an integrity check
1932 	 */
1933 	r = sqlite_exec(be->be_db, "PRAGMA integrity_check;",
1934 	    backend_integrity_callback, &integrity_results, &errp);
1935 
1936 	if (r == SQLITE_BUSY || r == SQLITE_LOCKED) {
1937 		free(errp);
1938 		*bep = NULL;
1939 		backend_destroy(be);
1940 		return (BACKEND_CREATE_LOCKED);
1941 	}
1942 	if (r == SQLITE_ABORT) {
1943 		free(errp);
1944 		errp = NULL;
1945 		integrity_results = "out of memory running integrity check\n";
1946 	} else if (r != SQLITE_OK && integrity_results == NULL) {
1947 		integrity_results = errp;
1948 		errp = NULL;
1949 	}
1950 
1951 integrity_fail:
1952 	if (integrity_results != NULL) {
1953 		const char *fname = "/etc/svc/volatile/db_errors";
1954 		if ((fd = open(fname, O_CREAT|O_WRONLY|O_APPEND, 0600)) < 0) {
1955 			fname = NULL;
1956 		} else {
1957 			if (backend_fd_write(fd, "\n\n") < 0 ||
1958 			    backend_fd_write(fd, db_file) < 0 ||
1959 			    backend_fd_write(fd,
1960 			    ": PRAGMA integrity_check; failed.  Results:\n") <
1961 			    0 || backend_fd_write(fd, integrity_results) < 0 ||
1962 			    backend_fd_write(fd, "\n\n") < 0) {
1963 				fname = NULL;
1964 			}
1965 			(void) close(fd);
1966 		}
1967 
1968 		if (!is_main_repository ||
1969 		    backend_id == BACKEND_TYPE_NONPERSIST) {
1970 			if (fname != NULL)
1971 				configd_critical(
1972 				    "%s: integrity check failed. Details in "
1973 				    "%s\n", db_file, fname);
1974 			else
1975 				configd_critical(
1976 				    "%s: integrity check failed.\n",
1977 				    db_file);
1978 		} else {
1979 			(void) fprintf(stderr,
1980 "\n"
1981 "svc.configd: smf(7) database integrity check of:\n"
1982 "\n"
1983 "    %s\n"
1984 "\n"
1985 "  failed. The database might be damaged or a media error might have\n"
1986 "  prevented it from being verified.  Additional information useful to\n"
1987 "  your service provider%s%s\n"
1988 "\n"
1989 "  The system will not be able to boot until you have restored a working\n"
1990 "  database.  svc.startd(8) will provide a sulogin(8) prompt for recovery\n"
1991 "  purposes.  The command:\n"
1992 "\n"
1993 "    /lib/svc/bin/restore_repository\n"
1994 "\n"
1995 "  can be run to restore a backup version of your repository.  See\n"
1996 "  http://illumos.org/msg/SMF-8000-MY for more information.\n"
1997 "\n",
1998 			    db_file,
1999 			    (fname == NULL)? ":\n\n" : " is in:\n\n    ",
2000 			    (fname == NULL)? integrity_results : fname);
2001 		}
2002 		free(errp);
2003 		goto fail;
2004 	}
2005 
2006 	/*
2007 	 * Simply do check if backend has been upgraded.  We do not wish
2008 	 * to actually carry out upgrade here - the main repository may
2009 	 * not be writable at this point.  Actual upgrade is carried out
2010 	 * via backend_check_readonly().  This check is done so that
2011 	 * we determine repository state - upgraded or not - and then
2012 	 * the appropriate SELECT statement (value-ordered or not)
2013 	 * can be used when retrieving property values early in boot.
2014 	 */
2015 	if (backend_id == BACKEND_TYPE_NORMAL)
2016 		backend_check_upgrade(be, B_FALSE);
2017 	/*
2018 	 * check if we are writable
2019 	 */
2020 	r = backend_is_readonly(be->be_db, be->be_path);
2021 
2022 	if (r == SQLITE_BUSY || r == SQLITE_LOCKED) {
2023 		free(errp);
2024 		*bep = NULL;
2025 		backend_destroy(be);
2026 		return (BACKEND_CREATE_LOCKED);
2027 	}
2028 	if (r != SQLITE_OK && r != SQLITE_FULL) {
2029 		free(errp);
2030 		be->be_readonly = 1;
2031 		*bep = be;
2032 		return (BACKEND_CREATE_READONLY);
2033 	}
2034 
2035 	*bep = be;
2036 	return (BACKEND_CREATE_SUCCESS);
2037 
2038 fail:
2039 	*bep = NULL;
2040 	backend_destroy(be);
2041 	return (BACKEND_CREATE_FAIL);
2042 }
2043 
2044 /*
2045  * (arg & -arg) is, through the magic of twos-complement arithmetic, the
2046  * lowest set bit in arg.
2047  */
2048 static size_t
round_up_to_p2(size_t arg)2049 round_up_to_p2(size_t arg)
2050 {
2051 	/*
2052 	 * Don't allow a zero result.
2053 	 */
2054 	assert(arg > 0 && ((ssize_t)arg > 0));
2055 
2056 	while ((arg & (arg - 1)) != 0)
2057 		arg += (arg & -arg);
2058 
2059 	return (arg);
2060 }
2061 
2062 /*
2063  * Returns
2064  *   _NO_RESOURCES - out of memory
2065  *   _BACKEND_ACCESS - backend type t (other than _NORMAL) doesn't exist
2066  *   _DONE - callback aborted query
2067  *   _SUCCESS
2068  */
2069 int
backend_run(backend_type_t t,backend_query_t * q,backend_run_callback_f * cb,void * data)2070 backend_run(backend_type_t t, backend_query_t *q,
2071     backend_run_callback_f *cb, void *data)
2072 {
2073 	char *errmsg = NULL;
2074 	int ret;
2075 	sqlite_backend_t *be;
2076 	hrtime_t ts, vts;
2077 
2078 	if (q == NULL || q->bq_buf == NULL)
2079 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
2080 
2081 	if ((ret = backend_lock(t, 0, &be)) != REP_PROTOCOL_SUCCESS)
2082 		return (ret);
2083 
2084 	ts = gethrtime();
2085 	vts = gethrvtime();
2086 	ret = sqlite_exec(be->be_db, q->bq_buf, cb, data, &errmsg);
2087 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2088 	ret = backend_error(be, ret, errmsg);
2089 	backend_unlock(be);
2090 
2091 	return (ret);
2092 }
2093 
2094 /*
2095  * Starts a "read-only" transaction -- i.e., locks out writers as long
2096  * as it is active.
2097  *
2098  * Fails with
2099  *   _NO_RESOURCES - out of memory
2100  *
2101  * If t is not _NORMAL, can also fail with
2102  *   _BACKEND_ACCESS - backend does not exist
2103  *
2104  * If writable is true, can also fail with
2105  *   _BACKEND_READONLY
2106  */
2107 static int
backend_tx_begin_common(backend_type_t t,backend_tx_t ** txp,int writable)2108 backend_tx_begin_common(backend_type_t t, backend_tx_t **txp, int writable)
2109 {
2110 	backend_tx_t *ret;
2111 	sqlite_backend_t *be;
2112 	int r;
2113 
2114 	*txp = NULL;
2115 
2116 	ret = uu_zalloc(sizeof (*ret));
2117 	if (ret == NULL)
2118 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
2119 
2120 	if ((r = backend_lock(t, writable, &be)) != REP_PROTOCOL_SUCCESS) {
2121 		uu_free(ret);
2122 		return (r);
2123 	}
2124 
2125 	ret->bt_be = be;
2126 	ret->bt_readonly = !writable;
2127 	ret->bt_type = t;
2128 	ret->bt_full = 0;
2129 
2130 	*txp = ret;
2131 	return (REP_PROTOCOL_SUCCESS);
2132 }
2133 
2134 int
backend_tx_begin_ro(backend_type_t t,backend_tx_t ** txp)2135 backend_tx_begin_ro(backend_type_t t, backend_tx_t **txp)
2136 {
2137 	return (backend_tx_begin_common(t, txp, 0));
2138 }
2139 
2140 static void
backend_tx_end(backend_tx_t * tx)2141 backend_tx_end(backend_tx_t *tx)
2142 {
2143 	sqlite_backend_t *be;
2144 
2145 	be = tx->bt_be;
2146 
2147 	if (tx->bt_full) {
2148 		struct sqlite *new;
2149 
2150 		/*
2151 		 * sqlite tends to be sticky with SQLITE_FULL, so we try
2152 		 * to get a fresh database handle if we got a FULL warning
2153 		 * along the way.  If that fails, no harm done.
2154 		 */
2155 		new = sqlite_open(be->be_path, 0600, NULL);
2156 		if (new != NULL) {
2157 			sqlite_close(be->be_db);
2158 			be->be_db = new;
2159 		}
2160 	}
2161 	backend_unlock(be);
2162 	tx->bt_be = NULL;
2163 	uu_free(tx);
2164 }
2165 
2166 void
backend_tx_end_ro(backend_tx_t * tx)2167 backend_tx_end_ro(backend_tx_t *tx)
2168 {
2169 	assert(tx->bt_readonly);
2170 	backend_tx_end(tx);
2171 }
2172 
2173 /*
2174  * Fails with
2175  *   _NO_RESOURCES - out of memory
2176  *   _BACKEND_ACCESS
2177  *   _BACKEND_READONLY
2178  */
2179 int
backend_tx_begin(backend_type_t t,backend_tx_t ** txp)2180 backend_tx_begin(backend_type_t t, backend_tx_t **txp)
2181 {
2182 	int r;
2183 	char *errmsg;
2184 	hrtime_t ts, vts;
2185 
2186 	r = backend_tx_begin_common(t, txp, 1);
2187 	if (r != REP_PROTOCOL_SUCCESS)
2188 		return (r);
2189 
2190 	ts = gethrtime();
2191 	vts = gethrvtime();
2192 	r = sqlite_exec((*txp)->bt_be->be_db, "BEGIN TRANSACTION", NULL, NULL,
2193 	    &errmsg);
2194 	UPDATE_TOTALS((*txp)->bt_be, bt_exec, ts, vts);
2195 	if (r == SQLITE_FULL)
2196 		(*txp)->bt_full = 1;
2197 	r = backend_error((*txp)->bt_be, r, errmsg);
2198 
2199 	if (r != REP_PROTOCOL_SUCCESS) {
2200 		assert(r != REP_PROTOCOL_DONE);
2201 		(void) sqlite_exec((*txp)->bt_be->be_db,
2202 		    "ROLLBACK TRANSACTION", NULL, NULL, NULL);
2203 		backend_tx_end(*txp);
2204 		*txp = NULL;
2205 		return (r);
2206 	}
2207 
2208 	(*txp)->bt_readonly = 0;
2209 
2210 	return (REP_PROTOCOL_SUCCESS);
2211 }
2212 
2213 void
backend_tx_rollback(backend_tx_t * tx)2214 backend_tx_rollback(backend_tx_t *tx)
2215 {
2216 	int r;
2217 	char *errmsg;
2218 	sqlite_backend_t *be;
2219 	hrtime_t ts, vts;
2220 
2221 	assert(tx != NULL && tx->bt_be != NULL && !tx->bt_readonly);
2222 	be = tx->bt_be;
2223 
2224 	ts = gethrtime();
2225 	vts = gethrvtime();
2226 	r = sqlite_exec(be->be_db, "ROLLBACK TRANSACTION", NULL, NULL,
2227 	    &errmsg);
2228 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2229 	if (r == SQLITE_FULL)
2230 		tx->bt_full = 1;
2231 	(void) backend_error(be, r, errmsg);
2232 
2233 	backend_tx_end(tx);
2234 }
2235 
2236 /*
2237  * Fails with
2238  *   _NO_RESOURCES - out of memory
2239  */
2240 int
backend_tx_commit(backend_tx_t * tx)2241 backend_tx_commit(backend_tx_t *tx)
2242 {
2243 	int r, r2;
2244 	char *errmsg;
2245 	sqlite_backend_t *be;
2246 	hrtime_t ts, vts;
2247 
2248 	assert(tx != NULL && tx->bt_be != NULL && !tx->bt_readonly);
2249 	be = tx->bt_be;
2250 	ts = gethrtime();
2251 	vts = gethrvtime();
2252 	r = sqlite_exec(be->be_db, "COMMIT TRANSACTION", NULL, NULL,
2253 	    &errmsg);
2254 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2255 	if (r == SQLITE_FULL)
2256 		tx->bt_full = 1;
2257 
2258 	r = backend_error(be, r, errmsg);
2259 	assert(r != REP_PROTOCOL_DONE);
2260 
2261 	if (r != REP_PROTOCOL_SUCCESS) {
2262 		r2 = sqlite_exec(be->be_db, "ROLLBACK TRANSACTION", NULL, NULL,
2263 		    &errmsg);
2264 		r2 = backend_error(be, r2, errmsg);
2265 		if (r2 != REP_PROTOCOL_SUCCESS)
2266 			backend_panic("cannot rollback failed commit");
2267 
2268 		backend_tx_end(tx);
2269 		return (r);
2270 	}
2271 	backend_tx_end(tx);
2272 	return (REP_PROTOCOL_SUCCESS);
2273 }
2274 
2275 static const char *
id_space_to_name(enum id_space id)2276 id_space_to_name(enum id_space id)
2277 {
2278 	switch (id) {
2279 	case BACKEND_ID_SERVICE_INSTANCE:
2280 		return ("SI");
2281 	case BACKEND_ID_PROPERTYGRP:
2282 		return ("PG");
2283 	case BACKEND_ID_GENERATION:
2284 		return ("GEN");
2285 	case BACKEND_ID_PROPERTY:
2286 		return ("PROP");
2287 	case BACKEND_ID_VALUE:
2288 		return ("VAL");
2289 	case BACKEND_ID_SNAPNAME:
2290 		return ("SNAME");
2291 	case BACKEND_ID_SNAPSHOT:
2292 		return ("SHOT");
2293 	case BACKEND_ID_SNAPLEVEL:
2294 		return ("SLVL");
2295 	default:
2296 		abort();
2297 		/*NOTREACHED*/
2298 	}
2299 }
2300 
2301 /*
2302  * Returns a new id or 0 if the id argument is invalid or the query fails.
2303  */
2304 uint32_t
backend_new_id(backend_tx_t * tx,enum id_space id)2305 backend_new_id(backend_tx_t *tx, enum id_space id)
2306 {
2307 	struct run_single_int_info info;
2308 	uint32_t new_id = 0;
2309 	const char *name = id_space_to_name(id);
2310 	char *errmsg;
2311 	int ret;
2312 	sqlite_backend_t *be;
2313 	hrtime_t ts, vts;
2314 
2315 	assert(tx != NULL && tx->bt_be != NULL && !tx->bt_readonly);
2316 	be = tx->bt_be;
2317 
2318 	info.rs_out = &new_id;
2319 	info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND;
2320 
2321 	ts = gethrtime();
2322 	vts = gethrvtime();
2323 	ret = sqlite_exec_printf(be->be_db,
2324 	    "SELECT id_next FROM id_tbl WHERE (id_name = '%q');"
2325 	    "UPDATE id_tbl SET id_next = id_next + 1 WHERE (id_name = '%q');",
2326 	    run_single_int_callback, &info, &errmsg, name, name);
2327 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2328 	if (ret == SQLITE_FULL)
2329 		tx->bt_full = 1;
2330 
2331 	ret = backend_error(be, ret, errmsg);
2332 
2333 	if (ret != REP_PROTOCOL_SUCCESS) {
2334 		return (0);
2335 	}
2336 
2337 	return (new_id);
2338 }
2339 
2340 /*
2341  * Returns
2342  *   _NO_RESOURCES - out of memory
2343  *   _DONE - callback aborted query
2344  *   _SUCCESS
2345  */
2346 int
backend_tx_run(backend_tx_t * tx,backend_query_t * q,backend_run_callback_f * cb,void * data)2347 backend_tx_run(backend_tx_t *tx, backend_query_t *q,
2348     backend_run_callback_f *cb, void *data)
2349 {
2350 	char *errmsg = NULL;
2351 	int ret;
2352 	sqlite_backend_t *be;
2353 	hrtime_t ts, vts;
2354 
2355 	assert(tx != NULL && tx->bt_be != NULL);
2356 	be = tx->bt_be;
2357 
2358 	if (q == NULL || q->bq_buf == NULL)
2359 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
2360 
2361 	ts = gethrtime();
2362 	vts = gethrvtime();
2363 	ret = sqlite_exec(be->be_db, q->bq_buf, cb, data, &errmsg);
2364 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2365 	if (ret == SQLITE_FULL)
2366 		tx->bt_full = 1;
2367 	ret = backend_error(be, ret, errmsg);
2368 
2369 	return (ret);
2370 }
2371 
2372 /*
2373  * Returns
2374  *   _NO_RESOURCES - out of memory
2375  *   _NOT_FOUND - the query returned no results
2376  *   _SUCCESS - the query returned a single integer
2377  */
2378 int
backend_tx_run_single_int(backend_tx_t * tx,backend_query_t * q,uint32_t * buf)2379 backend_tx_run_single_int(backend_tx_t *tx, backend_query_t *q, uint32_t *buf)
2380 {
2381 	struct run_single_int_info info;
2382 	int ret;
2383 
2384 	info.rs_out = buf;
2385 	info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND;
2386 
2387 	ret = backend_tx_run(tx, q, run_single_int_callback, &info);
2388 	assert(ret != REP_PROTOCOL_DONE);
2389 
2390 	if (ret != REP_PROTOCOL_SUCCESS)
2391 		return (ret);
2392 
2393 	return (info.rs_result);
2394 }
2395 
2396 /*
2397  * Fails with
2398  *   _NO_RESOURCES - out of memory
2399  */
2400 int
backend_tx_run_update(backend_tx_t * tx,const char * format,...)2401 backend_tx_run_update(backend_tx_t *tx, const char *format, ...)
2402 {
2403 	va_list a;
2404 	char *errmsg;
2405 	int ret;
2406 	sqlite_backend_t *be;
2407 	hrtime_t ts, vts;
2408 
2409 	assert(tx != NULL && tx->bt_be != NULL && !tx->bt_readonly);
2410 	be = tx->bt_be;
2411 
2412 	va_start(a, format);
2413 	ts = gethrtime();
2414 	vts = gethrvtime();
2415 	ret = sqlite_exec_vprintf(be->be_db, format, NULL, NULL, &errmsg, a);
2416 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2417 	if (ret == SQLITE_FULL)
2418 		tx->bt_full = 1;
2419 	va_end(a);
2420 	ret = backend_error(be, ret, errmsg);
2421 	assert(ret != REP_PROTOCOL_DONE);
2422 
2423 	return (ret);
2424 }
2425 
2426 /*
2427  * returns REP_PROTOCOL_FAIL_NOT_FOUND if no changes occured
2428  */
2429 int
backend_tx_run_update_changed(backend_tx_t * tx,const char * format,...)2430 backend_tx_run_update_changed(backend_tx_t *tx, const char *format, ...)
2431 {
2432 	va_list a;
2433 	char *errmsg;
2434 	int ret;
2435 	sqlite_backend_t *be;
2436 	hrtime_t ts, vts;
2437 
2438 	assert(tx != NULL && tx->bt_be != NULL && !tx->bt_readonly);
2439 	be = tx->bt_be;
2440 
2441 	va_start(a, format);
2442 	ts = gethrtime();
2443 	vts = gethrvtime();
2444 	ret = sqlite_exec_vprintf(be->be_db, format, NULL, NULL, &errmsg, a);
2445 	UPDATE_TOTALS(be, bt_exec, ts, vts);
2446 	if (ret == SQLITE_FULL)
2447 		tx->bt_full = 1;
2448 	va_end(a);
2449 
2450 	ret = backend_error(be, ret, errmsg);
2451 
2452 	return (ret);
2453 }
2454 
2455 #define	BACKEND_ADD_SCHEMA(be, file, tbls, idxs) \
2456 	(backend_add_schema((be), (file), \
2457 	    (tbls), sizeof (tbls) / sizeof (*(tbls)), \
2458 	    (idxs), sizeof (idxs) / sizeof (*(idxs))))
2459 
2460 static int
backend_add_schema(sqlite_backend_t * be,const char * file,struct backend_tbl_info * tbls,int tbl_count,struct backend_idx_info * idxs,int idx_count)2461 backend_add_schema(sqlite_backend_t *be, const char *file,
2462     struct backend_tbl_info *tbls, int tbl_count,
2463     struct backend_idx_info *idxs, int idx_count)
2464 {
2465 	int i;
2466 	char *errmsg;
2467 	int ret;
2468 
2469 	/*
2470 	 * Create the tables.
2471 	 */
2472 	for (i = 0; i < tbl_count; i++) {
2473 		if (tbls[i].bti_name == NULL) {
2474 			assert(i + 1 == tbl_count);
2475 			break;
2476 		}
2477 		ret = sqlite_exec_printf(be->be_db,
2478 		    "CREATE TABLE %s (%s);\n",
2479 		    NULL, NULL, &errmsg, tbls[i].bti_name, tbls[i].bti_cols);
2480 
2481 		if (ret != SQLITE_OK) {
2482 			configd_critical(
2483 			    "%s: %s table creation fails: %s\n", file,
2484 			    tbls[i].bti_name, errmsg);
2485 			free(errmsg);
2486 			return (-1);
2487 		}
2488 	}
2489 
2490 	/*
2491 	 * Make indices on key tables and columns.
2492 	 */
2493 	for (i = 0; i < idx_count; i++) {
2494 		if (idxs[i].bxi_tbl == NULL) {
2495 			assert(i + 1 == idx_count);
2496 			break;
2497 		}
2498 
2499 		ret = sqlite_exec_printf(be->be_db,
2500 		    "CREATE INDEX %s_%s ON %s (%s);\n",
2501 		    NULL, NULL, &errmsg, idxs[i].bxi_tbl, idxs[i].bxi_idx,
2502 		    idxs[i].bxi_tbl, idxs[i].bxi_cols);
2503 
2504 		if (ret != SQLITE_OK) {
2505 			configd_critical(
2506 			    "%s: %s_%s index creation fails: %s\n", file,
2507 			    idxs[i].bxi_tbl, idxs[i].bxi_idx, errmsg);
2508 			free(errmsg);
2509 			return (-1);
2510 		}
2511 	}
2512 	return (0);
2513 }
2514 
2515 static int
backend_init_schema(sqlite_backend_t * be,const char * db_file,backend_type_t t)2516 backend_init_schema(sqlite_backend_t *be, const char *db_file, backend_type_t t)
2517 {
2518 	int i;
2519 	char *errmsg;
2520 	int ret;
2521 
2522 	assert(t == BACKEND_TYPE_NORMAL || t == BACKEND_TYPE_NONPERSIST);
2523 
2524 	if (t == BACKEND_TYPE_NORMAL) {
2525 		ret = BACKEND_ADD_SCHEMA(be, db_file, tbls_normal, idxs_normal);
2526 	} else if (t == BACKEND_TYPE_NONPERSIST) {
2527 		ret = BACKEND_ADD_SCHEMA(be, db_file, tbls_np, idxs_np);
2528 	} else {
2529 		abort();		/* can't happen */
2530 	}
2531 
2532 	if (ret < 0) {
2533 		return (ret);
2534 	}
2535 
2536 	ret = BACKEND_ADD_SCHEMA(be, db_file, tbls_common, idxs_common);
2537 	if (ret < 0) {
2538 		return (ret);
2539 	}
2540 
2541 	/*
2542 	 * Add the schema version to the table
2543 	 */
2544 	ret = sqlite_exec_printf(be->be_db,
2545 	    "INSERT INTO schema_version (schema_version) VALUES (%d)",
2546 	    NULL, NULL, &errmsg, BACKEND_SCHEMA_VERSION);
2547 	if (ret != SQLITE_OK) {
2548 		configd_critical(
2549 		    "setting schema version fails: %s\n", errmsg);
2550 		free(errmsg);
2551 	}
2552 
2553 	/*
2554 	 * Populate id_tbl with initial IDs.
2555 	 */
2556 	for (i = 0; i < BACKEND_ID_INVALID; i++) {
2557 		const char *name = id_space_to_name(i);
2558 
2559 		ret = sqlite_exec_printf(be->be_db,
2560 		    "INSERT INTO id_tbl (id_name, id_next) "
2561 		    "VALUES ('%q', %d);", NULL, NULL, &errmsg, name, 1);
2562 		if (ret != SQLITE_OK) {
2563 			configd_critical(
2564 			    "id insertion for %s fails: %s\n", name, errmsg);
2565 			free(errmsg);
2566 			return (-1);
2567 		}
2568 	}
2569 	/*
2570 	 * Set the persistance of the database.  The normal database is marked
2571 	 * "synchronous", so that all writes are synchronized to stable storage
2572 	 * before proceeding.
2573 	 */
2574 	ret = sqlite_exec_printf(be->be_db,
2575 	    "PRAGMA default_synchronous = %s; PRAGMA synchronous = %s;",
2576 	    NULL, NULL, &errmsg,
2577 	    (t == BACKEND_TYPE_NORMAL)? "ON" : "OFF",
2578 	    (t == BACKEND_TYPE_NORMAL)? "ON" : "OFF");
2579 	if (ret != SQLITE_OK) {
2580 		configd_critical("pragma setting fails: %s\n", errmsg);
2581 		free(errmsg);
2582 		return (-1);
2583 	}
2584 
2585 	return (0);
2586 }
2587 
2588 int
backend_init(const char * db_file,const char * npdb_file,int have_np)2589 backend_init(const char *db_file, const char *npdb_file, int have_np)
2590 {
2591 	sqlite_backend_t *be;
2592 	char *errp;
2593 	struct sqlite *fast_db;
2594 	int r;
2595 	backend_switch_results_t switch_result = BACKEND_SWITCH_OK;
2596 	int writable_persist = 1;
2597 
2598 	/* set up our temporary directory */
2599 	sqlite_temp_directory = "/etc/svc/volatile";
2600 
2601 	if (strcmp(SQLITE_VERSION, sqlite_version) != 0) {
2602 		configd_critical("Mismatched link!  (%s should be %s)\n",
2603 		    sqlite_version, SQLITE_VERSION);
2604 		return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2605 	}
2606 
2607 	if (db_file == NULL)
2608 		db_file = REPOSITORY_DB;
2609 	if (strcmp(db_file, REPOSITORY_DB) != 0) {
2610 		is_main_repository = 0;
2611 	}
2612 
2613 	/*
2614 	 * If the svc.configd crashed, there might be a leftover transient
2615 	 * database at FAST_REPOSITORY_DB,which contains useful
2616 	 * information.  Both early manifest import and late manifest
2617 	 * import use svcadm to copy the repository to FAST_REPOSITORY_DB.
2618 	 * One reason for doing this is that it improves the performance of
2619 	 * manifest import.  The other reason is that the repository may be
2620 	 * on read-only root in the case of early manifest import.
2621 	 *
2622 	 * If FAST_REPOSITORY_DB exists, it is an indication that
2623 	 * svc.configd has been restarted for some reason.  Since we have
2624 	 * no way of knowing where we are in the boot process, the safe
2625 	 * thing to do is to move the repository back to it's non-transient
2626 	 * location, REPOSITORY_DB.  This may slow manifest import
2627 	 * performance, but it avoids the problem of missing the command to
2628 	 * move the repository to permanent storage.
2629 	 *
2630 	 * There is a caveat, though.  If root is read-only, we'll need to
2631 	 * leave the repository at FAST_REPOSITORY_DB.  If root is
2632 	 * read-only, late manifest import has not yet run, so it will move
2633 	 * the repository back to permanent storage when it runs.
2634 	 */
2635 	if (is_main_repository)
2636 		switch_result = backend_switch_recovery();
2637 
2638 	r = backend_create(BACKEND_TYPE_NORMAL, db_file, &be);
2639 	switch (r) {
2640 	case BACKEND_CREATE_FAIL:
2641 		return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2642 	case BACKEND_CREATE_LOCKED:
2643 		return (CONFIGD_EXIT_DATABASE_LOCKED);
2644 	case BACKEND_CREATE_SUCCESS:
2645 		break;		/* success */
2646 	case BACKEND_CREATE_READONLY:
2647 		writable_persist = 0;
2648 		break;
2649 	case BACKEND_CREATE_NEED_INIT:
2650 		if (backend_init_schema(be, db_file, BACKEND_TYPE_NORMAL)) {
2651 			backend_destroy(be);
2652 			return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2653 		}
2654 		break;
2655 	default:
2656 		abort();
2657 		/*NOTREACHED*/
2658 	}
2659 	backend_create_finish(BACKEND_TYPE_NORMAL, be);
2660 	flight_recorder_event(BE_FLIGHT_EV_REPO_CREATE,
2661 	    writable_persist == 1 ? BE_FLIGHT_ST_RW : BE_FLIGHT_ST_RO);
2662 	/*
2663 	 * If there was a transient repository that could not be copied
2664 	 * back because the root file system was read-only, switch over to
2665 	 * using the transient repository.
2666 	 */
2667 	if (switch_result == BACKEND_SWITCH_RO) {
2668 		char *db_name_copy = NULL;
2669 
2670 		fast_db = sqlite_open(FAST_REPOSITORY_DB, 0600, &errp);
2671 		if (fast_db == NULL) {
2672 			/* Can't open fast repository.  Stick with permanent. */
2673 			configd_critical("Cannot open \"%s\".  %s\n",
2674 			    FAST_REPOSITORY_DB, errp == NULL ? "" : errp);
2675 			free(errp);
2676 		} else {
2677 			db_name_copy = strdup(FAST_REPOSITORY_DB);
2678 			if (db_name_copy == NULL) {
2679 				configd_critical("backend_init: out of "
2680 				    "memory.\n");
2681 				sqlite_close(fast_db);
2682 				return (CONFIGD_EXIT_INIT_FAILED);
2683 			} else {
2684 				flight_recorder_event(
2685 				    BE_FLIGHT_EV_LINGERING_FAST,
2686 				    BE_FLIGHT_ST_RO);
2687 				sqlite_close(be->be_db);
2688 				be->be_db = fast_db;
2689 				be->be_ppath = be->be_path;
2690 				be->be_path = db_name_copy;
2691 			}
2692 		}
2693 	}
2694 
2695 	if (have_np) {
2696 		if (npdb_file == NULL)
2697 			npdb_file = NONPERSIST_DB;
2698 
2699 		r = backend_create(BACKEND_TYPE_NONPERSIST, npdb_file, &be);
2700 		switch (r) {
2701 		case BACKEND_CREATE_SUCCESS:
2702 			break;		/* success */
2703 		case BACKEND_CREATE_FAIL:
2704 			return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2705 		case BACKEND_CREATE_LOCKED:
2706 			return (CONFIGD_EXIT_DATABASE_LOCKED);
2707 		case BACKEND_CREATE_READONLY:
2708 			configd_critical("%s: unable to write\n", npdb_file);
2709 			return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2710 		case BACKEND_CREATE_NEED_INIT:
2711 			if (backend_init_schema(be, db_file,
2712 			    BACKEND_TYPE_NONPERSIST)) {
2713 				backend_destroy(be);
2714 				return (CONFIGD_EXIT_DATABASE_INIT_FAILED);
2715 			}
2716 			break;
2717 		default:
2718 			abort();
2719 			/*NOTREACHED*/
2720 		}
2721 		backend_create_finish(BACKEND_TYPE_NONPERSIST, be);
2722 
2723 		if (r != BACKEND_CREATE_NEED_INIT) {
2724 			flight_recorder_event(BE_FLIGHT_EV_RESTART,
2725 			    BE_FLIGHT_ST_INFO);
2726 		}
2727 
2728 		/*
2729 		 * If we started up with a writable filesystem, but the
2730 		 * non-persistent database needed initialization, we are
2731 		 * booting a non-global zone or a system with a writable
2732 		 * root (ZFS), so do a backup.  Checking to see if the
2733 		 * non-persistent database needed initialization also keeps
2734 		 * us from making additional backups if configd gets
2735 		 * restarted.
2736 		 */
2737 		if (r == BACKEND_CREATE_NEED_INIT && writable_persist &&
2738 		    backend_lock(BACKEND_TYPE_NORMAL, 0, &be) ==
2739 		    REP_PROTOCOL_SUCCESS) {
2740 			if (backend_create_backup_locked(be,
2741 			    REPOSITORY_BOOT_BACKUP) != REP_PROTOCOL_SUCCESS) {
2742 				configd_critical(
2743 				    "unable to create \"%s\" backup of "
2744 				    "\"%s\"\n", REPOSITORY_BOOT_BACKUP,
2745 				    be->be_path);
2746 			}
2747 			backend_unlock(be);
2748 		}
2749 
2750 		/*
2751 		 * On the other hand if we started with a read-only file
2752 		 * system and the non-persistent database needed
2753 		 * initialization, then we need to take a checkpoint of the
2754 		 * repository.  We grab the checkpoint now before Early
2755 		 * Manifest Import starts modifying the repository.  Then
2756 		 * when the file system becomes writable, the checkpoint
2757 		 * can be used to create the boot time backup of the
2758 		 * repository.  Checking that the non-persistent database
2759 		 * needed initialization, keeps us from making additional
2760 		 * checkpoints if configd gets restarted.
2761 		 */
2762 		if (r == BACKEND_CREATE_NEED_INIT && writable_persist == 0 &&
2763 		    backend_lock(BACKEND_TYPE_NORMAL, 0, &be) ==
2764 		    REP_PROTOCOL_SUCCESS) {
2765 			r = backend_checkpoint_repository(be);
2766 			if (r != REP_PROTOCOL_SUCCESS) {
2767 				configd_critical("unable to create checkpoint "
2768 				    "of \"%s\"\n", be->be_path);
2769 			}
2770 			backend_unlock(be);
2771 		}
2772 
2773 		/*
2774 		 * If the non-persistent database did not need
2775 		 * initialization, svc.configd has been restarted.  See if
2776 		 * the boot time checkpoint exists.  If it does, use it to
2777 		 * make a backup if root is writable.
2778 		 */
2779 		if (r != BACKEND_CREATE_NEED_INIT &&
2780 		    backend_lock(BACKEND_TYPE_NORMAL, 0, &be) ==
2781 		    REP_PROTOCOL_SUCCESS) {
2782 			struct stat sb;
2783 
2784 			if ((stat(REPOSITORY_CHECKPOINT, &sb) == 0) &&
2785 			    (sb.st_size > 0) && (sb.st_mode & S_IFREG)) {
2786 				be->be_checkpoint = REPOSITORY_CHECKPOINT;
2787 				flight_recorder_event(
2788 				    BE_FLIGHT_EV_CHECKPOINT_EXISTS,
2789 				    BE_FLIGHT_ST_INFO);
2790 			}
2791 
2792 			/*
2793 			 * If we have a checkpoint and root is writable,
2794 			 * make the backup now.
2795 			 */
2796 			if (be->be_checkpoint && writable_persist) {
2797 				if (backend_create_backup_locked(be,
2798 				    REPOSITORY_BOOT_BACKUP) !=
2799 				    REP_PROTOCOL_SUCCESS) {
2800 					configd_critical(
2801 					    "unable to create \"%s\" backup of "
2802 					    "\"%s\"\n", REPOSITORY_BOOT_BACKUP,
2803 					    be->be_path);
2804 				}
2805 			}
2806 			backend_unlock(be);
2807 		}
2808 	}
2809 
2810 	/*
2811 	 * If the persistent backend is writable at this point, upgrade it.
2812 	 * This can occur in a few cases, most notably on UFS roots if
2813 	 * we are operating on the backend from another root, as is the case
2814 	 * during alternate-root BFU.
2815 	 *
2816 	 * Otherwise, upgrade will occur via backend_check_readonly() when
2817 	 * the repository is re-opened read-write.
2818 	 */
2819 	if (writable_persist) {
2820 		r = backend_lock(BACKEND_TYPE_NORMAL, 1, &be);
2821 		assert(r == REP_PROTOCOL_SUCCESS);
2822 		backend_check_upgrade(be, B_TRUE);
2823 		backend_unlock(be);
2824 	}
2825 
2826 	return (CONFIGD_EXIT_OKAY);
2827 }
2828 
2829 /*
2830  * quiesce all database activity prior to exiting
2831  */
2832 void
backend_fini(void)2833 backend_fini(void)
2834 {
2835 	sqlite_backend_t *be_normal, *be_np;
2836 
2837 	(void) backend_lock(BACKEND_TYPE_NORMAL, 1, &be_normal);
2838 	(void) backend_lock(BACKEND_TYPE_NONPERSIST, 1, &be_np);
2839 }
2840 
2841 #define	QUERY_BASE	128
2842 backend_query_t *
backend_query_alloc(void)2843 backend_query_alloc(void)
2844 {
2845 	backend_query_t *q;
2846 	q = calloc(1, sizeof (backend_query_t));
2847 	if (q != NULL) {
2848 		q->bq_size = QUERY_BASE;
2849 		q->bq_buf = calloc(1, q->bq_size);
2850 		if (q->bq_buf == NULL) {
2851 			q->bq_size = 0;
2852 		}
2853 
2854 	}
2855 	return (q);
2856 }
2857 
2858 void
backend_query_append(backend_query_t * q,const char * value)2859 backend_query_append(backend_query_t *q, const char *value)
2860 {
2861 	char *alloc;
2862 	int count;
2863 	size_t size, old_len;
2864 
2865 	if (q == NULL) {
2866 		/* We'll discover the error when we try to run the query. */
2867 		return;
2868 	}
2869 
2870 	while (q->bq_buf != NULL) {
2871 		old_len = strlen(q->bq_buf);
2872 		size = q->bq_size;
2873 		count = strlcat(q->bq_buf, value, size);
2874 
2875 		if (count < size)
2876 			break;				/* success */
2877 
2878 		q->bq_buf[old_len] = 0;
2879 		size = round_up_to_p2(count + 1);
2880 
2881 		assert(size > q->bq_size);
2882 		alloc = realloc(q->bq_buf, size);
2883 		if (alloc == NULL) {
2884 			free(q->bq_buf);
2885 			q->bq_buf = NULL;
2886 			break;				/* can't grow */
2887 		}
2888 
2889 		q->bq_buf = alloc;
2890 		q->bq_size = size;
2891 	}
2892 }
2893 
2894 void
backend_query_add(backend_query_t * q,const char * format,...)2895 backend_query_add(backend_query_t *q, const char *format, ...)
2896 {
2897 	va_list args;
2898 	char *new;
2899 
2900 	if (q == NULL || q->bq_buf == NULL)
2901 		return;
2902 
2903 	va_start(args, format);
2904 	new = sqlite_vmprintf(format, args);
2905 	va_end(args);
2906 
2907 	if (new == NULL) {
2908 		free(q->bq_buf);
2909 		q->bq_buf = NULL;
2910 		return;
2911 	}
2912 
2913 	backend_query_append(q, new);
2914 
2915 	free(new);
2916 }
2917 
2918 void
backend_query_free(backend_query_t * q)2919 backend_query_free(backend_query_t *q)
2920 {
2921 	if (q != NULL) {
2922 		if (q->bq_buf != NULL) {
2923 			free(q->bq_buf);
2924 		}
2925 		free(q);
2926 	}
2927 }
2928