xref: /illumos-gate/usr/src/cmd/fs.d/nfs/nfslog/nfslog_elf.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * nfs log - read buffer file and print structs in user-readable form
28  */
29 
30 #define	_REENTRANT
31 
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <time.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/param.h>
45 #include <sys/utsname.h>
46 #include <errno.h>
47 #include <time.h>
48 #include <limits.h>
49 #include <libintl.h>
50 #include <pwd.h>
51 #include <netdb.h>
52 #include <syslog.h>
53 #include <rpc/rpc.h>
54 #include <netconfig.h>
55 #include <netdir.h>
56 #include <nfs/nfs_sec.h>
57 #include <nfs/export.h>
58 #include <rpc/auth.h>
59 #include <rpc/svc.h>
60 #include <rpc/xdr.h>
61 #include <rpc/clnt.h>
62 #include <nfs/nfs.h>
63 #include <nfs/nfs_log.h>
64 #include "fhtab.h"
65 #include "nfslogd.h"
66 
67 static char	empty_name[4] = "-";
68 
69 static char ftype3_names[NF3FIFO + 1][20] = {
70 	"\"none\"", "\"file\"", "\"dir\"", "\"blk device\"",
71 	"\"chr device\"", "\"link\"", "\"socket\"", "\"fifo\""
72 };
73 
74 #define	NFSL_FTYPE3(ftype)						\
75 	((((ftype) >= 0) && ((ftype) <= NF3FIFO)) ?			\
76 	ftype3_names[ftype] : empty_name)
77 
78 static char createmode3_names[EXCLUSIVE + 1][20] = {
79 	"\"unchecked", "\"guarded\"", "\"exclusive\""
80 };
81 
82 #define	NFSL_CREATEMODE3(createmode)					\
83 	((((createmode) >= 0) && ((createmode) <= EXCLUSIVE)) ?		\
84 	createmode3_names[createmode] : empty_name)
85 
86 static char	auth_flavor_name[RPCSEC_GSS + 1][20] = {
87 	"\"auth_null\"", "\"auth_unix\"", "\"auth_short\"", "\"auth_des\"",
88 	"\"auth_kerb\"", "\"none\"", "\"rpcsec_gss\""
89 };
90 
91 #define	NFSL_AUTH_FLAVOR_PRINT(auth_flavor)				\
92 	(((auth_flavor) <= RPCSEC_GSS) ?				\
93 	auth_flavor_name[auth_flavor] : empty_name)
94 
95 #define	NFSL_ERR_CNT		31	/* Actual err numbers */
96 
97 /*
98  * Two arrays - one short ints containing err codes, the other the strings
99  * (merged codes for both v2 and v3
100  */
101 static char	nfsl_status_name[NFSL_ERR_CNT][30] = {
102 	"\"ok\"", "\"perm\"", "\"noent\"", "\"io\"",
103 	"\"nxio\"", "\"access\"", "\"exist\"", "\"xdev\"",
104 	"\"nodev\"", "\"notdir\"", "\"isdir\"", "\"inval\"",
105 	"\"fbig\"", "\"nospc\"", "\"rofs\"", "\"mlink\"",
106 	"\"notsupp\"", "\"nametoolong\"", "\"notempty\"", "\"dquot\"",
107 	"\"stale\"", "\"remote\"", "\"wflush\"", "\"badhandle\"",
108 	"\"not_sync\"", "\"bad_cookie\"", "\"notsupp\"", "\"toosmall\"",
109 	"\"serverfault\"", "\"badtype\"", "\"jukebox\"",
110 };
111 
112 static short	nfsl_status[NFSL_ERR_CNT] = {
113 	0, 1, 2, 5, 6, 13, 17, 18,
114 	19, 20, 21, 22, 27, 28, 30, 31,
115 	45, 63, 66, 69, 70, 71, 99, 10001,
116 	10002, 10003, 10004, 10005, 10006, 10007, 10008
117 };
118 
119 /* list of open elf files */
120 static struct nfsl_log_file	*elf_file_list = NULL;
121 
122 /* Imported functions */
123 extern void bcopy(const void *s1, void *s2, size_t n);
124 
125 /* Static functions */
126 static void nfsl_log_file_free(struct nfsl_log_file *elfrec);
127 static void nfsl_log_file_add(struct nfsl_log_file *elfrec,
128 	struct nfsl_log_file **elf_listp);
129 static struct nfsl_log_file *nfsl_log_file_find(struct nfsl_log_file *elfrec,
130 	struct nfsl_log_file *elf_list);
131 static struct nfsl_log_file *nfsl_log_file_del(struct nfsl_log_file *elfrec,
132 	struct nfsl_log_file **elf_listp);
133 
134 static char *nfsl_get_time(time_t tt);
135 static char *nfsl_get_date(time_t tt);
136 static char *nfsl_get_date_nq(time_t tt);
137 static int nfsl_write_elfbuf(struct nfsl_log_file *elfrec);
138 static void nfsl_ipaddr_print(struct nfsl_log_file *, struct netbuf *);
139 static void nfsl_elf_record_header_print(struct nfsl_log_file *,
140 		nfslog_record_header *, char *, char *,
141 		struct nfsl_proc_disp *, char *);
142 static void nfsl_elf_buffer_header_print(struct nfsl_log_file *,
143 		nfslog_buffer_header *);
144 static struct nfsl_proc_disp *nfsl_find_elf_dispatch(
145 		nfslog_request_record *, char **);
146 static void nfsl_elf_rpc_print(struct nfsl_log_file *,
147 		nfslog_request_record *, struct nfsl_proc_disp *,
148 		char *, char *, char *);
149 static void nfslog_size3_print(struct nfsl_log_file *, set_size3 *);
150 
151 static void nfslog_null_args(struct nfsl_log_file *, caddr_t *);
152 static void nfslog_null_res(struct nfsl_log_file *, caddr_t *);
153 
154 
155 /*
156  * NFS VERSION 2
157  */
158 
159 /* Functions for elf print of the arguments */
160 static void nfslog_fhandle_print(struct nfsl_log_file *, fhandle_t *);
161 static void nfslog_diropargs_print(struct nfsl_log_file *, nfslog_diropargs *);
162 static void nfslog_setattrargs_print(struct nfsl_log_file *,
163 	nfslog_setattrargs *);
164 static void nfslog_sattr_print(struct nfsl_log_file *,
165 	nfslog_sattr *);
166 static void nfslog_nfsreadargs_print(struct nfsl_log_file *,
167 	nfslog_nfsreadargs *);
168 static void nfslog_writeargs_print(struct nfsl_log_file *,
169 	nfslog_writeargs *);
170 static void nfslog_writeresult_print(struct nfsl_log_file *,
171 	nfslog_writeresult *, bool_t);
172 static void nfslog_creatargs_print(struct nfsl_log_file *,
173 	nfslog_createargs *);
174 static void nfslog_rddirargs_print(struct nfsl_log_file *, nfslog_rddirargs *);
175 static void nfslog_linkargs_print(struct nfsl_log_file *, nfslog_linkargs *);
176 static void nfslog_rnmargs_print(struct nfsl_log_file *, nfslog_rnmargs *);
177 static void nfslog_symlinkargs_print(struct nfsl_log_file *,
178 	nfslog_symlinkargs *);
179 
180 static void nfslog_sharefsargs_print(struct nfsl_log_file *,
181 	nfslog_sharefsargs *);
182 static void nfslog_getfhargs_print(struct nfsl_log_file *,
183 	nfslog_getfhargs *);
184 
185 /* Functions for elf print of the response */
186 static void nfslog_nfsstat_print(struct nfsl_log_file *, enum nfsstat *,
187 	bool_t);
188 static void nfslog_diropres_print(struct nfsl_log_file *, nfslog_diropres *,
189 	bool_t);
190 static void nfslog_rdlnres_print(struct nfsl_log_file *, nfslog_rdlnres *,
191 	bool_t);
192 static void nfslog_rdresult_print(struct nfsl_log_file *,
193 	nfslog_rdresult *, bool_t);
194 static void nfslog_rddirres_print(struct nfsl_log_file *, nfslog_rddirres *,
195 	bool_t);
196 
197 /*
198  * NFS VERSION 3
199  */
200 
201 /* Functions for elf print of the arguments */
202 static void nfslog_fh3_print(struct nfsl_log_file *, nfs_fh3 *);
203 static void nfslog_diropargs3_print(struct nfsl_log_file *,
204 	nfslog_diropargs3 *);
205 static void nfslog_SETATTR3args_print(struct nfsl_log_file *,
206 	nfslog_SETATTR3args *);
207 static void nfslog_READ3args_print(struct nfsl_log_file *, nfslog_READ3args *);
208 static void nfslog_WRITE3args_print(struct nfsl_log_file *,
209 	nfslog_WRITE3args *);
210 static void nfslog_CREATE3args_print(struct nfsl_log_file *,
211 	nfslog_CREATE3args *);
212 static void nfslog_MKDIR3args_print(struct nfsl_log_file *,
213 	nfslog_MKDIR3args *);
214 static void nfslog_SYMLINK3args_print(struct nfsl_log_file *,
215 	nfslog_SYMLINK3args *);
216 static void nfslog_MKNOD3args_print(struct nfsl_log_file *,
217 	nfslog_MKNOD3args *);
218 static void nfslog_REMOVE3args_print(struct nfsl_log_file *,
219 	nfslog_REMOVE3args *);
220 static void nfslog_RMDIR3args_print(struct nfsl_log_file *,
221 	nfslog_RMDIR3args *);
222 static void nfslog_RENAME3args_print(struct nfsl_log_file *,
223 	nfslog_RENAME3args *);
224 static void nfslog_LINK3args_print(struct nfsl_log_file *,
225 	nfslog_LINK3args *);
226 static void nfslog_COMMIT3args_print(struct nfsl_log_file *,
227 	nfslog_COMMIT3args *);
228 static void nfslog_READDIRPLUS3args_print(struct nfsl_log_file *,
229 	nfslog_READDIRPLUS3args *);
230 
231 /* Functions for elf print of the response */
232 static void nfslog_nfsstat3_print(struct nfsl_log_file *,
233 	nfsstat3 *, bool_t);
234 static void nfslog_LOOKUP3res_print(struct nfsl_log_file *,
235 	nfslog_LOOKUP3res *, bool_t);
236 static void nfslog_READLINK3res_print(struct nfsl_log_file *,
237 	nfslog_READLINK3res *, bool_t);
238 static void nfslog_READ3res_print(struct nfsl_log_file *,
239 	nfslog_READ3res *, bool_t);
240 static void nfslog_WRITE3res_print(struct nfsl_log_file *,
241 	nfslog_WRITE3res *, bool_t);
242 static void nfslog_CREATE3res_print(struct nfsl_log_file *,
243 	nfslog_CREATE3res *, bool_t);
244 static void nfslog_MKDIR3res_print(struct nfsl_log_file *,
245 	nfslog_MKDIR3res *, bool_t);
246 static void nfslog_SYMLINK3res_print(struct nfsl_log_file *,
247 	nfslog_SYMLINK3res *, bool_t);
248 static void nfslog_MKNOD3res_print(struct nfsl_log_file *,
249 	nfslog_MKNOD3res *, bool_t);
250 static void nfslog_READDIRPLUS3res_print(struct nfsl_log_file *,
251 	nfslog_READDIRPLUS3res *, bool_t);
252 
253 extern int debug;
254 static bool_t nfsl_print_fh = FALSE;		/* print file handles? */
255 
256 #define	DFLT_BUFFERSIZE		8192
257 #define	DFLT_OVFSIZE		3072	/* Maximum logged or buffered size */
258 
259 static char hostname[MAXHOSTNAMELEN];	/* name of host */
260 
261 
262 /*
263  * Define the actions taken per prog/vers/proc:
264  *
265  * In some cases, the nl types are the same as the nfs types and a simple
266  * bcopy should suffice. Rather that define tens of identical procedures,
267  * simply define these to bcopy. Similarly this takes care of different
268  * procs that use same parameter struct.
269  */
270 
271 static struct nfsl_proc_disp nfsl_elf_proc_v2[] = {
272 	/*
273 	 * NFS VERSION 2
274 	 */
275 
276 	/* RFS_NULL = 0 */
277 	{nfslog_null_args, nfslog_null_res, "\"null\""},
278 
279 	/* RFS_GETATTR = 1 */
280 	{nfslog_fhandle_print, nfslog_nfsstat_print, "\"getattr\""},
281 
282 	/* RFS_SETATTR = 2 */
283 	{nfslog_setattrargs_print, nfslog_nfsstat_print, "\"setattr\""},
284 
285 	/* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
286 	{nfslog_null_args, nfslog_null_res, "\"root\""},
287 
288 	/* RFS_LOOKUP = 4 */
289 	{nfslog_diropargs_print, nfslog_diropres_print, "\"lookup\""},
290 
291 	/* RFS_READLINK = 5 */
292 	{nfslog_fhandle_print, nfslog_rdlnres_print, "\"readlink\""},
293 
294 	/* RFS_READ = 6 */
295 	{nfslog_nfsreadargs_print, nfslog_rdresult_print, "\"read\""},
296 
297 	/* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
298 	{nfslog_null_args, nfslog_null_res, "\"writecache\""},
299 
300 	/* RFS_WRITE = 8 */
301 	{nfslog_writeargs_print, nfslog_writeresult_print, "\"write\""},
302 
303 	/* RFS_CREATE = 9 */
304 	{nfslog_creatargs_print, nfslog_diropres_print, "\"create\""},
305 
306 	/* RFS_REMOVE = 10 */
307 	{nfslog_diropargs_print, nfslog_nfsstat_print, "\"remove\""},
308 
309 	/* RFS_RENAME = 11 */
310 	{nfslog_rnmargs_print, nfslog_nfsstat_print, "\"rename\""},
311 
312 	/* RFS_LINK = 12 */
313 	{nfslog_linkargs_print, nfslog_nfsstat_print, "\"link\""},
314 
315 	/* RFS_SYMLINK = 13 */
316 	{nfslog_symlinkargs_print, nfslog_nfsstat_print, "\"symlink\""},
317 
318 	/* RFS_MKDIR = 14 */
319 	{nfslog_creatargs_print, nfslog_diropres_print, "\"mkdir\""},
320 
321 	/* RFS_RMDIR = 15 */
322 	{nfslog_diropargs_print, nfslog_nfsstat_print, "\"rmdir\""},
323 
324 	/* RFS_READDIR = 16 */
325 	{nfslog_rddirargs_print, nfslog_rddirres_print, "\"readdir\""},
326 
327 	/* RFS_STATFS = 17 */
328 	{nfslog_fhandle_print, nfslog_nfsstat_print, "\"statfs\""},
329 };
330 
331 
332 /*
333  * NFS VERSION 3
334  */
335 
336 static struct nfsl_proc_disp nfsl_elf_proc_v3[] = {
337 
338 	/* NFSPROC3_NULL = 0 */
339 	{nfslog_null_args, nfslog_null_res, "\"null\""},
340 
341 	/* NFSPROC3_GETATTR = 1 */
342 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"getattr\""},
343 
344 	/* NFSPROC3_SETATTR = 2 */
345 	{nfslog_SETATTR3args_print, nfslog_nfsstat3_print, "\"setattr\""},
346 
347 	/* NFSPROC3_LOOKUP = 3 */
348 	{nfslog_diropargs3_print, nfslog_LOOKUP3res_print, "\"lookup\""},
349 
350 	/* NFSPROC3_ACCESS = 4 */
351 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"access\""},
352 
353 	/* NFSPROC3_READLINK = 5 */
354 	{nfslog_fh3_print, nfslog_READLINK3res_print, "\"readlink\""},
355 
356 	/* NFSPROC3_READ = 6 */
357 	{nfslog_READ3args_print, nfslog_READ3res_print, "\"read\""},
358 
359 	/* NFSPROC3_WRITE = 7 */
360 	{nfslog_WRITE3args_print, nfslog_WRITE3res_print, "\"write\""},
361 
362 	/* NFSPROC3_CREATE = 8 */
363 	{nfslog_CREATE3args_print, nfslog_CREATE3res_print, "\"create\""},
364 
365 	/* NFSPROC3_MKDIR = 9 */
366 	{nfslog_MKDIR3args_print, nfslog_MKDIR3res_print, "\"mkdir\""},
367 
368 	/* NFSPROC3_SYMLINK = 10 */
369 	{nfslog_SYMLINK3args_print, nfslog_SYMLINK3res_print, "\"symlink\""},
370 
371 	/* NFSPROC3_MKNOD = 11 */
372 	{nfslog_MKNOD3args_print, nfslog_MKNOD3res_print, "\"mknod\""},
373 
374 	/* NFSPROC3_REMOVE = 12 */
375 	{nfslog_REMOVE3args_print, nfslog_nfsstat3_print, "\"remove\""},
376 
377 	/* NFSPROC3_RMDIR = 13 */
378 	{nfslog_RMDIR3args_print, nfslog_nfsstat3_print, "\"rmdir\""},
379 
380 	/* NFSPROC3_RENAME = 14 */
381 	{nfslog_RENAME3args_print, nfslog_nfsstat3_print, "\"rename\""},
382 
383 	/* NFSPROC3_LINK = 15 */
384 	{nfslog_LINK3args_print, nfslog_nfsstat3_print, "\"link\""},
385 
386 	/* NFSPROC3_READDIR = 16 */
387 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"readdir\""},
388 
389 	/* NFSPROC3_READDIRPLUS = 17 */
390 	{nfslog_READDIRPLUS3args_print, nfslog_READDIRPLUS3res_print,
391 		"\"readdirplus\""},
392 
393 	/* NFSPROC3_FSSTAT = 18 */
394 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"fsstat\""},
395 
396 	/* NFSPROC3_FSINFO = 19 */
397 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"fsinfo\""},
398 
399 	/* NFSPROC3_PATHCONF = 20 */
400 	{nfslog_fh3_print, nfslog_nfsstat3_print, "\"pathconf\""},
401 
402 	/* NFSPROC3_COMMIT = 21 */
403 	{nfslog_COMMIT3args_print, nfslog_nfsstat3_print, "\"commit\""},
404 };
405 
406 /*
407  * NFSLOG VERSION 1
408  */
409 
410 static struct nfsl_proc_disp nfsl_log_elf_proc_v1[] = {
411 
412 	/* NFSLOG_NULL = 0 */
413 	{nfslog_null_args, nfslog_null_res, "\"null\""},
414 
415 	/* NFSLOG_SHARE = 1 */
416 	{nfslog_sharefsargs_print, nfslog_nfsstat_print, "\"log_share\""},
417 
418 	/* NFSLOG_UNSHARE = 2 */
419 	{nfslog_sharefsargs_print, nfslog_nfsstat_print, "\"log_unshare\""},
420 
421 	/* NFSLOG_LOOKUP = 3 */
422 	{nfslog_diropargs3_print, nfslog_LOOKUP3res_print, "\"lookup\""},
423 
424 	/* NFSLOG_GETFH = 4 */
425 	{nfslog_getfhargs_print, nfslog_nfsstat_print, "\"log_getfh\""},
426 };
427 
428 static struct nfsl_vers_disp nfsl_elf_vers_disptable[] = {
429 	{sizeof (nfsl_elf_proc_v2) / sizeof (nfsl_elf_proc_v2[0]),
430 	    nfsl_elf_proc_v2},
431 	{sizeof (nfsl_elf_proc_v3) / sizeof (nfsl_elf_proc_v3[0]),
432 	    nfsl_elf_proc_v3},
433 };
434 
435 static struct nfsl_vers_disp nfsl_log_elf_vers_disptable[] = {
436 	{sizeof (nfsl_log_elf_proc_v1) / sizeof (nfsl_log_elf_proc_v1[0]),
437 	    nfsl_log_elf_proc_v1},
438 };
439 
440 static struct nfsl_prog_disp nfsl_elf_dispatch_table[] = {
441 	{NFS_PROGRAM,
442 	    NFS_VERSMIN,
443 	    sizeof (nfsl_elf_vers_disptable) /
444 		sizeof (nfsl_elf_vers_disptable[0]),
445 	    nfsl_elf_vers_disptable, "nfs"},
446 	{NFSLOG_PROGRAM,
447 	    NFSLOG_VERSMIN,
448 	    sizeof (nfsl_log_elf_vers_disptable) /
449 		sizeof (nfsl_log_elf_vers_disptable[0]),
450 	    nfsl_log_elf_vers_disptable, "nfslog"},
451 };
452 
453 static int	nfsl_elf_dispatch_table_arglen =
454 			sizeof (nfsl_elf_dispatch_table) /
455 			sizeof (nfsl_elf_dispatch_table[0]);
456 
457 static char *
458 nfslog_get_status(short status)
459 {
460 	int	low, mid, high;
461 	short	errstat;
462 
463 	/* Usually status is 0... */
464 	if (status == 0)
465 		return (nfsl_status_name[0]);
466 
467 	low = 0;
468 	high = NFSL_ERR_CNT;
469 	mid = NFSL_ERR_CNT / 2;
470 	/* binary search for status string */
471 	while (((errstat = nfsl_status[mid]) != status) && (low < mid) &&
472 		(mid < high)) {
473 		if (errstat > status) {	/* search bottom half */
474 			high = mid;
475 		} else {		/* search upper half */
476 			low = mid;
477 		}
478 		mid = low + ((high - low) / 2);
479 	}
480 	if (errstat == status) {	/* found it */
481 		return (nfsl_status_name[mid]);
482 	}
483 	return (NULL);
484 }
485 
486 /* nfsl_get_time - return string with time formatted as hh:mm:ss */
487 static char *
488 nfsl_get_time(time_t tt)
489 {
490 	static char	timestr[20];
491 	static time_t	lasttime;
492 	struct tm	tmst;
493 
494 	if (tt == lasttime)
495 		return (timestr);
496 	if (localtime_r(&tt, &tmst) == NULL) {
497 		return (empty_name);
498 	}
499 	(void) sprintf(timestr, "%02d:%02d:%02d",
500 		tmst.tm_hour, tmst.tm_min, tmst.tm_sec);
501 	lasttime = tt;
502 	return (timestr);
503 }
504 
505 /* nfsl_get_date - return date string formatted as "yyyy-mm-dd hh:mm:ss" */
506 static char *
507 nfsl_get_date(time_t tt)
508 {
509 	static char	timestr[30];
510 	static time_t	lasttime;
511 	struct tm	tmst;
512 
513 	if (tt == lasttime)
514 		return (timestr);
515 	if (localtime_r(&tt, &tmst) == NULL) {
516 		return (empty_name);
517 	}
518 	(void) sprintf(timestr, "\"%04d-%02d-%02d %02d:%02d:%02d\"",
519 		tmst.tm_year + 1900, tmst.tm_mon + 1, tmst.tm_mday,
520 		tmst.tm_hour, tmst.tm_min, tmst.tm_sec);
521 	lasttime = tt;
522 	return (timestr);
523 }
524 
525 /*
526  * nfsl_get_date_nq - return date string formatted as yyyy-mm-dd hh:mm:ss
527  * (no quotes)
528  */
529 static char *
530 nfsl_get_date_nq(time_t tt)
531 {
532 	static char	timestr[30];
533 	static time_t	lasttime;
534 	struct tm	tmst;
535 
536 	if (tt == lasttime)
537 		return (timestr);
538 	if (localtime_r(&tt, &tmst) == NULL) {
539 		return (empty_name);
540 	}
541 	(void) sprintf(timestr, "%04d-%02d-%02d %02d:%02d:%02d",
542 		tmst.tm_year + 1900, tmst.tm_mon + 1, tmst.tm_mday,
543 		tmst.tm_hour, tmst.tm_min, tmst.tm_sec);
544 	return (timestr);
545 }
546 
547 /* write log buffer out to file */
548 static int
549 nfsl_write_elfbuf(struct nfsl_log_file *elfrec)
550 {
551 	int	rc;
552 	char	*elfbuf = elfrec->buf;
553 	int	elfbufoffset = elfrec->bufoffset;
554 
555 	if (debug > 1)
556 		(void) printf("nfsl_write_elfbuf: bufoffset %d\n",
557 			elfbufoffset);
558 	if (elfbufoffset <= 0)
559 		return (0);
560 	elfbuf[elfbufoffset] = '\0';
561 	if ((rc = fputs(elfbuf, elfrec->fp)) < 0) {
562 		syslog(LOG_ERR, gettext("Write to %s failed: %s\n"),
563 			elfrec->path, strerror(errno));
564 		return (-1);
565 	}
566 	if (rc != elfbufoffset) {
567 		syslog(LOG_ERR, gettext("Write %d bytes to %s returned %d\n"),
568 			elfbufoffset, elfrec->path, rc);
569 		return (-1);
570 	}
571 	elfrec->bufoffset = 0;
572 	return (0);
573 }
574 
575 /*ARGSUSED*/
576 static void
577 nfslog_null_args(struct nfsl_log_file *elfrec, caddr_t *nfsl_args)
578 {
579 }
580 
581 /*ARGSUSED*/
582 static void
583 nfslog_null_res(struct nfsl_log_file *elfrec, caddr_t *nfsl_res)
584 {
585 }
586 
587 static void
588 nfslog_fh3_print(struct nfsl_log_file *elfrec, nfs_fh3 *fh3)
589 {
590 	if (!nfsl_print_fh)
591 		return;
592 	if (fh3->fh3_length == sizeof (fhandle_t)) {
593 		nfslog_fhandle_print(elfrec, (fhandle_t *)&fh3->fh3_u.data);
594 	} else {
595 		nfslog_opaque_print_buf(fh3->fh3_u.data, fh3->fh3_length,
596 			elfrec->buf, &elfrec->bufoffset,
597 			DFLT_BUFFERSIZE + DFLT_OVFSIZE);
598 	}
599 }
600 
601 /*
602  * NFS VERSION 2
603  */
604 
605 
606 /* Functions that elf print the arguments */
607 
608 static void
609 nfslog_fhandle_print(struct nfsl_log_file *elfrec, fhandle_t *args)
610 {
611 	if (!nfsl_print_fh)
612 		return;
613 	nfslog_opaque_print_buf(args, sizeof (*args),
614 			elfrec->buf, &elfrec->bufoffset,
615 			DFLT_BUFFERSIZE + DFLT_OVFSIZE);
616 }
617 
618 static void
619 nfslog_diropargs_print(struct nfsl_log_file *elfrec, nfslog_diropargs *args)
620 {
621 	char	*elfbuf = elfrec->buf;
622 	int	elfbufoffset = elfrec->bufoffset;
623 
624 	if (nfsl_print_fh) {
625 		nfslog_fhandle_print(elfrec, &args->da_fhandle);
626 		elfbufoffset = elfrec->bufoffset;
627 		if (args->da_name != NULL) {
628 			elfbufoffset += sprintf(&elfbuf[elfbufoffset],
629 				" \"%s\"", args->da_name);
630 		} else {
631 			elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
632 				empty_name);
633 		}
634 	}
635 	elfrec->bufoffset = elfbufoffset;
636 }
637 
638 static void
639 nfslog_sattr_print(struct nfsl_log_file *elfrec, nfslog_sattr *args)
640 {
641 	char	*elfbuf = elfrec->buf;
642 	int	elfbufoffset = elfrec->bufoffset;
643 
644 /* BEGIN CSTYLED */
645 	if (args->sa_mode != (uint32_t)-1) {
646 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
647 			" \"mode=0%o\"", args->sa_mode);
648 	}
649 	if (args->sa_uid != (uint32_t)-1) {
650 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
651 			" \"uid=0x%x\"", args->sa_uid);
652 	}
653 	if (args->sa_gid != (uint32_t)-1) {
654 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
655 			" \"gid=0x%x\"", args->sa_gid);
656 	}
657 	if (args->sa_size != (uint32_t)-1) {
658 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
659 			" \"size=0x%x\"", args->sa_size);
660 	}
661 	if (args->sa_atime.tv_sec != (uint32_t)-1) {
662 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
663 			" \"atime=%s\"",
664 		    nfsl_get_date_nq((time_t)args->sa_atime.tv_sec));
665 	}
666 	if (args->sa_mtime.tv_sec != (uint32_t)-1) {
667 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
668 			" \"mtime=%s\"",
669 		    nfsl_get_date_nq((time_t)args->sa_mtime.tv_sec));
670 	}
671 /* END CSTYLED */
672 	elfrec->bufoffset = elfbufoffset;
673 }
674 
675 static void
676 nfslog_setattrargs_print(struct nfsl_log_file *elfrec, nfslog_setattrargs *args)
677 {
678 	nfslog_fhandle_print(elfrec, &args->saa_fh);
679 	nfslog_sattr_print(elfrec, &args->saa_sa);
680 }
681 
682 static void
683 nfslog_nfsreadargs_print(struct nfsl_log_file *elfrec,
684 	nfslog_nfsreadargs *args)
685 {
686 	char	*elfbuf = elfrec->buf;
687 	int	elfbufoffset;
688 
689 	nfslog_fhandle_print(elfrec, &args->ra_fhandle);
690 	elfbufoffset = elfrec->bufoffset;
691 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
692 		args->ra_offset);
693 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
694 		args->ra_count);
695 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
696 		args->ra_totcount);
697 	elfrec->bufoffset = elfbufoffset;
698 }
699 
700 static void
701 nfslog_writeargs_print(struct nfsl_log_file *elfrec, nfslog_writeargs *args)
702 {
703 	char	*elfbuf = elfrec->buf;
704 	int	elfbufoffset = elfrec->bufoffset;
705 
706 	nfslog_fhandle_print(elfrec, &args->waargs_fhandle);
707 	elfbufoffset = elfrec->bufoffset;
708 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
709 		args->waargs_begoff);
710 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
711 		args->waargs_offset);
712 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
713 		args->waargs_totcount);
714 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%x",
715 		args->waargs_count);
716 }
717 
718 static void
719 nfslog_writeresult_print(struct nfsl_log_file *elfrec, nfslog_writeresult *res,
720 	bool_t print_status)
721 {
722 	char	*elfbuf = elfrec->buf;
723 	int	elfbufoffset = elfrec->bufoffset;
724 
725 	if (print_status) {
726 		nfslog_nfsstat_print(elfrec, &res->wr_status, print_status);
727 	} else if (res->wr_status == NFS_OK) {
728 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
729 			res->nfslog_writeresult_u.wr_size);
730 		elfrec->bufoffset = elfbufoffset;
731 	}
732 }
733 
734 static void
735 nfslog_creatargs_print(struct nfsl_log_file *elfrec, nfslog_createargs *args)
736 {
737 	nfslog_diropargs_print(elfrec, &args->ca_da);
738 	nfslog_sattr_print(elfrec, &args->ca_sa);
739 }
740 
741 
742 static void
743 nfslog_rddirargs_print(struct nfsl_log_file *elfrec, nfslog_rddirargs *args)
744 {
745 	char	*elfbuf = elfrec->buf;
746 	int	elfbufoffset;
747 
748 	nfslog_fhandle_print(elfrec, &args->rda_fh);
749 	elfbufoffset = elfrec->bufoffset;
750 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
751 		args->rda_offset);
752 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
753 		args->rda_count);
754 	elfrec->bufoffset = elfbufoffset;
755 }
756 
757 static void
758 nfslog_rnmargs_print(struct nfsl_log_file *elfrec, nfslog_rnmargs *args)
759 {
760 	nfslog_diropargs_print(elfrec, &args->rna_from);
761 	nfslog_diropargs_print(elfrec, &args->rna_to);
762 }
763 
764 static void
765 nfslog_linkargs_print(struct nfsl_log_file *elfrec, nfslog_linkargs *args)
766 {
767 	nfslog_fhandle_print(elfrec, &args->la_from);
768 	nfslog_diropargs_print(elfrec, &args->la_to);
769 }
770 
771 static void
772 nfslog_symlinkargs_print(struct nfsl_log_file *elfrec, nfslog_symlinkargs *args)
773 {
774 	char	*elfbuf = elfrec->buf;
775 	int	elfbufoffset;
776 
777 	nfslog_diropargs_print(elfrec, &args->sla_from);
778 	elfbufoffset = elfrec->bufoffset;
779 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " \"%s\"",
780 		args->sla_tnm);
781 	elfrec->bufoffset = elfbufoffset;
782 	nfslog_sattr_print(elfrec, &args->sla_sa);
783 }
784 
785 /*
786  * SHARE/UNSHARE fs log args copy
787  */
788 static void
789 nfslog_sharefsargs_print(struct nfsl_log_file *elfrec,
790 	nfslog_sharefsargs *args)
791 {
792 	unsigned int	elfbufoffset;
793 	char		*elfbuf = elfrec->buf;
794 
795 	nfslog_fhandle_print(elfrec, &args->sh_fh_buf);
796 
797 	elfbufoffset = elfrec->bufoffset;
798 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
799 		args->sh_flags);
800 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
801 		args->sh_anon);
802 	if (nfsl_print_fh) {
803 		if (args->sh_path != NULL) {
804 			elfbufoffset += sprintf(&elfbuf[elfbufoffset],
805 				" \"%s\"", args->sh_path);
806 		} else {
807 			elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
808 				empty_name);
809 		}
810 	}
811 	elfrec->bufoffset = elfbufoffset;
812 }
813 
814 static void
815 nfslog_getfhargs_print(struct nfsl_log_file *elfrec,
816 	nfslog_getfhargs *args)
817 {
818 	unsigned int	elfbufoffset;
819 	char		*elfbuf = elfrec->buf;
820 
821 	nfslog_fhandle_print(elfrec, &args->gfh_fh_buf);
822 
823 	elfbufoffset = elfrec->bufoffset;
824 	if (nfsl_print_fh) {
825 		if (args->gfh_path != NULL) {
826 			elfbufoffset += sprintf(&elfbuf[elfbufoffset],
827 				" \"%s\"", args->gfh_path);
828 		} else {
829 			elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
830 				empty_name);
831 		}
832 	}
833 	elfrec->bufoffset = elfbufoffset;
834 }
835 
836 static void
837 nfslog_nfsstat_print(struct nfsl_log_file *elfrec, enum nfsstat *res,
838 	bool_t print_status)
839 {
840 	if (print_status) {
841 		char	*statp = nfslog_get_status((short)(*res));
842 
843 		if (statp != NULL)
844 			elfrec->bufoffset +=
845 				sprintf(&elfrec->buf[elfrec->bufoffset], " %s",
846 						statp);
847 		else
848 			elfrec->bufoffset +=
849 				sprintf(&elfrec->buf[elfrec->bufoffset], " %5d",
850 						*res);
851 	}
852 }
853 
854 static void
855 nfslog_diropres_print(struct nfsl_log_file *elfrec, nfslog_diropres *res,
856 	bool_t print_status)
857 {
858 	if (print_status) {
859 		nfslog_nfsstat_print(elfrec, &res->dr_status, print_status);
860 	} else if (res->dr_status == NFS_OK) {
861 		nfslog_fhandle_print(elfrec,
862 			&res->nfslog_diropres_u.dr_ok.drok_fhandle);
863 	}
864 }
865 
866 static void
867 nfslog_rdlnres_print(struct nfsl_log_file *elfrec, nfslog_rdlnres *res,
868 	bool_t print_status)
869 {
870 	if (print_status) {
871 		nfslog_nfsstat_print(elfrec, &res->rl_status, print_status);
872 	} else if (res->rl_status == NFS_OK) {
873 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
874 			" \"%s\"", res->nfslog_rdlnres_u.rl_ok);
875 	}
876 }
877 
878 static void
879 nfslog_rdresult_print(struct nfsl_log_file *elfrec, nfslog_rdresult *res,
880 	bool_t print_status)
881 {
882 	if (print_status) {
883 		nfslog_nfsstat_print(elfrec, &res->r_status, print_status);
884 	} else if (res->r_status == NFS_OK) {
885 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
886 			" 0x%x", res->nfslog_rdresult_u.r_ok.filesize);
887 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
888 			" 0x%x", res->nfslog_rdresult_u.r_ok.rrok_count);
889 	}
890 }
891 
892 static void
893 nfslog_rddirres_print(struct nfsl_log_file *elfrec, nfslog_rddirres *res,
894 	bool_t print_status)
895 {
896 	if (print_status) {
897 		nfslog_nfsstat_print(elfrec, &res->rd_status, print_status);
898 	} else if (res->rd_status == NFS_OK) {
899 		char	*elfbuf = elfrec->buf;
900 		int	elfbufoffset = elfrec->bufoffset;
901 
902 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
903 			res->nfslog_rddirres_u.rd_ok.rdok_offset);
904 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
905 			res->nfslog_rddirres_u.rd_ok.rdok_size);
906 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
907 			res->nfslog_rddirres_u.rd_ok.rdok_eof);
908 		elfrec->bufoffset = elfbufoffset;
909 	}
910 }
911 
912 /*
913  * NFS VERSION 3
914  */
915 
916 static void
917 nfslog_diropargs3_print(struct nfsl_log_file *elfrec,
918 	nfslog_diropargs3 *args)
919 {
920 	if (nfsl_print_fh) {
921 		nfslog_fh3_print(elfrec, &args->dir);
922 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
923 			" \"%s\"", args->name);
924 	}
925 }
926 
927 static void
928 nfslog_size3_print(struct nfsl_log_file *elfrec, set_size3 *args)
929 {
930 	char	*elfbuf = elfrec->buf;
931 	int	elfbufoffset = elfrec->bufoffset;
932 
933 	if (args->set_it) {
934 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
935 		/* CSTYLED */
936 			" \"size=0x%llx\"", args->size);
937 	}
938 	elfrec->bufoffset = elfbufoffset;
939 }
940 
941 static void
942 nfslog_SETATTR3args_print(struct nfsl_log_file *elfrec,
943 	nfslog_SETATTR3args *args)
944 {
945 	nfslog_fh3_print(elfrec, &args->object);
946 	nfslog_size3_print(elfrec, &args->size);
947 }
948 
949 static void
950 nfslog_READ3args_print(struct nfsl_log_file *elfrec, nfslog_READ3args *args)
951 {
952 	nfslog_fh3_print(elfrec, &args->file);
953 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%llx",
954 		args->offset);
955 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%x",
956 		args->count);
957 }
958 
959 static void
960 nfslog_WRITE3args_print(struct nfsl_log_file *elfrec,
961 	nfslog_WRITE3args *args)
962 {
963 	char	*elfbuf = elfrec->buf;
964 	int	elfbufoffset;
965 
966 	nfslog_fh3_print(elfrec, &args->file);
967 	elfbufoffset = elfrec->bufoffset;
968 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%llx",
969 		args->offset);
970 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
971 		args->count);
972 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
973 		args->stable);
974 	elfrec->bufoffset = elfbufoffset;
975 }
976 
977 static void
978 nfslog_CREATE3args_print(struct nfsl_log_file *elfrec,
979 	nfslog_CREATE3args *args)
980 {
981 	nfslog_diropargs3_print(elfrec, &args->where);
982 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " %s",
983 		NFSL_CREATEMODE3(args->how.mode));
984 	if (args->how.mode != EXCLUSIVE) {
985 		nfslog_size3_print(elfrec,
986 			&args->how.nfslog_createhow3_u.size);
987 	}
988 }
989 
990 static void
991 nfslog_MKDIR3args_print(struct nfsl_log_file *elfrec,
992 	nfslog_MKDIR3args *args)
993 {
994 	nfslog_diropargs3_print(elfrec, &args->where);
995 }
996 
997 static void
998 nfslog_SYMLINK3args_print(struct nfsl_log_file *elfrec,
999 	nfslog_SYMLINK3args *args)
1000 {
1001 	nfslog_diropargs3_print(elfrec, &args->where);
1002 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1003 		" \"%s\"", args->symlink_data);
1004 }
1005 
1006 static void
1007 nfslog_MKNOD3args_print(struct nfsl_log_file *elfrec,
1008 	nfslog_MKNOD3args *args)
1009 {
1010 	nfslog_diropargs3_print(elfrec, &args->where);
1011 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " %s",
1012 		NFSL_FTYPE3(args->type));
1013 }
1014 
1015 static void
1016 nfslog_REMOVE3args_print(struct nfsl_log_file *elfrec,
1017 	nfslog_REMOVE3args *args)
1018 {
1019 	nfslog_diropargs3_print(elfrec, &args->object);
1020 }
1021 
1022 static void
1023 nfslog_RMDIR3args_print(struct nfsl_log_file *elfrec,
1024 	nfslog_RMDIR3args *args)
1025 {
1026 	nfslog_diropargs3_print(elfrec, &args->object);
1027 }
1028 
1029 static void
1030 nfslog_RENAME3args_print(struct nfsl_log_file *elfrec,
1031 	nfslog_RENAME3args *args)
1032 {
1033 	nfslog_diropargs3_print(elfrec, &args->from);
1034 	nfslog_diropargs3_print(elfrec, &args->to);
1035 }
1036 
1037 static void
1038 nfslog_LINK3args_print(struct nfsl_log_file *elfrec, nfslog_LINK3args *args)
1039 {
1040 	nfslog_fh3_print(elfrec, &args->file);
1041 	nfslog_diropargs3_print(elfrec, &args->link);
1042 }
1043 
1044 static void
1045 nfslog_READDIRPLUS3args_print(struct nfsl_log_file *elfrec,
1046 	nfslog_READDIRPLUS3args *args)
1047 {
1048 	nfslog_fh3_print(elfrec, &args->dir);
1049 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%x",
1050 		args->dircount);
1051 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%x",
1052 		args->maxcount);
1053 }
1054 
1055 static void
1056 nfslog_COMMIT3args_print(struct nfsl_log_file *elfrec,
1057 	nfslog_COMMIT3args *args)
1058 {
1059 	nfslog_fh3_print(elfrec, &args->file);
1060 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%llx",
1061 		args->offset);
1062 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], " 0x%x",
1063 		args->count);
1064 }
1065 
1066 static void
1067 nfslog_nfsstat3_print(struct nfsl_log_file *elfrec, enum nfsstat3 *res,
1068 	bool_t print_status)
1069 {
1070 	if (print_status) {
1071 		char	*statp = nfslog_get_status((short)(*res));
1072 
1073 		if (statp != NULL)
1074 			elfrec->bufoffset +=
1075 				sprintf(&elfrec->buf[elfrec->bufoffset], " %s",
1076 					statp);
1077 		else
1078 			elfrec->bufoffset +=
1079 				sprintf(&elfrec->buf[elfrec->bufoffset], " %5d",
1080 					*res);
1081 	}
1082 }
1083 
1084 static void
1085 nfslog_LOOKUP3res_print(struct nfsl_log_file *elfrec,
1086 	nfslog_LOOKUP3res *res, bool_t print_status)
1087 {
1088 	if (print_status) {
1089 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1090 	} else if (res->status == NFS3_OK) {
1091 		nfslog_fh3_print(elfrec, &res->nfslog_LOOKUP3res_u.object);
1092 	}
1093 }
1094 
1095 static void
1096 nfslog_READLINK3res_print(struct nfsl_log_file *elfrec,
1097 	nfslog_READLINK3res *res, bool_t print_status)
1098 {
1099 	if (print_status) {
1100 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1101 	} else if (res->status == NFS3_OK) {
1102 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1103 			" %s", res->nfslog_READLINK3res_u.data);
1104 	}
1105 }
1106 
1107 static void
1108 nfslog_READ3res_print(struct nfsl_log_file *elfrec, nfslog_READ3res *res,
1109 	bool_t print_status)
1110 {
1111 	if (print_status) {
1112 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1113 	} else if (res->status == NFS3_OK) {
1114 		char	*elfbuf = elfrec->buf;
1115 		int	elfbufoffset = elfrec->bufoffset;
1116 
1117 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%llx",
1118 			res->nfslog_READ3res_u.ok.filesize);
1119 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
1120 			res->nfslog_READ3res_u.ok.count);
1121 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
1122 			res->nfslog_READ3res_u.ok.eof);
1123 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
1124 			res->nfslog_READ3res_u.ok.size);
1125 		elfrec->bufoffset = elfbufoffset;
1126 	}
1127 }
1128 
1129 static void
1130 nfslog_WRITE3res_print(struct nfsl_log_file *elfrec, nfslog_WRITE3res *res,
1131 	bool_t print_status)
1132 {
1133 	if (print_status) {
1134 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1135 	} else if (res->status == NFS3_OK) {
1136 		char	*elfbuf = elfrec->buf;
1137 		int	elfbufoffset = elfrec->bufoffset;
1138 
1139 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%llx",
1140 			res->nfslog_WRITE3res_u.ok.filesize);
1141 		elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1142 			" 0x%x", res->nfslog_WRITE3res_u.ok.count);
1143 		elfbufoffset += sprintf(&elfrec->buf[elfbufoffset],
1144 			" 0x%x", res->nfslog_WRITE3res_u.ok.committed);
1145 		elfrec->bufoffset = elfbufoffset;
1146 	}
1147 }
1148 
1149 static void
1150 nfslog_CREATE3res_print(struct nfsl_log_file *elfrec, nfslog_CREATE3res *res,
1151 	bool_t print_status)
1152 {
1153 	if (print_status) {
1154 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1155 	} else if (res->status == NFS3_OK) {
1156 		if (res->nfslog_CREATE3res_u.ok.obj.handle_follows) {
1157 			nfslog_fh3_print(elfrec,
1158 				&res->nfslog_CREATE3res_u.ok.obj.handle);
1159 		}
1160 	}
1161 }
1162 
1163 static void
1164 nfslog_MKDIR3res_print(struct nfsl_log_file *elfrec, nfslog_MKDIR3res *res,
1165 	bool_t print_status)
1166 {
1167 	if (print_status) {
1168 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1169 	} else if (res->status == NFS3_OK) {
1170 		if (res->nfslog_MKDIR3res_u.obj.handle_follows) {
1171 			nfslog_fh3_print(elfrec,
1172 				&res->nfslog_MKDIR3res_u.obj.handle);
1173 		}
1174 	}
1175 }
1176 
1177 static void
1178 nfslog_SYMLINK3res_print(struct nfsl_log_file *elfrec, nfslog_SYMLINK3res *res,
1179 	bool_t print_status)
1180 {
1181 	if (print_status) {
1182 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1183 	} else if (res->status == NFS3_OK) {
1184 		if (res->nfslog_SYMLINK3res_u.obj.handle_follows) {
1185 			nfslog_fh3_print(elfrec,
1186 				&res->nfslog_SYMLINK3res_u.obj.handle);
1187 		}
1188 	}
1189 }
1190 
1191 static void
1192 nfslog_MKNOD3res_print(struct nfsl_log_file *elfrec, nfslog_MKNOD3res *res,
1193 	bool_t print_status)
1194 {
1195 	if (print_status) {
1196 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1197 	} else if (res->status == NFS3_OK) {
1198 		if (res->nfslog_MKNOD3res_u.obj.handle_follows) {
1199 			nfslog_fh3_print(elfrec,
1200 				&res->nfslog_MKNOD3res_u.obj.handle);
1201 		}
1202 	}
1203 }
1204 
1205 static void
1206 nfslog_READDIRPLUS3res_print(struct nfsl_log_file *elfrec,
1207 	nfslog_READDIRPLUS3res *res, bool_t print_status)
1208 {
1209 	if (print_status) {
1210 		nfslog_nfsstat3_print(elfrec, &res->status, print_status);
1211 	}
1212 }
1213 
1214 /*
1215  * **** End of table functions for logging specific procs ****
1216  *
1217  * Hereafter are the general logging management and dispatcher.
1218  */
1219 
1220 
1221 /*
1222  * nfsl_ipaddr_print - extracts sender ip address from transport struct
1223  * and prints it in legible form.
1224  */
1225 static void
1226 nfsl_ipaddr_print(struct nfsl_log_file *elfrec, struct netbuf *ptr)
1227 {
1228 	struct hostent	*hp;
1229 	extern char	*inet_ntop();
1230 	int		size, sin_family, error;
1231 	char		*elfbuf = elfrec->buf;
1232 	char		*addrp;
1233 	int		elfbufoffset = elfrec->bufoffset;
1234 
1235 	if (ptr->len == 0) {
1236 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1237 			empty_name);
1238 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1239 			empty_name);
1240 		elfrec->bufoffset = elfbufoffset;
1241 		return;
1242 	}
1243 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " ");
1244 	/* LINTED */
1245 	sin_family = ((struct sockaddr_in *)ptr->buf)->sin_family;
1246 	switch (sin_family) {
1247 	case (AF_INET):
1248 		/* LINTED */
1249 		addrp = (char *)&((struct sockaddr_in *)ptr->buf)->sin_addr;
1250 		size = sizeof (struct in_addr);
1251 		break;
1252 	case (AF_INET6):
1253 		/* LINTED */
1254 		addrp = (char *)&((struct sockaddr_in6 *)ptr->buf)->sin6_addr;
1255 		size = sizeof (struct in6_addr);
1256 		break;
1257 	default:
1258 		/* unknown protocol: print address in hex form */
1259 		for (size = ptr->len, addrp = ptr->buf; size > 0; size--) {
1260 			elfbufoffset += sprintf(&elfbuf[elfbufoffset], "%02x",
1261 				*addrp);
1262 		}
1263 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1264 			empty_name);
1265 		elfrec->bufoffset = elfbufoffset;
1266 		return;
1267 	}
1268 	if (inet_ntop(sin_family, addrp, &elfbuf[elfbufoffset],
1269 		(size_t)(DFLT_BUFFERSIZE + DFLT_OVFSIZE - elfbufoffset))
1270 		    == NULL) {
1271 		/* Not enough space to print - should never happen */
1272 		elfbuf[elfrec->bufoffset] = '\0';	/* just in case */
1273 		return;
1274 	}
1275 	/* inet_ntop copied address into elfbuf, so update offset */
1276 	elfbufoffset += strlen(&elfbuf[elfbufoffset]);
1277 	/* get host name and log it as well */
1278 	hp = getipnodebyaddr(addrp, size, sin_family, &error);
1279 	if (hp != NULL) {
1280 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " \"%s\"",
1281 			hp->h_name);
1282 	} else {
1283 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1284 			empty_name);
1285 	}
1286 	elfrec->bufoffset = elfbufoffset;
1287 }
1288 
1289 static void
1290 nfsl_elf_record_header_print(struct nfsl_log_file *elfrec,
1291 	nfslog_record_header *lhp, char *principal_name, char *tag,
1292 	struct nfsl_proc_disp *disp, char *progname)
1293 {
1294 	struct passwd	*pwp = NULL;
1295 	char	*elfbuf = elfrec->buf;
1296 	int	elfbufoffset = elfrec->bufoffset;
1297 
1298 	/*
1299 	 * Fields: time bytes tag rpc-program rpc-version rpc-procedure
1300 	 *	   auth-flavor s-user-name s-uid uid u-name gid net-id
1301 	 *   c-ip c-dns s-dns status rpcarg-path <arguments> <response>
1302 	 */
1303 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], "%s",
1304 		nfsl_get_time((time_t)lhp->rh_timestamp.tv_sec));
1305 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%x",
1306 		lhp->rh_reclen);
1307 	if ((tag != NULL) && (tag[0] != '\0')) {
1308 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " \"%s\"", tag);
1309 	} else {
1310 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1311 					empty_name);
1312 	}
1313 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s 0x%x %s",
1314 				progname, lhp->rh_version, disp->procname);
1315 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1316 		NFSL_AUTH_FLAVOR_PRINT(lhp->rh_auth_flavor));
1317 	if ((principal_name != NULL) && (principal_name[0] != '\0')) {
1318 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " \"%s\"",
1319 			principal_name);
1320 		if ((pwp = getpwnam(principal_name)) != NULL) {
1321 			elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1322 				" 0x%lx", pwp->pw_uid);
1323 		} else {
1324 			elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1325 				" %s", empty_name);
1326 		}
1327 	} else {
1328 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1329 			empty_name);
1330 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1331 			empty_name);
1332 	}
1333 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%lx", lhp->rh_uid);
1334 	if (((pwp = getpwuid(lhp->rh_uid)) != NULL) && (pwp->pw_name != NULL)) {
1335 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " \"%s\"",
1336 			pwp->pw_name);
1337 	} else {
1338 		elfbufoffset += sprintf(&elfbuf[elfbufoffset], " %s",
1339 			empty_name);
1340 	}
1341 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], " 0x%lx", lhp->rh_gid);
1342 	elfrec->bufoffset = elfbufoffset;
1343 }
1344 
1345 static void
1346 nfsl_elf_buffer_header_print(struct nfsl_log_file *elfrec,
1347 	nfslog_buffer_header *bufhdr)
1348 {
1349 	int	rc;
1350 	struct utsname	name;
1351 	char	*elfbuf = elfrec->buf;
1352 	int	elfbufoffset = elfrec->bufoffset;
1353 
1354 	rc = uname(&name);
1355 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1356 		"#Version %d.0\n#Software \"%s\"\n",
1357 		bufhdr->bh_version, ((rc >= 0) ? name.sysname : empty_name));
1358 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], "#Date %s\n",
1359 		nfsl_get_date((time_t)bufhdr->bh_timestamp.tv_sec));
1360 	elfbufoffset += sprintf(&elfbuf[elfbufoffset], "#Remark %s\n",
1361 		empty_name);
1362 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1363 		"#Fields: time bytes tag");
1364 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1365 		" rpc-program rpc-version rpc-procedure");
1366 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1367 		" auth-flavor s-user-name s-uid uid u-name gid net-id c-ip");
1368 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1369 		" c-dns s-dns status rpcarg-path");
1370 	elfbufoffset += sprintf(&elfbuf[elfbufoffset],
1371 		" rpc-arguments... rpc-response...\n");
1372 	elfrec->bufoffset = elfbufoffset;
1373 }
1374 
1375 /*
1376  * nfsl_find_elf_dispatch - get the dispatch struct for this request
1377  */
1378 static struct nfsl_proc_disp *
1379 nfsl_find_elf_dispatch(nfslog_request_record *logrec, char **prognamep)
1380 {
1381 	nfslog_record_header	*logrechdr = &logrec->re_header;
1382 	struct nfsl_prog_disp	*progtable;	/* prog struct */
1383 	struct nfsl_vers_disp	*verstable;	/* version struct */
1384 	int			i, vers;
1385 
1386 	/* Find prog element - search because can't use prog as array index */
1387 	for (i = 0; (i < nfsl_elf_dispatch_table_arglen) &&
1388 	    (logrechdr->rh_prognum != nfsl_elf_dispatch_table[i].nfsl_dis_prog);
1389 		i++);
1390 	if (i >= nfsl_elf_dispatch_table_arglen) {	/* program not logged */
1391 		/* not an error */
1392 		return (NULL);
1393 	}
1394 	progtable = &nfsl_elf_dispatch_table[i];
1395 	/* Find vers element - no validity check - if here it's valid vers */
1396 	vers = logrechdr->rh_version - progtable->nfsl_dis_versmin;
1397 	verstable = &progtable->nfsl_dis_vers_table[vers];
1398 	/* Find proc element - no validity check - if here it's valid proc */
1399 	*prognamep = progtable->progname;
1400 	return (&verstable->nfsl_dis_proc_table[logrechdr->rh_procnum]);
1401 }
1402 
1403 /*
1404  * nfsl_elf_rpc_print - Print the record buffer.
1405  */
1406 static void
1407 nfsl_elf_rpc_print(struct nfsl_log_file *elfrec,
1408 	nfslog_request_record *logrec, struct nfsl_proc_disp *disp,
1409 	char *progname, char *path1, char *path2)
1410 {
1411 	if (debug > 1) {
1412 		(void) printf("%s %d %s", progname,
1413 			logrec->re_header.rh_version, disp->procname);
1414 		(void) printf(": '%s', '%s'\n",
1415 			((path1 != NULL) ? path1 : empty_name),
1416 			((path2 != NULL) ? path2 : empty_name));
1417 	}
1418 	/*
1419 	 * XXXX programs using this file to get a usable record should
1420 	 * take "record" struct.
1421 	 */
1422 	/*
1423 	 * Print the variable fields:
1424 	 *	principal name
1425 	 *	netid
1426 	 *	ip address
1427 	 *	rpc args
1428 	 *	rpc res
1429 	 * Use the displacements calculated earlier...
1430 	 */
1431 
1432 	/*
1433 	 * Fields: time bytes tag rpc-program rpc-version rpc-procedure
1434 	 *	   auth-flavor s-user-name s-uid uid u-name gid net-id c-ip
1435 	 *	 c-dns s-dns status rpcarg-path <arguments> <response>
1436 	 */
1437 	nfsl_elf_record_header_print(elfrec, &logrec->re_header,
1438 			logrec->re_principal_name, logrec->re_tag,
1439 			disp, progname);
1440 	if ((logrec->re_netid != NULL) && (logrec->re_netid[0] != '\0')) {
1441 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1442 			" \"%s\"", logrec->re_netid);
1443 	} else {
1444 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1445 			" %s", empty_name);
1446 	}
1447 	nfsl_ipaddr_print(elfrec, &logrec->re_ipaddr);
1448 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1449 		" \"%s\"", hostname);
1450 	/* Next is return status */
1451 	(*disp->nfsl_dis_res)(elfrec, logrec->re_rpc_res, TRUE);
1452 	/* Next is argpath */
1453 	if (path1 != NULL) {
1454 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1455 			" \"%s\"", path1);
1456 	} else {
1457 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1458 			" %s", empty_name);
1459 	}
1460 	/*
1461 	 * path2 is non-empty for rename/link type operations. If it is non-
1462 	 * empty print it here as it's a part of the args
1463 	 */
1464 	if (path2 != NULL) {
1465 		elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset],
1466 			" \"%s\"", path2);
1467 	}
1468 	/* Next print formatted rpc args */
1469 	(*disp->nfsl_dis_args)(elfrec, logrec->re_rpc_arg);
1470 	/* Next print formatted rpc res (minus status) */
1471 	(*disp->nfsl_dis_res)(elfrec, logrec->re_rpc_res, FALSE);
1472 	elfrec->bufoffset += sprintf(&elfrec->buf[elfrec->bufoffset], "\n");
1473 }
1474 
1475 /*
1476  * nfsl_log_file_add - add a new record to the list
1477  */
1478 static void
1479 nfsl_log_file_add(struct nfsl_log_file *elfrec,
1480 	struct nfsl_log_file **elf_listp)
1481 {
1482 	elfrec->next = *elf_listp;
1483 	elfrec->prev = NULL;
1484 	if (*elf_listp != NULL) {
1485 		(*elf_listp)->prev = elfrec;
1486 	}
1487 	*elf_listp = elfrec;
1488 }
1489 
1490 /*
1491  * nfsl_log_file_find - finds a record in the list, given a cookie (== elfrec)
1492  * Returns the record.
1493  */
1494 static struct nfsl_log_file *
1495 nfsl_log_file_find(struct nfsl_log_file *elfrec,
1496 	struct nfsl_log_file *elf_list)
1497 {
1498 	struct nfsl_log_file	*rec;
1499 
1500 	for (rec = elf_list; (rec != NULL) && (rec != elfrec);
1501 		rec = rec->next);
1502 	return (rec);
1503 }
1504 
1505 /*
1506  * nfsl_log_file_del - delete a record from the list, does not free rec.
1507  * Returns the deleted record.
1508  */
1509 static struct nfsl_log_file *
1510 nfsl_log_file_del(struct nfsl_log_file *elfrec,
1511 	struct nfsl_log_file **elf_listp)
1512 {
1513 	struct nfsl_log_file	*rec;
1514 
1515 	if ((rec = nfsl_log_file_find(elfrec, *elf_listp)) == NULL) {
1516 		return (NULL);
1517 	}
1518 	if (rec->prev != NULL) {
1519 		rec->prev->next = rec->next;
1520 	} else {
1521 		*elf_listp = rec->next;
1522 	}
1523 	if (rec->next != NULL) {
1524 		rec->next->prev = rec->prev;
1525 	}
1526 	return (rec);
1527 }
1528 
1529 /*
1530  * nfsl_log_file_free - frees a record
1531  */
1532 static void
1533 nfsl_log_file_free(struct nfsl_log_file *elfrec)
1534 {
1535 	if (elfrec == NULL)
1536 		return;
1537 	if (elfrec->path != NULL)
1538 		free(elfrec->path);
1539 	if (elfrec->buf != NULL)
1540 		free(elfrec->buf);
1541 	free(elfrec);
1542 }
1543 
1544 /*
1545  * Exported Functions
1546  */
1547 
1548 /*
1549  * nfslog_open_elf_file - open the output elf file and mallocs needed buffers
1550  * Returns a pointer to the nfsl_log_file on success, NULL on error.
1551  *
1552  * *error contains the last error encountered on this object, It can
1553  * be used to avoid reporting the same error endlessly, by comparing
1554  * the current error to the last error. It is reset to the current error
1555  * code on return.
1556  */
1557 void *
1558 nfslog_open_elf_file(char *elfpath, nfslog_buffer_header *bufhdr, int *error)
1559 {
1560 	struct nfsl_log_file *elfrec;
1561 	struct stat stat_buf;
1562 	int preverror = *error;
1563 
1564 	if ((elfrec = malloc(sizeof (*elfrec))) == NULL) {
1565 		*error = errno;
1566 		if (*error != preverror) {
1567 			syslog(LOG_ERR, gettext("nfslog_open_elf_file: %s"),
1568 				strerror(*error));
1569 		}
1570 		return (NULL);
1571 	}
1572 	bzero(elfrec, sizeof (*elfrec));
1573 
1574 	elfrec->buf = (char *)malloc(DFLT_BUFFERSIZE + DFLT_OVFSIZE);
1575 	if (elfrec->buf == NULL) {
1576 		*error = errno;
1577 		if (*error != preverror) {
1578 			syslog(LOG_ERR, gettext("nfslog_open_elf_file: %s"),
1579 				strerror(*error));
1580 		}
1581 		nfsl_log_file_free(elfrec);
1582 		return (NULL);
1583 	}
1584 
1585 	if ((elfrec->path = strdup(elfpath)) == NULL) {
1586 		*error = errno;
1587 		if (*error != preverror) {
1588 			syslog(LOG_ERR, gettext("nfslog_open_elf_file: %s"),
1589 				strerror(*error));
1590 		}
1591 		nfsl_log_file_free(elfrec);
1592 		return (NULL);
1593 	}
1594 
1595 	if ((elfrec->fp = fopen(elfpath, "a")) == NULL) {
1596 		*error = errno;
1597 		if (*error != preverror) {
1598 			syslog(LOG_ERR, gettext("Cannot open '%s': %s"),
1599 				elfpath, strerror(*error));
1600 		}
1601 		nfsl_log_file_free(elfrec);
1602 		return (NULL);
1603 	}
1604 
1605 	if (stat(elfpath, &stat_buf) == -1) {
1606 		*error = errno;
1607 		if (*error != preverror) {
1608 			syslog(LOG_ERR, gettext("Cannot stat '%s': %s"),
1609 				elfpath, strerror(*error));
1610 		}
1611 		(void) fclose(elfrec->fp);
1612 		nfsl_log_file_free(elfrec);
1613 		return (NULL);
1614 	}
1615 
1616 	nfsl_log_file_add(elfrec, &elf_file_list);
1617 
1618 	if (stat_buf.st_size == 0) {
1619 		/*
1620 		 * Print header unto logfile
1621 		 */
1622 		nfsl_elf_buffer_header_print(elfrec, bufhdr);
1623 	}
1624 
1625 	if (hostname[0] == '\0') {
1626 		(void) gethostname(hostname, MAXHOSTNAMELEN);
1627 	}
1628 
1629 	return (elfrec);
1630 }
1631 
1632 /*
1633  * nfslog_close_elf_file - close elffile and write out last buffer
1634  */
1635 void
1636 nfslog_close_elf_file(void **elfcookie)
1637 {
1638 	struct nfsl_log_file	*elfrec;
1639 
1640 	if ((*elfcookie == NULL) || ((elfrec = nfsl_log_file_del(
1641 	    *elfcookie, &elf_file_list)) == NULL)) {
1642 		*elfcookie = NULL;
1643 		return;
1644 	}
1645 	if (elfrec->fp != NULL) {
1646 		/* Write the last output buffer to disk */
1647 		(void) nfsl_write_elfbuf(elfrec);
1648 		(void) fclose(elfrec->fp);
1649 	}
1650 	nfsl_log_file_free(elfrec);
1651 	*elfcookie = NULL;
1652 }
1653 
1654 /*
1655  * nfslog_process_elf_rec - processes the record in the buffer and outputs
1656  *	to the elf log.
1657  * Return 0 for success, errno else.
1658  */
1659 int
1660 nfslog_process_elf_rec(void *elfcookie, nfslog_request_record *logrec,
1661 	char *path1, char *path2)
1662 {
1663 	struct nfsl_log_file	*elfrec;
1664 	struct nfsl_proc_disp	*disp;
1665 	char			*progname;
1666 
1667 	if ((elfrec = nfsl_log_file_find(elfcookie, elf_file_list)) == NULL) {
1668 		return (EINVAL);
1669 	}
1670 	/* Make sure there is room */
1671 	if (elfrec->bufoffset > DFLT_BUFFERSIZE) {
1672 		if (nfsl_write_elfbuf(elfrec) < 0) {
1673 			return (errno);
1674 		}
1675 	}
1676 	if ((disp = nfsl_find_elf_dispatch(logrec, &progname)) != NULL) {
1677 		nfsl_elf_rpc_print(elfrec, logrec, disp, progname,
1678 			path1, path2);
1679 	}
1680 	return (0);
1681 }
1682