Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Linux module support routines. | |
12 | * | |
13 | */ | |
14 | #include <afsconfig.h> | |
15 | #include "afs/param.h" | |
16 | ||
17 | ||
18 | #include <linux/module.h> /* early to avoid printf->printk mapping */ | |
19 | #ifdef HAVE_LINUX_SEQ_FILE_H | |
20 | # include <linux/seq_file.h> | |
21 | #endif | |
22 | #include "afs/sysincludes.h" | |
23 | #include "afsincludes.h" | |
24 | #include "afs/nfsclient.h" | |
25 | #include <linux/unistd.h> /* For syscall numbers. */ | |
26 | #include <linux/mm.h> | |
27 | ||
28 | #ifdef AFS_AMD64_LINUX20_ENV | |
29 | # include <asm/ia32_unistd.h> | |
30 | #endif | |
31 | ||
32 | #include <linux/slab.h> | |
33 | #include <linux/init.h> | |
34 | #include <linux/sched.h> | |
35 | #include <linux/kernel.h> | |
36 | ||
37 | #include "osi_compat.h" | |
38 | ||
39 | struct proc_dir_entry *openafs_procfs; | |
40 | ||
41 | #ifdef HAVE_LINUX_SEQ_FILE_H | |
42 | static void * | |
43 | c_start(struct seq_file *m, loff_t *pos) | |
44 | { | |
45 | struct afs_q *cq, *tq; | |
46 | loff_t n = 0; | |
47 | ||
48 | AFS_GLOCK(); | |
49 | ObtainReadLock(&afs_xcell); | |
50 | for (cq = CellLRU.next; cq != &CellLRU; cq = tq) { | |
51 | tq = QNext(cq); | |
52 | ||
53 | if (n++ == *pos) | |
54 | break; | |
55 | } | |
56 | if (cq == &CellLRU) | |
57 | cq = NULL; | |
58 | ||
59 | AFS_GUNLOCK(); | |
60 | return cq; | |
61 | } | |
62 | ||
63 | static void * | |
64 | c_next(struct seq_file *m, void *p, loff_t *pos) | |
65 | { | |
66 | struct afs_q *cq = p, *tq; | |
67 | ||
68 | AFS_GLOCK(); | |
69 | (*pos)++; | |
70 | tq = QNext(cq); | |
71 | ||
72 | if (tq == &CellLRU) | |
73 | tq = NULL; | |
74 | ||
75 | AFS_GUNLOCK(); | |
76 | return tq; | |
77 | } | |
78 | ||
79 | static void | |
80 | c_stop(struct seq_file *m, void *p) | |
81 | { | |
82 | AFS_GLOCK(); | |
83 | ReleaseReadLock(&afs_xcell); | |
84 | AFS_GUNLOCK(); | |
85 | } | |
86 | ||
87 | static int | |
88 | c_show(struct seq_file *m, void *p) | |
89 | { | |
90 | struct afs_q *cq = p; | |
91 | struct cell *tc = QTOC(cq); | |
92 | int j; | |
93 | ||
94 | seq_printf(m, ">%s #(%d/%d)\n", tc->cellName, | |
95 | tc->cellNum, tc->cellIndex); | |
96 | ||
97 | for (j = 0; j < AFS_MAXCELLHOSTS; j++) { | |
98 | afs_uint32 addr; | |
99 | ||
100 | if (!tc->cellHosts[j]) break; | |
101 | ||
102 | addr = tc->cellHosts[j]->addr->sa_ip; | |
103 | #if defined(NIPQUAD) | |
104 | seq_printf(m, "%u.%u.%u.%u #%u.%u.%u.%u\n", | |
105 | NIPQUAD(addr), NIPQUAD(addr)); | |
106 | #else | |
107 | seq_printf(m, "%pI4 #%pI4\n", &addr, &addr); | |
108 | #endif | |
109 | } | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static struct seq_operations afs_csdb_op = { | |
115 | .start = c_start, | |
116 | .next = c_next, | |
117 | .stop = c_stop, | |
118 | .show = c_show, | |
119 | }; | |
120 | ||
121 | static int | |
122 | afs_csdb_open(struct inode *inode, struct file *file) | |
123 | { | |
124 | return seq_open(file, &afs_csdb_op); | |
125 | } | |
126 | ||
127 | static struct file_operations afs_csdb_operations = { | |
128 | .open = afs_csdb_open, | |
129 | .read = seq_read, | |
130 | .llseek = seq_lseek, | |
131 | .release = seq_release, | |
132 | }; | |
133 | ||
134 | static void * | |
135 | uu_start(struct seq_file *m, loff_t *pos) | |
136 | { | |
137 | struct unixuser *tu; | |
138 | void *ret; | |
139 | loff_t n = 0; | |
140 | afs_int32 i; | |
141 | ||
142 | AFS_GLOCK(); | |
143 | ObtainReadLock(&afs_xuser); | |
144 | ||
145 | if (!*pos) { | |
146 | ret = (void *)(1); | |
147 | goto done; | |
148 | } | |
149 | ||
150 | ret = NULL; | |
151 | ||
152 | for (i = 0; i < NUSERS; i++) { | |
153 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
154 | if (++n == *pos) { | |
155 | ret = tu; | |
156 | goto done; | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | done: | |
162 | AFS_GUNLOCK(); | |
163 | return ret; | |
164 | } | |
165 | ||
166 | static void * | |
167 | uu_next(struct seq_file *m, void *p, loff_t *pos) | |
168 | { | |
169 | struct unixuser *tu = p; | |
170 | afs_int32 i = 0; | |
171 | ||
172 | (*pos)++; | |
173 | if (!p) return NULL; | |
174 | ||
175 | if (p != (void *)1) { | |
176 | if (tu->next) return tu->next; | |
177 | i = UHash(tu->uid) + 1; | |
178 | } | |
179 | ||
180 | for (; i < NUSERS; i++) | |
181 | if (afs_users[i]) return afs_users[i]; | |
182 | return NULL; | |
183 | } | |
184 | ||
185 | static void | |
186 | uu_stop(struct seq_file *m, void *p) | |
187 | { | |
188 | AFS_GLOCK(); | |
189 | ReleaseReadLock(&afs_xuser); | |
190 | AFS_GUNLOCK(); | |
191 | } | |
192 | ||
193 | static int | |
194 | uu_show(struct seq_file *m, void *p) | |
195 | { | |
196 | struct cell *tc = 0; | |
197 | struct unixuser *tu = p; | |
198 | union tokenUnion *token; | |
199 | char *cellname; | |
200 | ||
201 | if (p == (void *)1) { | |
202 | seq_printf(m, "%10s %4s %-6s %-25s %10s", | |
203 | "UID/PAG", "Refs", "States", "Cell", "ViceID"); | |
204 | seq_printf(m, " %10s %10s %10s %3s", | |
205 | "Tok Set", "Tok Begin", "Tok Expire", "vno"); | |
206 | seq_printf(m, " %-15s %10s %10s %s\n", | |
207 | "NFS Client", "UID/PAG", "Client UID", "Sysname(s)"); | |
208 | ||
209 | return 0; | |
210 | } | |
211 | ||
212 | AFS_GLOCK(); | |
213 | ||
214 | tu->refCount++; | |
215 | ReleaseReadLock(&afs_xuser); | |
216 | ||
217 | afs_LockUser(tu, READ_LOCK, 0); | |
218 | ||
219 | if (tu->cell == -1) { | |
220 | cellname = "<default>"; | |
221 | } else { | |
222 | tc = afs_GetCellStale(tu->cell, READ_LOCK); | |
223 | if (tc) cellname = tc->cellName; | |
224 | else cellname = "<unknown>"; | |
225 | } | |
226 | ||
227 | seq_printf(m, "%10d %4d %04x %-25s %10d", | |
228 | tu->uid, tu->refCount, tu->states, cellname, tu->viceId); | |
229 | ||
230 | if (tc) afs_PutCell(tc, READ_LOCK); | |
231 | ||
232 | if (tu->states & UHasTokens) { | |
233 | token = afs_FindToken(tu->tokens, RX_SECIDX_KAD); | |
234 | seq_printf(m, " %10d %10d %10d %3d", | |
235 | tu->tokenTime, | |
236 | (token!=NULL)?token->rxkad.clearToken.BeginTimestamp:0, | |
237 | (token!=NULL)?token->rxkad.clearToken.EndTimestamp:0, | |
238 | (token!=NULL)?token->rxkad.clearToken.AuthHandle:0); | |
239 | } else { | |
240 | seq_printf(m, " %-36s", "Tokens Not Set"); | |
241 | } | |
242 | ||
243 | if (tu->exporter && tu->exporter->exp_type == EXP_NFS) { | |
244 | struct nfsclientpag *np = (struct nfsclientpag *)(tu->exporter); | |
245 | char ipaddr[16]; | |
246 | int i; | |
247 | ||
248 | #if defined(NIPQUAD) | |
249 | sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(np->host)); | |
250 | #else | |
251 | sprintf(ipaddr, "%pI4", &np->host); | |
252 | #endif | |
253 | seq_printf(m, " %-15s %10d %10d", ipaddr, np->uid, np->client_uid); | |
254 | if (np->sysnamecount) { | |
255 | for (i = 0; i < np->sysnamecount; i++) | |
256 | seq_printf(m, " %s", np->sysname[i]); | |
257 | } else { | |
258 | seq_printf(m, " <no sysname list>"); | |
259 | } | |
260 | ||
261 | } else if (tu->exporter) { | |
262 | seq_printf(m, " Unknown exporter type %d", tu->exporter->exp_type); | |
263 | } | |
264 | seq_printf(m, "\n"); | |
265 | ||
266 | afs_PutUser(tu, READ_LOCK); | |
267 | ObtainReadLock(&afs_xuser); | |
268 | ||
269 | AFS_GUNLOCK(); | |
270 | ||
271 | return 0; | |
272 | } | |
273 | ||
274 | static struct seq_operations afs_unixuser_seqop = { | |
275 | .start = uu_start, | |
276 | .next = uu_next, | |
277 | .stop = uu_stop, | |
278 | .show = uu_show, | |
279 | }; | |
280 | ||
281 | static int | |
282 | afs_unixuser_open(struct inode *inode, struct file *file) | |
283 | { | |
284 | return seq_open(file, &afs_unixuser_seqop); | |
285 | } | |
286 | ||
287 | static struct file_operations afs_unixuser_fops = { | |
288 | .open = afs_unixuser_open, | |
289 | .read = seq_read, | |
290 | .llseek = seq_lseek, | |
291 | .release = seq_release, | |
292 | }; | |
293 | ||
294 | ||
295 | #else /* HAVE_LINUX_SEQ_FILE_H */ | |
296 | ||
297 | static int | |
298 | csdbproc_info(char *buffer, char **start, off_t offset, int length) | |
299 | { | |
300 | int len = 0; | |
301 | off_t pos = 0; | |
302 | int cnt; | |
303 | struct afs_q *cq, *tq; | |
304 | struct cell *tc; | |
305 | char tbuffer[16]; | |
306 | /* 90 - 64 cellname, 10 for 32 bit num and index, plus | |
307 | decor */ | |
308 | char temp[91]; | |
309 | afs_uint32 addr; | |
310 | ||
311 | AFS_GLOCK(); | |
312 | ||
313 | ObtainReadLock(&afs_xcell); | |
314 | ||
315 | for (cq = CellLRU.next; cq != &CellLRU; cq = tq) { | |
316 | tc = QTOC(cq); tq = QNext(cq); | |
317 | ||
318 | pos += 90; | |
319 | ||
320 | if (pos <= offset) { | |
321 | len = 0; | |
322 | } else { | |
323 | sprintf(temp, ">%s #(%d/%d)\n", tc->cellName, | |
324 | tc->cellNum, tc->cellIndex); | |
325 | sprintf(buffer + len, "%-89s\n", temp); | |
326 | len += 90; | |
327 | if (pos >= offset+length) { | |
328 | ReleaseReadLock(&afs_xcell); | |
329 | goto done; | |
330 | } | |
331 | } | |
332 | ||
333 | for (cnt = 0; cnt < AFS_MAXCELLHOSTS; cnt++) { | |
334 | if (!tc->cellHosts[cnt]) break; | |
335 | pos += 90; | |
336 | if (pos <= offset) { | |
337 | len = 0; | |
338 | } else { | |
339 | addr = ntohl(tc->cellHosts[cnt]->addr->sa_ip); | |
340 | sprintf(tbuffer, "%d.%d.%d.%d", | |
341 | (int)((addr>>24) & 0xff), | |
342 | (int)((addr>>16) & 0xff), | |
343 | (int)((addr>>8) & 0xff), (int)( addr & 0xff)); | |
344 | sprintf(temp, "%s #%s\n", tbuffer, tbuffer); | |
345 | sprintf(buffer + len, "%-89s\n", temp); | |
346 | len += 90; | |
347 | if (pos >= offset+length) { | |
348 | ReleaseReadLock(&afs_xcell); | |
349 | goto done; | |
350 | } | |
351 | } | |
352 | } | |
353 | } | |
354 | ||
355 | ReleaseReadLock(&afs_xcell); | |
356 | ||
357 | done: | |
358 | AFS_GUNLOCK(); | |
359 | ||
360 | *start = buffer + len - (pos - offset); | |
361 | len = pos - offset; | |
362 | if (len > length) | |
363 | len = length; | |
364 | return len; | |
365 | } | |
366 | ||
367 | #endif /* HAVE_LINUX_SEQ_FILE_H */ | |
368 | ||
369 | void | |
370 | osi_proc_init(void) | |
371 | { | |
372 | struct proc_dir_entry *entry; | |
373 | #if !defined(EXPORTED_PROC_ROOT_FS) | |
374 | char path[64]; | |
375 | #endif | |
376 | ||
377 | #if defined(EXPORTED_PROC_ROOT_FS) | |
378 | openafs_procfs = proc_mkdir(PROC_FSDIRNAME, proc_root_fs); | |
379 | #else | |
380 | sprintf(path, "fs/%s", PROC_FSDIRNAME); | |
381 | openafs_procfs = proc_mkdir(path, NULL); | |
382 | #endif | |
383 | #ifdef HAVE_LINUX_SEQ_FILE_H | |
384 | entry = afs_proc_create("unixusers", 0, openafs_procfs, &afs_unixuser_fops); | |
385 | # if defined(STRUCT_PROC_DIR_ENTRY_HAS_OWNER) | |
386 | if (entry) | |
387 | entry->owner = THIS_MODULE; | |
388 | # endif | |
389 | entry = afs_proc_create(PROC_CELLSERVDB_NAME, 0, openafs_procfs, &afs_csdb_operations); | |
390 | #else | |
391 | entry = create_proc_info_entry(PROC_CELLSERVDB_NAME, (S_IFREG|S_IRUGO), openafs_procfs, csdbproc_info); | |
392 | #endif | |
393 | #if defined(STRUCT_PROC_DIR_ENTRY_HAS_OWNER) | |
394 | if (entry) | |
395 | entry->owner = THIS_MODULE; | |
396 | #endif | |
397 | } | |
398 | ||
399 | void | |
400 | osi_proc_clean(void) | |
401 | { | |
402 | #if !defined(EXPORTED_PROC_ROOT_FS) | |
403 | char path[64]; | |
404 | #endif | |
405 | ||
406 | remove_proc_entry(PROC_CELLSERVDB_NAME, openafs_procfs); | |
407 | #ifdef HAVE_LINUX_SEQ_FILE_H | |
408 | remove_proc_entry("unixusers", openafs_procfs); | |
409 | #endif | |
410 | #if defined(EXPORTED_PROC_ROOT_FS) | |
411 | remove_proc_entry(PROC_FSDIRNAME, proc_root_fs); | |
412 | #else | |
413 | sprintf(path, "fs/%s", PROC_FSDIRNAME); | |
414 | remove_proc_entry(path, NULL); | |
415 | #endif | |
416 | } |