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