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