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