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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	db_dictlog.cc
24  *
25  *	Copyright (c) 1988-2000 by Sun Microsystems, Inc.
26  *	All Rights Reserved.
27  */
28 
29 #include <stdio.h>
30 
31 #include <malloc.h>
32 #include <string.h>
33 #ifdef TDRPC
34 #include <sysent.h>
35 #endif
36 #include <unistd.h>
37 
38 #include "nisdb_rw.h"
39 
40 #include "db_headers.h"
41 #include "db_dictlog.h"
42 
43 #include "nisdb_mt.h"
44 
45 
46 /*
47  * Constructor:  Create a log entry using the given parameters.  Note that
48  * pointers to db_query and entry_object are simply assigned, not copied.
49  */
db_dictlog_entry(int a,vers * v,char * tname,table_obj * obj)50 db_dictlog_entry::db_dictlog_entry(int a, vers * v, char *tname,
51 				    table_obj *obj)
52 {
53 	action = a;
54 	aversion.assign(v);
55 	table_name = tname;
56 	table_object = obj;
57 	next = NULL;
58 	bversion.assign(v);
59 }
60 
~db_dictlog_entry()61 db_dictlog_entry::~db_dictlog_entry()
62 {
63 /* we might not have allocated these ourselves, so we cannot delete them */
64 }
65 
66 /* prints a line from the journal */
67 void
print()68 db_dictlog_entry::print()
69 {
70 	switch (action) {
71 	case DB_ADD_TABLE:
72 	    printf ("add: ");
73 	    break;
74 	case DB_REMOVE_TABLE:
75 	    printf ("remove: ");
76 	    break;
77 	default:
78 	    printf ("action(%d): ", action);
79 	    break;
80 	}
81 
82 	aversion.print(stdout);
83 	putchar(' ');
84 	if (table_name != NULL)
85 		printf ("table %s\n", table_name);
86 	else
87 		printf("no table!\n");
88 	bversion.print(stdout);
89 	putchar('\n');
90 }
91 
92 static void
free_table_entry(table_obj * obj)93 free_table_entry(table_obj* obj)
94 {
95 	if (obj == NULL)
96 		return;
97 
98 	if (obj->ta_type != NULL)
99 		free(obj->ta_type);
100 
101 	table_col* tcs = obj->ta_cols.ta_cols_val;
102 	int i;
103 	for (i = 0; i < obj->ta_cols.ta_cols_len; i++) {
104 		if (tcs[i].tc_name != NULL)
105 			delete tcs[i].tc_name;
106 	}
107 	if (tcs != NULL)
108 		delete tcs;
109 	if (obj->ta_path != NULL)
110 		free(obj->ta_path);
111 	free(obj);
112 }
113 
114 static void
delete_log_entry(db_dictlog_entry * lentry)115 delete_log_entry(db_dictlog_entry *lentry)
116 {
117 	char *tname;
118 	table_obj *obj;
119 	if (lentry) {
120 		if ((tname = lentry->get_table_name())) {
121 			delete tname;
122 		}
123 		if ((obj = lentry->get_table_object())) {
124 		    free_table_entry(obj);
125 		}
126 		delete lentry;
127 	}
128 }
129 
130 /*
131  * Execute given function 'func' on log.
132  * function takes as arguments: pointer to log entry, character pointer to
133  * another argument, and pointer to an integer, which is used as a counter.
134  * 'func' should increment this value for each successful application.
135  * The log is traversed until either 'func' returns FALSE, or when the log
136  * is exhausted.  The second argument to 'execute_on_log' is passed as the
137  * second argument to 'func'.  The third argument, 'clean' determines whether
138  * the log entry is deleted after the function has been applied.
139  * Returns the number of times that 'func' incremented its third argument.
140  */
141 int
execute_on_log(bool_t (* func)(db_dictlog_entry *,char *,int *),char * dict,bool_t clean)142 db_dictlog::execute_on_log(bool_t (*func) (db_dictlog_entry *,
143 					    char *, int *),
144 					    char* dict, bool_t clean)
145 {
146 	db_dictlog_entry    *j;
147 	int count = 0;
148 	bool_t done = FALSE;
149 
150 	WRITELOCK(this, 0, "w db_dictlog::execute_on_log");
151 	if (open() == FALSE) {   // open log
152 		WRITEUNLOCK(this, 0, "wu db_dictlog::execute_on_log");
153 		return (0);
154 	}
155 	while (!done) {
156 		j = get();
157 		if (j == NULL)
158 			break;
159 		if ((*func)(j, dict, &count) == FALSE) done = TRUE;
160 		if (clean) delete_log_entry(j);
161 	}
162 
163 	close();
164 	WRITEUNLOCK(this, count, "wu db_dictlog::execute_on_log");
165 	return (count);
166 }
167 
168 static bool_t
print_log_entry(db_dictlog_entry * j,char *,int * count)169 print_log_entry(db_dictlog_entry *j, char*, int *count)
170 {
171 	j->print();
172 	++ *count;
173 	return (TRUE);
174 }
175 
176 /* Print contents of log file to stdout */
177 int
print()178 db_dictlog::print()
179 {
180 	return (execute_on_log(&(print_log_entry), NULL));
181 }
182 
183 /*
184  * Return the next element in current log; return NULL if end of log or error.
185  * Log must have been opened for READ.
186  */
187 db_dictlog_entry
get()188 *db_dictlog::get()
189 {
190 	db_dictlog_entry *j;
191 
192 	READLOCK(this, NULL, "r db_dictlog::get");
193 	if (mode != PICKLE_READ) {
194 		READUNLOCK(this, NULL, "ru db_dictlog::get");
195 		return (NULL);
196 	}
197 
198 	j = new db_dictlog_entry;
199 
200 	if (j == NULL) {
201 		READUNLOCK(this, NULL, "ru db_dictlog::get");
202 		return (NULL);
203 	}
204 	if (xdr_db_dictlog_entry(&(xdr), j) == FALSE) {
205 		delete_log_entry (j);
206 /*    WARNING("Could not sucessfully finish reading log"); */
207 		READUNLOCK(this, NULL, "ru db_dictlog::get");
208 		return (NULL);
209 	}
210 	if (! j->sane()) {
211 		WARNING("truncated log entry found");
212 		delete_log_entry(j);
213 		j = NULL;
214 	}
215 	READUNLOCK(this, j, "ru db_dictlog::get");
216 	return (j);
217 }
218 
219 /* Append given log entry to log. */
220 int
append(db_dictlog_entry * j)221 db_dictlog::append(db_dictlog_entry *j)
222 {
223 	int status;
224 
225 	WRITELOCK(this, -1, "w db_dictlog::append");
226 	if (mode != PICKLE_APPEND) {
227 		WRITEUNLOCK(this, -1, "wu db_dictlog::append");
228 		return (-1);
229 	}
230 
231 	/* xdr returns TRUE if successful, FALSE otherwise */
232 	status = ((xdr_db_dictlog_entry(&(xdr), j)) ? 0 : -1);
233 	if (status < 0) {
234 		WARNING("db_dictlog: could not write log entry");
235 		WRITEUNLOCK(this, status, "wu db_dictlog::append");
236 		return (status);
237 	}
238 
239 	status = fflush(file);
240 	if (status < 0) {
241 		WARNING("db_dictlog: could not flush log entry to disk");
242 		WRITEUNLOCK(this, status, "wu db_dictlog::append");
243 		return (status);
244 	}
245 
246 	status = fsync(fileno(file));
247 	if (status < 0) {
248 		WARNING("db_dictlog: could not sync log entry to disk");
249 	}
250 
251 	WRITEUNLOCK(this, status, "wu db_dictlog::append");
252 	return (status);
253 }
254