1/*
2 *  linux/fs/9p/fcprint.c
3 *
4 *  Print 9P call.
5 *
6 *  Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License version 2
10 *  as published by the Free Software Foundation.
11 *
12 *  This program is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to:
19 *  Free Software Foundation
20 *  51 Franklin Street, Fifth Floor
21 *  Boston, MA  02111-1301  USA
22 *
23 */
24#include <linux/module.h>
25#include <linux/errno.h>
26#include <linux/fs.h>
27#include <linux/idr.h>
28
29#include "debug.h"
30#include "v9fs.h"
31#include "9p.h"
32#include "mux.h"
33
34static int
35v9fs_printqid(char *buf, int buflen, struct v9fs_qid *q)
36{
37	int n;
38	char b[10];
39
40	n = 0;
41	if (q->type & V9FS_QTDIR)
42		b[n++] = 'd';
43	if (q->type & V9FS_QTAPPEND)
44		b[n++] = 'a';
45	if (q->type & V9FS_QTAUTH)
46		b[n++] = 'A';
47	if (q->type & V9FS_QTEXCL)
48		b[n++] = 'l';
49	if (q->type & V9FS_QTTMP)
50		b[n++] = 't';
51	if (q->type & V9FS_QTSYMLINK)
52		b[n++] = 'L';
53	b[n] = '\0';
54
55	return scnprintf(buf, buflen, "(%.16llx %x %s)", (long long int) q->path,
56		q->version, b);
57}
58
59static int
60v9fs_printperm(char *buf, int buflen, int perm)
61{
62	int n;
63	char b[15];
64
65	n = 0;
66	if (perm & V9FS_DMDIR)
67		b[n++] = 'd';
68	if (perm & V9FS_DMAPPEND)
69		b[n++] = 'a';
70	if (perm & V9FS_DMAUTH)
71		b[n++] = 'A';
72	if (perm & V9FS_DMEXCL)
73		b[n++] = 'l';
74	if (perm & V9FS_DMTMP)
75		b[n++] = 't';
76	if (perm & V9FS_DMDEVICE)
77		b[n++] = 'D';
78	if (perm & V9FS_DMSOCKET)
79		b[n++] = 'S';
80	if (perm & V9FS_DMNAMEDPIPE)
81		b[n++] = 'P';
82	if (perm & V9FS_DMSYMLINK)
83		b[n++] = 'L';
84	b[n] = '\0';
85
86	return scnprintf(buf, buflen, "%s%03o", b, perm&077);
87}
88
89static int
90v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
91{
92	int n;
93
94	n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len,
95		st->name.str, st->uid.len, st->uid.str);
96	if (extended)
97		n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid);
98
99	n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str);
100	if (extended)
101		n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid);
102
103	n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str);
104	if (extended)
105		n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
106
107	n += scnprintf(buf+n, buflen-n, " q ");
108	n += v9fs_printqid(buf+n, buflen-n, &st->qid);
109	n += scnprintf(buf+n, buflen-n, " m ");
110	n += v9fs_printperm(buf+n, buflen-n, st->mode);
111	n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
112		st->atime, st->mtime, (long long int) st->length);
113
114	if (extended)
115		n += scnprintf(buf+n, buflen-n, " ext '%.*s'",
116			st->extension.len, st->extension.str);
117
118	return n;
119}
120
121static int
122v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen)
123{
124	int i, n;
125
126	i = n = 0;
127	while (i < datalen) {
128		n += scnprintf(buf + n, buflen - n, "%02x", data[i]);
129		if (i%4 == 3)
130			n += scnprintf(buf + n, buflen - n, " ");
131		if (i%32 == 31)
132			n += scnprintf(buf + n, buflen - n, "\n");
133
134		i++;
135	}
136	n += scnprintf(buf + n, buflen - n, "\n");
137
138	return n;
139}
140
141static int
142v9fs_printdata(char *buf, int buflen, u8 *data, int datalen)
143{
144	return v9fs_dumpdata(buf, buflen, data, datalen<16?datalen:16);
145}
146
147int
148v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
149{
150	int i, ret, type, tag;
151
152	if (!fc)
153		return scnprintf(buf, buflen, "<NULL>");
154
155	type = fc->id;
156	tag = fc->tag;
157
158	ret = 0;
159	switch (type) {
160	case TVERSION:
161		ret += scnprintf(buf+ret, buflen-ret,
162			"Tversion tag %u msize %u version '%.*s'", tag,
163			fc->params.tversion.msize, fc->params.tversion.version.len,
164			fc->params.tversion.version.str);
165		break;
166
167	case RVERSION:
168		ret += scnprintf(buf+ret, buflen-ret,
169			"Rversion tag %u msize %u version '%.*s'", tag,
170			fc->params.rversion.msize, fc->params.rversion.version.len,
171			fc->params.rversion.version.str);
172		break;
173
174	case TAUTH:
175		ret += scnprintf(buf+ret, buflen-ret,
176			"Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
177			fc->params.tauth.afid, fc->params.tauth.uname.len,
178			fc->params.tauth.uname.str, fc->params.tauth.aname.len,
179			fc->params.tauth.aname.str);
180		break;
181
182	case RAUTH:
183		ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
184		v9fs_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
185		break;
186
187	case TATTACH:
188		ret += scnprintf(buf+ret, buflen-ret,
189			"Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'",
190			tag, fc->params.tattach.fid, fc->params.tattach.afid,
191			fc->params.tattach.uname.len, fc->params.tattach.uname.str,
192			fc->params.tattach.aname.len, fc->params.tattach.aname.str);
193		break;
194
195	case RATTACH:
196		ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", tag);
197		v9fs_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
198		break;
199
200	case RERROR:
201		ret += scnprintf(buf+ret, buflen-ret, "Rerror tag %u ename '%.*s'",
202			tag, fc->params.rerror.error.len,
203			fc->params.rerror.error.str);
204		if (extended)
205			ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
206				fc->params.rerror.errno);
207		break;
208
209	case TFLUSH:
210		ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
211			tag, fc->params.tflush.oldtag);
212		break;
213
214	case RFLUSH:
215		ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
216		break;
217
218	case TWALK:
219		ret += scnprintf(buf+ret, buflen-ret,
220			"Twalk tag %u fid %d newfid %d nwname %d", tag,
221			fc->params.twalk.fid, fc->params.twalk.newfid,
222			fc->params.twalk.nwname);
223		for(i = 0; i < fc->params.twalk.nwname; i++)
224			ret += scnprintf(buf+ret, buflen-ret," '%.*s'",
225				fc->params.twalk.wnames[i].len,
226				fc->params.twalk.wnames[i].str);
227		break;
228
229	case RWALK:
230		ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
231			tag, fc->params.rwalk.nwqid);
232		for(i = 0; i < fc->params.rwalk.nwqid; i++)
233			ret += v9fs_printqid(buf+ret, buflen-ret,
234				&fc->params.rwalk.wqids[i]);
235		break;
236
237	case TOPEN:
238		ret += scnprintf(buf+ret, buflen-ret,
239			"Topen tag %u fid %d mode %d", tag,
240			fc->params.topen.fid, fc->params.topen.mode);
241		break;
242
243	case ROPEN:
244		ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
245		ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
246		ret += scnprintf(buf+ret, buflen-ret," iounit %d",
247			fc->params.ropen.iounit);
248		break;
249
250	case TCREATE:
251		ret += scnprintf(buf+ret, buflen-ret,
252			"Tcreate tag %u fid %d name '%.*s' perm ", tag,
253			fc->params.tcreate.fid, fc->params.tcreate.name.len,
254			fc->params.tcreate.name.str);
255
256		ret += v9fs_printperm(buf+ret, buflen-ret, fc->params.tcreate.perm);
257		ret += scnprintf(buf+ret, buflen-ret, " mode %d",
258			fc->params.tcreate.mode);
259		break;
260
261	case RCREATE:
262		ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
263		ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.rcreate.qid);
264		ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
265			fc->params.rcreate.iounit);
266		break;
267
268	case TREAD:
269		ret += scnprintf(buf+ret, buflen-ret,
270			"Tread tag %u fid %d offset %lld count %u", tag,
271			fc->params.tread.fid,
272			(long long int) fc->params.tread.offset,
273			fc->params.tread.count);
274		break;
275
276	case RREAD:
277		ret += scnprintf(buf+ret, buflen-ret,
278			"Rread tag %u count %u data ", tag,
279			fc->params.rread.count);
280		ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.rread.data,
281			fc->params.rread.count);
282		break;
283
284	case TWRITE:
285		ret += scnprintf(buf+ret, buflen-ret,
286			"Twrite tag %u fid %d offset %lld count %u data ",
287			tag, fc->params.twrite.fid,
288			(long long int) fc->params.twrite.offset,
289			fc->params.twrite.count);
290		ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
291			fc->params.twrite.count);
292		break;
293
294	case RWRITE:
295		ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
296			tag, fc->params.rwrite.count);
297		break;
298
299	case TCLUNK:
300		ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
301			tag, fc->params.tclunk.fid);
302		break;
303
304	case RCLUNK:
305		ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
306		break;
307
308	case TREMOVE:
309		ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
310			tag, fc->params.tremove.fid);
311		break;
312
313	case RREMOVE:
314		ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
315		break;
316
317	case TSTAT:
318		ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
319			tag, fc->params.tstat.fid);
320		break;
321
322	case RSTAT:
323		ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
324		ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
325			extended);
326		break;
327
328	case TWSTAT:
329		ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
330			tag, fc->params.twstat.fid);
331		ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.twstat.stat,
332			extended);
333		break;
334
335	case RWSTAT:
336		ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
337		break;
338
339	default:
340		ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type);
341		break;
342	}
343
344	return ret;
345}
346