~ubuntu-branches/ubuntu/raring/openafs/raring

« back to all changes in this revision

Viewing changes to .pc/3.8-compat/src/afs/afs_pioctl.c

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-03-05 01:01:49 UTC
  • mfrom: (44.1.1 raring-proposed)
  • Revision ID: package-import@ubuntu.com-20130305010149-3ui1dhq9a2fw9abp
Tags: 1.6.2-1+ubuntu2
Explicitly include -pthread in UAFS_XLIBS to fix build failure

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <afsconfig.h>
 
11
#include "afs/param.h"
 
12
 
 
13
 
 
14
#include "afs/sysincludes.h"    /* Standard vendor system headers */
 
15
#ifdef AFS_OBSD_ENV
 
16
#include "h/syscallargs.h"
 
17
#endif
 
18
#ifdef AFS_FBSD_ENV
 
19
#include "h/sysproto.h"
 
20
#endif
 
21
#ifdef AFS_NBSD40_ENV
 
22
#include <sys/ioctl.h>
 
23
#include <sys/ioccom.h>
 
24
#endif
 
25
#include "afsincludes.h"        /* Afs-based standard headers */
 
26
#include "afs/afs_stats.h"      /* afs statistics */
 
27
#include "afs/vice.h"
 
28
#include "afs/afs_bypasscache.h"
 
29
#include "rx/rx_globals.h"
 
30
 
 
31
struct VenusFid afs_rootFid;
 
32
afs_int32 afs_waitForever = 0;
 
33
short afs_waitForeverCount = 0;
 
34
afs_int32 afs_showflags = GAGUSER | GAGCONSOLE; /* show all messages */
 
35
 
 
36
afs_int32 afs_is_disconnected;
 
37
afs_int32 afs_is_discon_rw;
 
38
/* On reconnection, turn this knob on until it finishes,
 
39
 * then turn it off.
 
40
 */
 
41
afs_int32 afs_in_sync = 0;
 
42
 
 
43
struct afs_pdata {
 
44
    char *ptr;
 
45
    size_t remaining;
 
46
};
 
47
 
 
48
/*
 
49
 * A set of handy little functions for encoding and decoding
 
50
 * pioctls without losing your marbles, or memory integrity
 
51
 */
 
52
 
 
53
static_inline int
 
54
afs_pd_alloc(struct afs_pdata *apd, size_t size)
 
55
{
 
56
 
 
57
    if (size > AFS_LRALLOCSIZ)
 
58
        apd->ptr = osi_Alloc(size + 1);
 
59
    else
 
60
        apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
 
61
 
 
62
    if (apd->ptr == NULL)
 
63
        return ENOMEM;
 
64
 
 
65
    apd->remaining = size;
 
66
 
 
67
    return 0;
 
68
}
 
69
 
 
70
static_inline void
 
71
afs_pd_free(struct afs_pdata *apd)
 
72
{
 
73
    if (apd->ptr == NULL)
 
74
        return;
 
75
 
 
76
    if (apd->remaining > AFS_LRALLOCSIZ)
 
77
        osi_Free(apd->ptr, apd->remaining + 1);
 
78
    else
 
79
        osi_FreeLargeSpace(apd->ptr);
 
80
 
 
81
    apd->ptr = NULL;
 
82
    apd->remaining = 0;
 
83
}
 
84
 
 
85
static_inline char *
 
86
afs_pd_where(struct afs_pdata *apd)
 
87
{
 
88
    return apd ? apd->ptr : NULL;
 
89
}
 
90
 
 
91
static_inline size_t
 
92
afs_pd_remaining(struct afs_pdata *apd)
 
93
{
 
94
    return apd ? apd->remaining : 0;
 
95
}
 
96
 
 
97
static_inline int
 
98
afs_pd_skip(struct afs_pdata *apd, size_t skip)
 
99
{
 
100
    if (apd == NULL || apd->remaining < skip)
 
101
        return EINVAL;
 
102
    apd->remaining -= skip;
 
103
    apd->ptr += skip;
 
104
 
 
105
    return 0;
 
106
}
 
107
 
 
108
static_inline int
 
109
afs_pd_getBytes(struct afs_pdata *apd, void *dest, size_t bytes)
 
110
{
 
111
    if (apd == NULL || apd->remaining < bytes)
 
112
        return EINVAL;
 
113
    apd->remaining -= bytes;
 
114
    memcpy(dest, apd->ptr, bytes);
 
115
    apd->ptr += bytes;
 
116
    return 0;
 
117
}
 
118
 
 
119
static_inline int
 
120
afs_pd_getInt(struct afs_pdata *apd, afs_int32 *val)
 
121
{
 
122
    return afs_pd_getBytes(apd, val, sizeof(*val));
 
123
}
 
124
 
 
125
static_inline int
 
126
afs_pd_getUint(struct afs_pdata *apd, afs_uint32 *val)
 
127
{
 
128
    return afs_pd_getBytes(apd, val, sizeof(*val));
 
129
}
 
130
 
 
131
static_inline void *
 
132
afs_pd_inline(struct afs_pdata *apd, size_t bytes)
 
133
{
 
134
    void *ret;
 
135
 
 
136
    if (apd == NULL || apd->remaining < bytes)
 
137
        return NULL;
 
138
 
 
139
    ret = apd->ptr;
 
140
 
 
141
    apd->remaining -= bytes;
 
142
    apd->ptr += bytes;
 
143
 
 
144
    return ret;
 
145
}
 
146
 
 
147
static_inline int
 
148
afs_pd_getString(struct afs_pdata *apd, char *str, size_t maxLen)
 
149
{
 
150
    size_t len;
 
151
 
 
152
    if (apd == NULL || apd->remaining <= 0)
 
153
        return EINVAL;
 
154
    len = strlen(apd->ptr) + 1;
 
155
    if (len > maxLen)
 
156
        return E2BIG;
 
157
    memcpy(str, apd->ptr, len);
 
158
    apd->ptr += len;
 
159
    apd->remaining -= len;
 
160
    return 0;
 
161
}
 
162
 
 
163
static_inline int
 
164
afs_pd_getStringPtr(struct afs_pdata *apd, char **str)
 
165
{
 
166
    size_t len;
 
167
 
 
168
    if (apd == NULL || apd->remaining <= 0)
 
169
        return EINVAL;
 
170
    len = strlen(apd->ptr) + 1;
 
171
    *str = apd->ptr;
 
172
    apd->ptr += len;
 
173
    apd->remaining -= len;
 
174
    return 0;
 
175
}
 
176
 
 
177
static_inline int
 
178
afs_pd_putBytes(struct afs_pdata *apd, const void *bytes, size_t len)
 
179
{
 
180
    if (apd == NULL || apd->remaining < len)
 
181
        return E2BIG;
 
182
    memcpy(apd->ptr, bytes, len);
 
183
    apd->ptr += len;
 
184
    apd->remaining -= len;
 
185
    return 0;
 
186
}
 
187
 
 
188
static_inline int
 
189
afs_pd_putInt(struct afs_pdata *apd, afs_int32 val)
 
190
{
 
191
    return afs_pd_putBytes(apd, &val, sizeof(val));
 
192
}
 
193
 
 
194
static_inline int
 
195
afs_pd_putString(struct afs_pdata *apd, char *str) {
 
196
 
 
197
    /* Add 1 so we copy the NULL too */
 
198
    return afs_pd_putBytes(apd, str, strlen(str) +1);
 
199
}
 
200
 
 
201
/*!
 
202
 * \defgroup pioctl Path IOCTL functions
 
203
 *
 
204
 * DECL_PIOCTL is a macro defined to contain the following parameters for functions:
 
205
 *
 
206
 * \param[in] avc
 
207
 *      the AFS vcache structure in use by pioctl
 
208
 * \param[in] afun
 
209
 *      not in use
 
210
 * \param[in] areq
 
211
 *      the AFS vrequest structure
 
212
 * \param[in] ain
 
213
 *      an afs_pdata block describing the data received from the caller
 
214
 * \param[in] aout
 
215
 *      an afs_pdata block describing a pre-allocated block for output
 
216
 * \param[in] acred
 
217
 *      UNIX credentials structure underlying the operation
 
218
 */
 
219
 
 
220
#define DECL_PIOCTL(x) \
 
221
        static int x(struct vcache *avc, int afun, struct vrequest *areq, \
 
222
                     struct afs_pdata *ain, struct afs_pdata *aout, \
 
223
                     afs_ucred_t **acred)
 
224
 
 
225
/* Prototypes for pioctl routines */
 
226
DECL_PIOCTL(PGetFID);
 
227
DECL_PIOCTL(PSetAcl);
 
228
DECL_PIOCTL(PStoreBehind);
 
229
DECL_PIOCTL(PGCPAGs);
 
230
DECL_PIOCTL(PGetAcl);
 
231
DECL_PIOCTL(PNoop);
 
232
DECL_PIOCTL(PBogus);
 
233
DECL_PIOCTL(PGetFileCell);
 
234
DECL_PIOCTL(PGetWSCell);
 
235
DECL_PIOCTL(PGetUserCell);
 
236
DECL_PIOCTL(PSetTokens);
 
237
DECL_PIOCTL(PGetVolumeStatus);
 
238
DECL_PIOCTL(PSetVolumeStatus);
 
239
DECL_PIOCTL(PFlush);
 
240
DECL_PIOCTL(PNewStatMount);
 
241
DECL_PIOCTL(PGetTokens);
 
242
DECL_PIOCTL(PUnlog);
 
243
DECL_PIOCTL(PMariner);
 
244
DECL_PIOCTL(PCheckServers);
 
245
DECL_PIOCTL(PCheckVolNames);
 
246
DECL_PIOCTL(PCheckAuth);
 
247
DECL_PIOCTL(PFindVolume);
 
248
DECL_PIOCTL(PViceAccess);
 
249
DECL_PIOCTL(PSetCacheSize);
 
250
DECL_PIOCTL(PGetCacheSize);
 
251
DECL_PIOCTL(PRemoveCallBack);
 
252
DECL_PIOCTL(PNewCell);
 
253
DECL_PIOCTL(PNewAlias);
 
254
DECL_PIOCTL(PListCells);
 
255
DECL_PIOCTL(PListAliases);
 
256
DECL_PIOCTL(PRemoveMount);
 
257
DECL_PIOCTL(PGetCellStatus);
 
258
DECL_PIOCTL(PSetCellStatus);
 
259
DECL_PIOCTL(PFlushVolumeData);
 
260
DECL_PIOCTL(PGetVnodeXStatus);
 
261
DECL_PIOCTL(PGetVnodeXStatus2);
 
262
DECL_PIOCTL(PSetSysName);
 
263
DECL_PIOCTL(PSetSPrefs);
 
264
DECL_PIOCTL(PSetSPrefs33);
 
265
DECL_PIOCTL(PGetSPrefs);
 
266
DECL_PIOCTL(PExportAfs);
 
267
DECL_PIOCTL(PGag);
 
268
DECL_PIOCTL(PTwiddleRx);
 
269
DECL_PIOCTL(PGetInitParams);
 
270
DECL_PIOCTL(PGetRxkcrypt);
 
271
DECL_PIOCTL(PSetRxkcrypt);
 
272
DECL_PIOCTL(PGetCPrefs);
 
273
DECL_PIOCTL(PSetCPrefs);
 
274
DECL_PIOCTL(PFlushMount);
 
275
DECL_PIOCTL(PRxStatProc);
 
276
DECL_PIOCTL(PRxStatPeer);
 
277
DECL_PIOCTL(PPrefetchFromTape);
 
278
DECL_PIOCTL(PFsCmd);
 
279
DECL_PIOCTL(PCallBackAddr);
 
280
DECL_PIOCTL(PDiscon);
 
281
DECL_PIOCTL(PNFSNukeCreds);
 
282
DECL_PIOCTL(PNewUuid);
 
283
DECL_PIOCTL(PPrecache);
 
284
DECL_PIOCTL(PGetPAG);
 
285
#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
286
DECL_PIOCTL(PSetCachingThreshold);
 
287
#endif
 
288
 
 
289
/*
 
290
 * A macro that says whether we're going to need HandleClientContext().
 
291
 * This is currently used only by the nfs translator.
 
292
 */
 
293
#if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
 
294
#define AFS_NEED_CLIENTCONTEXT
 
295
#endif
 
296
 
 
297
/* Prototypes for private routines */
 
298
#ifdef AFS_NEED_CLIENTCONTEXT
 
299
static int HandleClientContext(struct afs_ioctl *ablob, int *com,
 
300
                               afs_ucred_t **acred,
 
301
                               afs_ucred_t *credp);
 
302
#endif
 
303
int HandleIoctl(struct vcache *avc, afs_int32 acom,
 
304
                struct afs_ioctl *adata);
 
305
int afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
 
306
                     struct afs_ioctl *ablob, int afollow,
 
307
                     afs_ucred_t **acred);
 
308
static int Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
 
309
                    afs_ucred_t *acred);
 
310
 
 
311
typedef int (*pioctlFunction) (struct vcache *, int, struct vrequest *,
 
312
                               struct afs_pdata *, struct afs_pdata *,
 
313
                               afs_ucred_t **);
 
314
 
 
315
static pioctlFunction VpioctlSw[] = {
 
316
    PBogus,                     /* 0 */
 
317
    PSetAcl,                    /* 1 */
 
318
    PGetAcl,                    /* 2 */
 
319
    PSetTokens,                 /* 3 */
 
320
    PGetVolumeStatus,           /* 4 */
 
321
    PSetVolumeStatus,           /* 5 */
 
322
    PFlush,                     /* 6 */
 
323
    PBogus,                     /* 7 */
 
324
    PGetTokens,                 /* 8 */
 
325
    PUnlog,                     /* 9 */
 
326
    PCheckServers,              /* 10 */
 
327
    PCheckVolNames,             /* 11 */
 
328
    PCheckAuth,                 /* 12 */
 
329
    PBogus,                     /* 13 -- used to be quick check time */
 
330
    PFindVolume,                /* 14 */
 
331
    PBogus,                     /* 15 -- prefetch is now special-cased; see pioctl code! */
 
332
    PBogus,                     /* 16 -- used to be testing code */
 
333
    PNoop,                      /* 17 -- used to be enable group */
 
334
    PNoop,                      /* 18 -- used to be disable group */
 
335
    PBogus,                     /* 19 -- used to be list group */
 
336
    PViceAccess,                /* 20 */
 
337
    PUnlog,                     /* 21 -- unlog *is* unpag in this system */
 
338
    PGetFID,                    /* 22 -- get file ID */
 
339
    PBogus,                     /* 23 -- used to be waitforever */
 
340
    PSetCacheSize,              /* 24 */
 
341
    PRemoveCallBack,            /* 25 -- flush only the callback */
 
342
    PNewCell,                   /* 26 */
 
343
    PListCells,                 /* 27 */
 
344
    PRemoveMount,               /* 28 -- delete mount point */
 
345
    PNewStatMount,              /* 29 -- new style mount point stat */
 
346
    PGetFileCell,               /* 30 -- get cell name for input file */
 
347
    PGetWSCell,                 /* 31 -- get cell name for workstation */
 
348
    PMariner,                   /* 32 - set/get mariner host */
 
349
    PGetUserCell,               /* 33 -- get cell name for user */
 
350
    PBogus,                     /* 34 -- Enable/Disable logging */
 
351
    PGetCellStatus,             /* 35 */
 
352
    PSetCellStatus,             /* 36 */
 
353
    PFlushVolumeData,           /* 37 -- flush all data from a volume */
 
354
    PSetSysName,                /* 38 - Set system name */
 
355
    PExportAfs,                 /* 39 - Export Afs to remote nfs clients */
 
356
    PGetCacheSize,              /* 40 - get cache size and usage */
 
357
    PGetVnodeXStatus,           /* 41 - get vcache's special status */
 
358
    PSetSPrefs33,               /* 42 - Set CM Server preferences... */
 
359
    PGetSPrefs,                 /* 43 - Get CM Server preferences... */
 
360
    PGag,                       /* 44 - turn off/on all CM messages */
 
361
    PTwiddleRx,                 /* 45 - adjust some RX params       */
 
362
    PSetSPrefs,                 /* 46 - Set CM Server preferences... */
 
363
    PStoreBehind,               /* 47 - set degree of store behind to be done */
 
364
    PGCPAGs,                    /* 48 - disable automatic pag gc-ing */
 
365
    PGetInitParams,             /* 49 - get initial cm params */
 
366
    PGetCPrefs,                 /* 50 - get client interface addresses */
 
367
    PSetCPrefs,                 /* 51 - set client interface addresses */
 
368
    PFlushMount,                /* 52 - flush mount symlink data */
 
369
    PRxStatProc,                /* 53 - control process RX statistics */
 
370
    PRxStatPeer,                /* 54 - control peer RX statistics */
 
371
    PGetRxkcrypt,               /* 55 -- Get rxkad encryption flag */
 
372
    PSetRxkcrypt,               /* 56 -- Set rxkad encryption flag */
 
373
    PBogus,                     /* 57 -- arla: set file prio */
 
374
    PBogus,                     /* 58 -- arla: fallback getfh */
 
375
    PBogus,                     /* 59 -- arla: fallback fhopen */
 
376
    PBogus,                     /* 60 -- arla: controls xfsdebug */
 
377
    PBogus,                     /* 61 -- arla: controls arla debug */
 
378
    PBogus,                     /* 62 -- arla: debug interface */
 
379
    PBogus,                     /* 63 -- arla: print xfs status */
 
380
    PBogus,                     /* 64 -- arla: force cache check */
 
381
    PBogus,                     /* 65 -- arla: break callback */
 
382
    PPrefetchFromTape,          /* 66 -- MR-AFS: prefetch file from tape */
 
383
    PFsCmd,                     /* 67 -- RXOSD: generic commnd interface */
 
384
    PBogus,                     /* 68 -- arla: fetch stats */
 
385
    PGetVnodeXStatus2,          /* 69 - get caller access and some vcache status */
 
386
};
 
387
 
 
388
static pioctlFunction CpioctlSw[] = {
 
389
    PBogus,                     /* 0 */
 
390
    PNewAlias,                  /* 1 -- create new cell alias */
 
391
    PListAliases,               /* 2 -- list cell aliases */
 
392
    PCallBackAddr,              /* 3 -- request addr for callback rxcon */
 
393
    PBogus,                     /* 4 */
 
394
    PDiscon,                    /* 5 -- get/set discon mode */
 
395
    PBogus,                     /* 6 */
 
396
    PBogus,                     /* 7 */
 
397
    PBogus,                     /* 8 */
 
398
    PNewUuid,                   /* 9 */
 
399
    PBogus,                     /* 10 */
 
400
    PBogus,                     /* 11 */
 
401
    PPrecache,                  /* 12 */
 
402
    PGetPAG,                    /* 13 */
 
403
};
 
404
 
 
405
static pioctlFunction OpioctlSw[]  = {
 
406
    PBogus,                     /* 0 */
 
407
    PNFSNukeCreds,              /* 1 -- nuke all creds for NFS client */
 
408
#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
409
    PSetCachingThreshold        /* 2 -- get/set cache-bypass size threshold */
 
410
#else
 
411
    PNoop                       /* 2 -- get/set cache-bypass size threshold */
 
412
#endif
 
413
};
 
414
 
 
415
#define PSetClientContext 99    /*  Special pioctl to setup caller's creds  */
 
416
int afs_nobody = NFS_NOBODY;
 
417
 
 
418
int
 
419
HandleIoctl(struct vcache *avc, afs_int32 acom,
 
420
            struct afs_ioctl *adata)
 
421
{
 
422
    afs_int32 code;
 
423
 
 
424
    code = 0;
 
425
    AFS_STATCNT(HandleIoctl);
 
426
 
 
427
    switch (acom & 0xff) {
 
428
    case 1:
 
429
        avc->f.states |= CSafeStore;
 
430
        avc->asynchrony = 0;
 
431
        /* SXW - Should we force a MetaData flush for this flag setting */
 
432
        break;
 
433
 
 
434
        /* case 2 used to be abort store, but this is no longer provided,
 
435
         * since it is impossible to implement under normal Unix.
 
436
         */
 
437
 
 
438
    case 3:{
 
439
            /* return the name of the cell this file is open on */
 
440
            struct cell *tcell;
 
441
            afs_int32 i;
 
442
 
 
443
            tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
 
444
            if (tcell) {
 
445
                i = strlen(tcell->cellName) + 1;        /* bytes to copy out */
 
446
 
 
447
                if (i > adata->out_size) {
 
448
                    /* 0 means we're not interested in the output */
 
449
                    if (adata->out_size != 0)
 
450
                        code = EFAULT;
 
451
                } else {
 
452
                    /* do the copy */
 
453
                    AFS_COPYOUT(tcell->cellName, adata->out, i, code);
 
454
                }
 
455
                afs_PutCell(tcell, READ_LOCK);
 
456
            } else
 
457
                code = ENOTTY;
 
458
        }
 
459
        break;
 
460
 
 
461
    case 49:                    /* VIOC_GETINITPARAMS */
 
462
        if (adata->out_size < sizeof(struct cm_initparams)) {
 
463
            code = EFAULT;
 
464
        } else {
 
465
            AFS_COPYOUT(&cm_initParams, adata->out,
 
466
                        sizeof(struct cm_initparams), code);
 
467
        }
 
468
        break;
 
469
 
 
470
    default:
 
471
 
 
472
        code = EINVAL;
 
473
#ifdef AFS_AIX51_ENV
 
474
        code = ENOSYS;
 
475
#endif
 
476
        break;
 
477
    }
 
478
    return code;                /* so far, none implemented */
 
479
}
 
480
 
 
481
#ifdef AFS_AIX_ENV
 
482
/* For aix we don't temporarily bypass ioctl(2) but rather do our
 
483
 * thing directly in the vnode layer call, VNOP_IOCTL; thus afs_ioctl
 
484
 * is now called from afs_gn_ioctl.
 
485
 */
 
486
int
 
487
afs_ioctl(struct vcache *tvc, int cmd, int arg)
 
488
{
 
489
    struct afs_ioctl data;
 
490
    int error = 0;
 
491
 
 
492
    AFS_STATCNT(afs_ioctl);
 
493
    if (((cmd >> 8) & 0xff) == 'V') {
 
494
        /* This is a VICEIOCTL call */
 
495
        AFS_COPYIN(arg, (caddr_t) & data, sizeof(data), error);
 
496
        if (error)
 
497
            return (error);
 
498
        error = HandleIoctl(tvc, cmd, &data);
 
499
        return (error);
 
500
    } else {
 
501
        /* No-op call; just return. */
 
502
        return (ENOTTY);
 
503
    }
 
504
}
 
505
# if defined(AFS_AIX32_ENV)
 
506
#  if defined(AFS_AIX51_ENV)
 
507
#   ifdef __64BIT__
 
508
int
 
509
kioctl(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
 
510
           caddr_t arg3)
 
511
#   else /* __64BIT__ */
 
512
int
 
513
kioctl32(int fdes, int com, caddr_t arg, caddr_t ext, caddr_t arg2,
 
514
             caddr_t arg3)
 
515
#   endif /* __64BIT__ */
 
516
#  else
 
517
int
 
518
kioctl(int fdes, int com, caddr_t arg, caddr_t ext)
 
519
#  endif /* AFS_AIX51_ENV */
 
520
{
 
521
    struct a {
 
522
        int fd, com;
 
523
        caddr_t arg, ext;
 
524
#  ifdef AFS_AIX51_ENV
 
525
        caddr_t arg2, arg3;
 
526
#  endif
 
527
    } u_uap, *uap = &u_uap;
 
528
    struct file *fd;
 
529
    struct vcache *tvc;
 
530
    int ioctlDone = 0, code = 0;
 
531
 
 
532
    AFS_STATCNT(afs_xioctl);
 
533
    uap->fd = fdes;
 
534
    uap->com = com;
 
535
    uap->arg = arg;
 
536
#  ifdef AFS_AIX51_ENV
 
537
    uap->arg2 = arg2;
 
538
    uap->arg3 = arg3;
 
539
#  endif
 
540
    if (setuerror(getf(uap->fd, &fd))) {
 
541
        return -1;
 
542
    }
 
543
    if (fd->f_type == DTYPE_VNODE) {
 
544
        /* good, this is a vnode; next see if it is an AFS vnode */
 
545
        tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
 
546
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
547
            /* This is an AFS vnode */
 
548
            if (((uap->com >> 8) & 0xff) == 'V') {
 
549
                struct afs_ioctl *datap;
 
550
                AFS_GLOCK();
 
551
                datap =
 
552
                    (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
553
                code=copyin_afs_ioctl((char *)uap->arg, datap);
 
554
                if (code) {
 
555
                    osi_FreeSmallSpace(datap);
 
556
                    AFS_GUNLOCK();
 
557
#  if defined(AFS_AIX41_ENV)
 
558
                    ufdrele(uap->fd);
 
559
#  endif
 
560
                    return (setuerror(code), code);
 
561
                }
 
562
                code = HandleIoctl(tvc, uap->com, datap);
 
563
                osi_FreeSmallSpace(datap);
 
564
                AFS_GUNLOCK();
 
565
                ioctlDone = 1;
 
566
#  if defined(AFS_AIX41_ENV)
 
567
                ufdrele(uap->fd);
 
568
#  endif
 
569
             }
 
570
        }
 
571
    }
 
572
    if (!ioctlDone) {
 
573
#  if defined(AFS_AIX41_ENV)
 
574
        ufdrele(uap->fd);
 
575
#   if defined(AFS_AIX51_ENV)
 
576
#    ifdef __64BIT__
 
577
        code = okioctl(fdes, com, arg, ext, arg2, arg3);
 
578
#    else /* __64BIT__ */
 
579
        code = okioctl32(fdes, com, arg, ext, arg2, arg3);
 
580
#    endif /* __64BIT__ */
 
581
#   else /* !AFS_AIX51_ENV */
 
582
        code = okioctl(fdes, com, arg, ext);
 
583
#   endif /* AFS_AIX51_ENV */
 
584
        return code;
 
585
#  elif defined(AFS_AIX32_ENV)
 
586
        okioctl(fdes, com, arg, ext);
 
587
#  endif
 
588
    }
 
589
#  if defined(KERNEL_HAVE_UERROR)
 
590
    if (!getuerror())
 
591
        setuerror(code);
 
592
#   if !defined(AFS_AIX41_ENV)
 
593
    return (getuerror()? -1 : u.u_ioctlrv);
 
594
#   else
 
595
    return getuerror()? -1 : 0;
 
596
#   endif
 
597
#  endif
 
598
    return 0;
 
599
}
 
600
# endif
 
601
 
 
602
#elif defined(AFS_SGI_ENV)
 
603
# if defined(AFS_SGI65_ENV)
 
604
afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
 
605
          rval_t * rvalp, struct vopbd * vbds)
 
606
# else
 
607
afs_ioctl(OSI_VN_DECL(tvc), int cmd, void *arg, int flag, cred_t * cr,
 
608
          rval_t * rvalp, struct vopbd * vbds)
 
609
# endif
 
610
{
 
611
    struct afs_ioctl data;
 
612
    int error = 0;
 
613
    int locked;
 
614
 
 
615
    OSI_VN_CONVERT(tvc);
 
616
 
 
617
    AFS_STATCNT(afs_ioctl);
 
618
    if (((cmd >> 8) & 0xff) == 'V') {
 
619
        /* This is a VICEIOCTL call */
 
620
        error = copyin_afs_ioctl(arg, &data);
 
621
        if (error)
 
622
            return (error);
 
623
        locked = ISAFS_GLOCK();
 
624
        if (!locked)
 
625
            AFS_GLOCK();
 
626
        error = HandleIoctl(tvc, cmd, &data);
 
627
        if (!locked)
 
628
            AFS_GUNLOCK();
 
629
        return (error);
 
630
    } else {
 
631
        /* No-op call; just return. */
 
632
        return (ENOTTY);
 
633
    }
 
634
}
 
635
#elif defined(AFS_SUN5_ENV)
 
636
struct afs_ioctl_sys {
 
637
    int fd;
 
638
    int com;
 
639
    int arg;
 
640
};
 
641
 
 
642
int
 
643
afs_xioctl(struct afs_ioctl_sys *uap, rval_t *rvp)
 
644
{
 
645
    struct file *fd;
 
646
    struct vcache *tvc;
 
647
    int ioctlDone = 0, code = 0;
 
648
 
 
649
    AFS_STATCNT(afs_xioctl);
 
650
# if defined(AFS_SUN57_ENV)
 
651
    fd = getf(uap->fd);
 
652
    if (!fd)
 
653
        return (EBADF);
 
654
# elif defined(AFS_SUN54_ENV)
 
655
    fd = GETF(uap->fd);
 
656
    if (!fd)
 
657
        return (EBADF);
 
658
# else
 
659
    if (code = getf(uap->fd, &fd)) {
 
660
        return (code);
 
661
    }
 
662
# endif
 
663
    if (fd->f_vnode->v_type == VREG || fd->f_vnode->v_type == VDIR) {
 
664
        tvc = VTOAFS(fd->f_vnode);      /* valid, given a vnode */
 
665
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
666
            /* This is an AFS vnode */
 
667
            if (((uap->com >> 8) & 0xff) == 'V') {
 
668
                struct afs_ioctl *datap;
 
669
                AFS_GLOCK();
 
670
                datap =
 
671
                    (struct afs_ioctl *)osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
672
                code=copyin_afs_ioctl((char *)uap->arg, datap);
 
673
                if (code) {
 
674
                    osi_FreeSmallSpace(datap);
 
675
                    AFS_GUNLOCK();
 
676
# if defined(AFS_SUN54_ENV)
 
677
                    releasef(uap->fd);
 
678
# else
 
679
                    releasef(fd);
 
680
# endif
 
681
                    return (EFAULT);
 
682
                }
 
683
                code = HandleIoctl(tvc, uap->com, datap);
 
684
                osi_FreeSmallSpace(datap);
 
685
                AFS_GUNLOCK();
 
686
                ioctlDone = 1;
 
687
            }
 
688
        }
 
689
    }
 
690
# if defined(AFS_SUN57_ENV)
 
691
    releasef(uap->fd);
 
692
# elif defined(AFS_SUN54_ENV)
 
693
    RELEASEF(uap->fd);
 
694
# else
 
695
    releasef(fd);
 
696
# endif
 
697
    if (!ioctlDone)
 
698
        code = ioctl(uap, rvp);
 
699
 
 
700
    return (code);
 
701
}
 
702
#elif defined(AFS_LINUX22_ENV)
 
703
struct afs_ioctl_sys {
 
704
    unsigned int com;
 
705
    unsigned long arg;
 
706
};
 
707
int
 
708
afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
 
709
           unsigned long arg)
 
710
{
 
711
    struct afs_ioctl_sys ua, *uap = &ua;
 
712
    struct vcache *tvc;
 
713
    int ioctlDone = 0, code = 0;
 
714
 
 
715
    AFS_STATCNT(afs_xioctl);
 
716
    ua.com = com;
 
717
    ua.arg = arg;
 
718
 
 
719
    tvc = VTOAFS(ip);
 
720
    if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
721
        /* This is an AFS vnode */
 
722
        if (((uap->com >> 8) & 0xff) == 'V') {
 
723
            struct afs_ioctl *datap;
 
724
            AFS_GLOCK();
 
725
            datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
726
            code = copyin_afs_ioctl((char *)uap->arg, datap);
 
727
            if (code) {
 
728
                osi_FreeSmallSpace(datap);
 
729
                AFS_GUNLOCK();
 
730
                return -code;
 
731
            }
 
732
            code = HandleIoctl(tvc, uap->com, datap);
 
733
            osi_FreeSmallSpace(datap);
 
734
            AFS_GUNLOCK();
 
735
            ioctlDone = 1;
 
736
        }
 
737
        else
 
738
            code = EINVAL;
 
739
    }
 
740
    return -code;
 
741
}
 
742
#elif defined(AFS_DARWIN_ENV) && !defined(AFS_DARWIN80_ENV)
 
743
struct ioctl_args {
 
744
    int fd;
 
745
    u_long com;
 
746
    caddr_t arg;
 
747
};
 
748
 
 
749
int
 
750
afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
 
751
{
 
752
    struct file *fd;
 
753
    struct vcache *tvc;
 
754
    int ioctlDone = 0, code = 0;
 
755
 
 
756
    AFS_STATCNT(afs_xioctl);
 
757
    if ((code = fdgetf(p, uap->fd, &fd)))
 
758
        return code;
 
759
    if (fd->f_type == DTYPE_VNODE) {
 
760
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
 
761
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
762
            /* This is an AFS vnode */
 
763
            if (((uap->com >> 8) & 0xff) == 'V') {
 
764
                struct afs_ioctl *datap;
 
765
                AFS_GLOCK();
 
766
                datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
767
                code = copyin_afs_ioctl((char *)uap->arg, datap);
 
768
                if (code) {
 
769
                    osi_FreeSmallSpace(datap);
 
770
                    AFS_GUNLOCK();
 
771
                    return code;
 
772
                }
 
773
                code = HandleIoctl(tvc, uap->com, datap);
 
774
                osi_FreeSmallSpace(datap);
 
775
                AFS_GUNLOCK();
 
776
                ioctlDone = 1;
 
777
            }
 
778
        }
 
779
    }
 
780
 
 
781
    if (!ioctlDone)
 
782
        return ioctl(p, uap, retval);
 
783
 
 
784
    return (code);
 
785
}
 
786
#elif defined(AFS_XBSD_ENV)
 
787
# if defined(AFS_FBSD_ENV)
 
788
#  define arg data
 
789
int
 
790
afs_xioctl(struct thread *td, struct ioctl_args *uap,
 
791
           register_t *retval)
 
792
{
 
793
    afs_proc_t *p = td->td_proc;
 
794
# else
 
795
struct ioctl_args {
 
796
    int fd;
 
797
    u_long com;
 
798
    caddr_t arg;
 
799
};
 
800
 
 
801
int
 
802
afs_xioctl(afs_proc_t *p, struct ioctl_args *uap, register_t *retval)
 
803
{
 
804
# endif
 
805
    struct filedesc *fdp;
 
806
    struct vcache *tvc;
 
807
    int ioctlDone = 0, code = 0;
 
808
    struct file *fd;
 
809
 
 
810
    AFS_STATCNT(afs_xioctl);
 
811
#   if defined(AFS_NBSD40_ENV)
 
812
     fdp = p->l_proc->p_fd;
 
813
#   else
 
814
    fdp = p->p_fd;
 
815
#endif
 
816
    if ((u_int) uap->fd >= fdp->fd_nfiles
 
817
        || (fd = fdp->fd_ofiles[uap->fd]) == NULL)
 
818
        return EBADF;
 
819
    if ((fd->f_flag & (FREAD | FWRITE)) == 0)
 
820
        return EBADF;
 
821
    /* first determine whether this is any sort of vnode */
 
822
    if (fd->f_type == DTYPE_VNODE) {
 
823
        /* good, this is a vnode; next see if it is an AFS vnode */
 
824
# if defined(AFS_OBSD_ENV)
 
825
        tvc =
 
826
            IsAfsVnode((struct vnode *)fd->
 
827
                       f_data) ? VTOAFS((struct vnode *)fd->f_data) : NULL;
 
828
# else
 
829
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
 
830
# endif
 
831
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
832
            /* This is an AFS vnode */
 
833
            if (((uap->com >> 8) & 0xff) == 'V') {
 
834
                struct afs_ioctl *datap;
 
835
                AFS_GLOCK();
 
836
                datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
837
                code = copyin_afs_ioctl((char *)uap->arg, datap);
 
838
                if (code) {
 
839
                    osi_FreeSmallSpace(datap);
 
840
                    AFS_GUNLOCK();
 
841
                    return code;
 
842
                }
 
843
                code = HandleIoctl(tvc, uap->com, datap);
 
844
                osi_FreeSmallSpace(datap);
 
845
                AFS_GUNLOCK();
 
846
                ioctlDone = 1;
 
847
            }
 
848
        }
 
849
    }
 
850
 
 
851
    if (!ioctlDone) {
 
852
# if defined(AFS_FBSD_ENV)
 
853
#  if (__FreeBSD_version >= 900044)
 
854
        return sys_ioctl(td, uap);
 
855
#  else
 
856
        return ioctl(td, uap);
 
857
#  endif
 
858
# elif defined(AFS_OBSD_ENV)
 
859
        code = sys_ioctl(p, uap, retval);
 
860
# elif defined(AFS_NBSD_ENV)
 
861
           struct lwp *l = osi_curproc();
 
862
           code = sys_ioctl(l, uap, retval);
 
863
# endif
 
864
    }
 
865
 
 
866
    return (code);
 
867
}
 
868
#elif defined(UKERNEL)
 
869
int
 
870
afs_xioctl(void)
 
871
{
 
872
    struct a {
 
873
        int fd;
 
874
        int com;
 
875
        caddr_t arg;
 
876
    } *uap = (struct a *)get_user_struct()->u_ap;
 
877
    struct file *fd;
 
878
    struct vcache *tvc;
 
879
    int ioctlDone = 0, code = 0;
 
880
 
 
881
    AFS_STATCNT(afs_xioctl);
 
882
 
 
883
    fd = getf(uap->fd);
 
884
    if (!fd)
 
885
        return (EBADF);
 
886
    /* first determine whether this is any sort of vnode */
 
887
    if (fd->f_type == DTYPE_VNODE) {
 
888
        /* good, this is a vnode; next see if it is an AFS vnode */
 
889
        tvc = VTOAFS((struct vnode *)fd->f_data);       /* valid, given a vnode */
 
890
        if (tvc && IsAfsVnode(AFSTOV(tvc))) {
 
891
            /* This is an AFS vnode */
 
892
            if (((uap->com >> 8) & 0xff) == 'V') {
 
893
                struct afs_ioctl *datap;
 
894
                AFS_GLOCK();
 
895
                datap = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
 
896
                code=copyin_afs_ioctl((char *)uap->arg, datap);
 
897
                if (code) {
 
898
                    osi_FreeSmallSpace(datap);
 
899
                    AFS_GUNLOCK();
 
900
 
 
901
                    return (setuerror(code), code);
 
902
                }
 
903
                code = HandleIoctl(tvc, uap->com, datap);
 
904
                osi_FreeSmallSpace(datap);
 
905
                AFS_GUNLOCK();
 
906
                ioctlDone = 1;
 
907
            }
 
908
        }
 
909
    }
 
910
 
 
911
    if (!ioctlDone) {
 
912
        ioctl();
 
913
    }
 
914
 
 
915
    return 0;
 
916
}
 
917
#endif /* AFS_HPUX102_ENV */
 
918
 
 
919
#if defined(AFS_SGI_ENV)
 
920
  /* "pioctl" system call entry point; just pass argument to the parameterized
 
921
   * call below */
 
922
struct pioctlargs {
 
923
    char *path;
 
924
    sysarg_t cmd;
 
925
    caddr_t cmarg;
 
926
    sysarg_t follow;
 
927
};
 
928
int
 
929
afs_pioctl(struct pioctlargs *uap, rval_t * rvp)
 
930
{
 
931
    int code;
 
932
 
 
933
    AFS_STATCNT(afs_pioctl);
 
934
    AFS_GLOCK();
 
935
    code = afs_syscall_pioctl(uap->path, uap->cmd, uap->cmarg, uap->follow);
 
936
    AFS_GUNLOCK();
 
937
# ifdef AFS_SGI64_ENV
 
938
    return code;
 
939
# else
 
940
    return u.u_error;
 
941
# endif
 
942
}
 
943
 
 
944
#elif defined(AFS_FBSD_ENV)
 
945
int
 
946
afs_pioctl(struct thread *td, void *args, int *retval)
 
947
{
 
948
    struct a {
 
949
        char *path;
 
950
        int cmd;
 
951
        caddr_t cmarg;
 
952
        int follow;
 
953
    } *uap = (struct a *)args;
 
954
 
 
955
    AFS_STATCNT(afs_pioctl);
 
956
    return (afs_syscall_pioctl
 
957
            (uap->path, uap->cmd, uap->cmarg, uap->follow, td->td_ucred));
 
958
}
 
959
 
 
960
#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
961
int
 
962
afs_pioctl(afs_proc_t *p, void *args, int *retval)
 
963
{
 
964
    struct a {
 
965
        char *path;
 
966
        int cmd;
 
967
        caddr_t cmarg;
 
968
        int follow;
 
969
    } *uap = (struct a *)args;
 
970
 
 
971
    AFS_STATCNT(afs_pioctl);
 
972
# if defined(AFS_DARWIN80_ENV) || defined(AFS_NBSD40_ENV)
 
973
    return (afs_syscall_pioctl
 
974
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
 
975
             kauth_cred_get()));
 
976
# else
 
977
    return (afs_syscall_pioctl
 
978
            (uap->path, uap->cmd, uap->cmarg, uap->follow,
 
979
#  if defined(AFS_FBSD_ENV)
 
980
             td->td_ucred));
 
981
#  else
 
982
             p->p_cred->pc_ucred));
 
983
#  endif
 
984
# endif
 
985
}
 
986
 
 
987
#endif
 
988
 
 
989
/* macro to avoid adding any more #ifdef's to pioctl code. */
 
990
#if defined(AFS_LINUX22_ENV) || defined(AFS_AIX41_ENV)
 
991
#define PIOCTL_FREE_CRED() crfree(credp)
 
992
#else
 
993
#define PIOCTL_FREE_CRED()
 
994
#endif
 
995
 
 
996
int
 
997
#ifdef  AFS_SUN5_ENV
 
998
afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
 
999
                   rval_t *vvp, afs_ucred_t *credp)
 
1000
#else
 
1001
#ifdef AFS_DARWIN100_ENV
 
1002
afs_syscall64_pioctl(user_addr_t path, unsigned int com, user_addr_t cmarg,
 
1003
                   int follow, afs_ucred_t *credp)
 
1004
#elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
1005
afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow,
 
1006
                   afs_ucred_t *credp)
 
1007
#else
 
1008
afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
 
1009
#endif
 
1010
#endif
 
1011
{
 
1012
    struct afs_ioctl data;
 
1013
#ifdef AFS_NEED_CLIENTCONTEXT
 
1014
    afs_ucred_t *tmpcred = NULL;
 
1015
#endif
 
1016
#if defined(AFS_NEED_CLIENTCONTEXT) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
1017
    afs_ucred_t *foreigncreds = NULL;
 
1018
#endif
 
1019
    afs_int32 code = 0;
 
1020
    struct vnode *vp = NULL;
 
1021
#ifdef  AFS_AIX41_ENV
 
1022
    struct ucred *credp = crref();      /* don't free until done! */
 
1023
#endif
 
1024
#ifdef AFS_LINUX22_ENV
 
1025
    cred_t *credp = crref();    /* don't free until done! */
 
1026
    struct dentry *dp;
 
1027
#endif
 
1028
 
 
1029
    AFS_STATCNT(afs_syscall_pioctl);
 
1030
    if (follow)
 
1031
        follow = 1;             /* compat. with old venus */
 
1032
    code = copyin_afs_ioctl(cmarg, &data);
 
1033
    if (code) {
 
1034
        PIOCTL_FREE_CRED();
 
1035
#if defined(KERNEL_HAVE_UERROR)
 
1036
        setuerror(code);
 
1037
#endif
 
1038
        return (code);
 
1039
    }
 
1040
    if ((com & 0xff) == PSetClientContext) {
 
1041
#ifdef AFS_NEED_CLIENTCONTEXT
 
1042
#if defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV)
 
1043
        code = HandleClientContext(&data, &com, &foreigncreds, credp);
 
1044
#else
 
1045
        code = HandleClientContext(&data, &com, &foreigncreds, osi_curcred());
 
1046
#endif
 
1047
        if (code) {
 
1048
            if (foreigncreds) {
 
1049
                crfree(foreigncreds);
 
1050
            }
 
1051
            PIOCTL_FREE_CRED();
 
1052
#if defined(KERNEL_HAVE_UERROR)
 
1053
            return (setuerror(code), code);
 
1054
#else
 
1055
            return (code);
 
1056
#endif
 
1057
        }
 
1058
#else /* AFS_NEED_CLIENTCONTEXT */
 
1059
        return EINVAL;
 
1060
#endif /* AFS_NEED_CLIENTCONTEXT */
 
1061
    }
 
1062
#ifdef AFS_NEED_CLIENTCONTEXT
 
1063
    if (foreigncreds) {
 
1064
        /*
 
1065
         * We could have done without temporary setting the u.u_cred below
 
1066
         * (foreigncreds could be passed as param the pioctl modules)
 
1067
         * but calls such as afs_osi_suser() doesn't allow that since it
 
1068
         * references u.u_cred directly.  We could, of course, do something
 
1069
         * like afs_osi_suser(cred) which, I think, is better since it
 
1070
         * generalizes and supports multi cred environments...
 
1071
         */
 
1072
#if defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
 
1073
        tmpcred = credp;
 
1074
        credp = foreigncreds;
 
1075
#elif defined(AFS_AIX41_ENV)
 
1076
        tmpcred = crref();      /* XXX */
 
1077
        crset(foreigncreds);
 
1078
#elif defined(AFS_HPUX101_ENV)
 
1079
        tmpcred = p_cred(u.u_procp);
 
1080
        set_p_cred(u.u_procp, foreigncreds);
 
1081
#elif defined(AFS_SGI_ENV)
 
1082
        tmpcred = OSI_GET_CURRENT_CRED();
 
1083
        OSI_SET_CURRENT_CRED(foreigncreds);
 
1084
#else
 
1085
        tmpcred = u.u_cred;
 
1086
        u.u_cred = foreigncreds;
 
1087
#endif
 
1088
    }
 
1089
#endif /* AFS_NEED_CLIENTCONTEXT */
 
1090
    if ((com & 0xff) == 15) {
 
1091
        /* special case prefetch so entire pathname eval occurs in helper process.
 
1092
         * otherwise, the pioctl call is essentially useless */
 
1093
#if     defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
1094
        code =
 
1095
            Prefetch(path, &data, follow,
 
1096
                     foreigncreds ? foreigncreds : credp);
 
1097
#else
 
1098
        code = Prefetch(path, &data, follow, osi_curcred());
 
1099
#endif
 
1100
        vp = NULL;
 
1101
#if defined(KERNEL_HAVE_UERROR)
 
1102
        setuerror(code);
 
1103
#endif
 
1104
        goto rescred;
 
1105
    }
 
1106
    if (path) {
 
1107
        AFS_GUNLOCK();
 
1108
#ifdef  AFS_AIX41_ENV
 
1109
        code =
 
1110
            lookupname(path, USR, follow, NULL, &vp,
 
1111
                       foreigncreds ? foreigncreds : credp);
 
1112
#else
 
1113
#ifdef AFS_LINUX22_ENV
 
1114
        code = gop_lookupname_user(path, AFS_UIOUSER, follow, &dp);
 
1115
        if (!code)
 
1116
            vp = (struct vnode *)dp->d_inode;
 
1117
#else
 
1118
        code = gop_lookupname_user(path, AFS_UIOUSER, follow, &vp);
 
1119
#if defined(AFS_FBSD80_ENV) /* XXX check on 7x */
 
1120
        if (vp != NULL)
 
1121
                VN_HOLD(vp);
 
1122
#endif /* AFS_FBSD80_ENV */
 
1123
#endif /* AFS_LINUX22_ENV */
 
1124
#endif /* AFS_AIX41_ENV */
 
1125
        AFS_GLOCK();
 
1126
        if (code) {
 
1127
            vp = NULL;
 
1128
#if defined(KERNEL_HAVE_UERROR)
 
1129
            setuerror(code);
 
1130
#endif
 
1131
            goto rescred;
 
1132
        }
 
1133
    } else
 
1134
        vp = NULL;
 
1135
 
 
1136
#if defined(AFS_SUN510_ENV)
 
1137
    if (vp && !IsAfsVnode(vp)) {
 
1138
        struct vnode *realvp;
 
1139
        if
 
1140
#ifdef AFS_SUN511_ENV
 
1141
          (VOP_REALVP(vp, &realvp, NULL) == 0)
 
1142
#else
 
1143
          (VOP_REALVP(vp, &realvp) == 0)
 
1144
#endif
 
1145
{
 
1146
            struct vnode *oldvp = vp;
 
1147
 
 
1148
            VN_HOLD(realvp);
 
1149
            vp = realvp;
 
1150
            AFS_RELE(oldvp);
 
1151
        }
 
1152
    }
 
1153
#endif
 
1154
    /* now make the call if we were passed no file, or were passed an AFS file */
 
1155
    if (!vp || IsAfsVnode(vp)) {
 
1156
#if defined(AFS_SUN5_ENV)
 
1157
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 
1158
#elif defined(AFS_AIX41_ENV)
 
1159
        {
 
1160
            struct ucred *cred1, *cred2;
 
1161
 
 
1162
            if (foreigncreds) {
 
1163
                cred1 = cred2 = foreigncreds;
 
1164
            } else {
 
1165
                cred1 = cred2 = credp;
 
1166
            }
 
1167
            code = afs_HandlePioctl(vp, com, &data, follow, &cred1);
 
1168
            if (cred1 != cred2) {
 
1169
                /* something changed the creds */
 
1170
                crset(cred1);
 
1171
            }
 
1172
        }
 
1173
#elif defined(AFS_HPUX101_ENV)
 
1174
        {
 
1175
            struct ucred *cred = p_cred(u.u_procp);
 
1176
            code = afs_HandlePioctl(vp, com, &data, follow, &cred);
 
1177
        }
 
1178
#elif defined(AFS_SGI_ENV)
 
1179
        {
 
1180
            struct cred *credp;
 
1181
            credp = OSI_GET_CURRENT_CRED();
 
1182
            code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 
1183
        }
 
1184
#elif defined(AFS_LINUX22_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
1185
        code = afs_HandlePioctl(vp, com, &data, follow, &credp);
 
1186
#elif defined(UKERNEL)
 
1187
        code = afs_HandlePioctl(vp, com, &data, follow,
 
1188
                                &(get_user_struct()->u_cred));
 
1189
#else
 
1190
        code = afs_HandlePioctl(vp, com, &data, follow, &u.u_cred);
 
1191
#endif
 
1192
    } else {
 
1193
#if defined(KERNEL_HAVE_UERROR)
 
1194
        setuerror(EINVAL);
 
1195
#else
 
1196
        code = EINVAL;          /* not in /afs */
 
1197
#endif
 
1198
    }
 
1199
 
 
1200
  rescred:
 
1201
#if defined(AFS_NEED_CLIENTCONTEXT)
 
1202
    if (foreigncreds) {
 
1203
#ifdef  AFS_AIX41_ENV
 
1204
        crset(tmpcred);         /* restore original credentials */
 
1205
#else
 
1206
#if     defined(AFS_HPUX101_ENV)
 
1207
        set_p_cred(u.u_procp, tmpcred); /* restore original credentials */
 
1208
#elif   defined(AFS_SGI_ENV)
 
1209
        OSI_SET_CURRENT_CRED(tmpcred);  /* restore original credentials */
 
1210
#elif   defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV)
 
1211
        credp = tmpcred;                /* restore original credentials */
 
1212
#else
 
1213
        osi_curcred() = tmpcred;        /* restore original credentials */
 
1214
#endif /* AFS_HPUX101_ENV */
 
1215
        crfree(foreigncreds);
 
1216
#endif /* AIX41 */
 
1217
    }
 
1218
#endif /* AFS_NEED_CLIENTCONTEXT */
 
1219
    if (vp) {
 
1220
#ifdef AFS_LINUX22_ENV
 
1221
        /*
 
1222
         * Holding the global lock when calling dput can cause a deadlock
 
1223
         * when the kernel calls back into afs_dentry_iput
 
1224
         */
 
1225
        AFS_GUNLOCK();
 
1226
        dput(dp);
 
1227
        AFS_GLOCK();
 
1228
#else
 
1229
#if defined(AFS_FBSD80_ENV)
 
1230
    if (VOP_ISLOCKED(vp))
 
1231
        VOP_UNLOCK(vp, 0);
 
1232
#endif /* AFS_FBSD80_ENV */
 
1233
        AFS_RELE(vp);           /* put vnode back */
 
1234
#endif
 
1235
    }
 
1236
    PIOCTL_FREE_CRED();
 
1237
#if defined(KERNEL_HAVE_UERROR)
 
1238
    if (!getuerror())
 
1239
        setuerror(code);
 
1240
    return (getuerror());
 
1241
#else
 
1242
    return (code);
 
1243
#endif
 
1244
}
 
1245
 
 
1246
#ifdef AFS_DARWIN100_ENV
 
1247
int
 
1248
afs_syscall_pioctl(char * path, unsigned int com, caddr_t cmarg,
 
1249
                   int follow, afs_ucred_t *credp)
 
1250
{
 
1251
    return afs_syscall64_pioctl(CAST_USER_ADDR_T(path), com,
 
1252
                                CAST_USER_ADDR_T((unsigned int)cmarg), follow,
 
1253
                                credp);
 
1254
}
 
1255
#endif
 
1256
 
 
1257
#define MAXPIOCTLTOKENLEN \
 
1258
(3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
 
1259
 
 
1260
int
 
1261
afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
 
1262
                 struct afs_ioctl *ablob, int afollow,
 
1263
                 afs_ucred_t **acred)
 
1264
{
 
1265
    struct vcache *avc;
 
1266
    struct vrequest treq;
 
1267
    afs_int32 code;
 
1268
    afs_int32 function, device;
 
1269
    struct afs_pdata input, output;
 
1270
    struct afs_pdata copyInput, copyOutput;
 
1271
    size_t outSize;
 
1272
    pioctlFunction *pioctlSw;
 
1273
    int pioctlSwSize;
 
1274
    struct afs_fakestat_state fakestate;
 
1275
 
 
1276
    memset(&input, 0, sizeof(input));
 
1277
    memset(&output, 0, sizeof(output));
 
1278
 
 
1279
    avc = avp ? VTOAFS(avp) : NULL;
 
1280
    afs_Trace3(afs_iclSetp, CM_TRACE_PIOCTL, ICL_TYPE_INT32, acom & 0xff,
 
1281
               ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, afollow);
 
1282
    AFS_STATCNT(HandlePioctl);
 
1283
 
 
1284
    code = afs_InitReq(&treq, *acred);
 
1285
    if (code)
 
1286
        return code;
 
1287
 
 
1288
    afs_InitFakeStat(&fakestate);
 
1289
    if (avc) {
 
1290
        code = afs_EvalFakeStat(&avc, &fakestate, &treq);
 
1291
        if (code)
 
1292
            goto out;
 
1293
    }
 
1294
    device = (acom & 0xff00) >> 8;
 
1295
    switch (device) {
 
1296
    case 'V':                   /* Original pioctls */
 
1297
        pioctlSw = VpioctlSw;
 
1298
        pioctlSwSize = sizeof(VpioctlSw);
 
1299
        break;
 
1300
    case 'C':                   /* Coordinated/common pioctls */
 
1301
        pioctlSw = CpioctlSw;
 
1302
        pioctlSwSize = sizeof(CpioctlSw);
 
1303
        break;
 
1304
    case 'O':                   /* Coordinated/common pioctls */
 
1305
        pioctlSw = OpioctlSw;
 
1306
        pioctlSwSize = sizeof(OpioctlSw);
 
1307
        break;
 
1308
    default:
 
1309
        code = EINVAL;
 
1310
        goto out;
 
1311
    }
 
1312
    function = acom & 0xff;
 
1313
    if (function >= (pioctlSwSize / sizeof(char *))) {
 
1314
        code = EINVAL;
 
1315
        goto out;
 
1316
    }
 
1317
 
 
1318
    /* Do all range checking before continuing */
 
1319
    if (ablob->in_size > MAXPIOCTLTOKENLEN ||
 
1320
        ablob->in_size < 0 || ablob->out_size < 0) {
 
1321
        code = EINVAL;
 
1322
        goto out;
 
1323
    }
 
1324
 
 
1325
    code = afs_pd_alloc(&input, ablob->in_size);
 
1326
    if (code)
 
1327
        goto out;
 
1328
 
 
1329
    if (ablob->in_size > 0) {
 
1330
        AFS_COPYIN(ablob->in, input.ptr, ablob->in_size, code);
 
1331
        input.ptr[input.remaining] = '\0';
 
1332
    }
 
1333
    if (code)
 
1334
        goto out;
 
1335
 
 
1336
    if (function == 8 && device == 'V') {       /* PGetTokens */
 
1337
        code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN);
 
1338
    } else {
 
1339
        code = afs_pd_alloc(&output, AFS_LRALLOCSIZ);
 
1340
    }
 
1341
    if (code)
 
1342
        goto out;
 
1343
 
 
1344
    copyInput = input;
 
1345
    copyOutput = output;
 
1346
 
 
1347
    code =
 
1348
        (*pioctlSw[function]) (avc, function, &treq, &copyInput,
 
1349
                               &copyOutput, acred);
 
1350
 
 
1351
    outSize = copyOutput.ptr - output.ptr;
 
1352
 
 
1353
    if (code == 0 && ablob->out_size > 0) {
 
1354
        if (outSize > ablob->out_size) {
 
1355
            code = E2BIG;       /* data wont fit in user buffer */
 
1356
        } else if (outSize) {
 
1357
            AFS_COPYOUT(output.ptr, ablob->out, outSize, code);
 
1358
        }
 
1359
    }
 
1360
 
 
1361
out:
 
1362
    afs_pd_free(&input);
 
1363
    afs_pd_free(&output);
 
1364
 
 
1365
    afs_PutFakeStat(&fakestate);
 
1366
    return afs_CheckCode(code, &treq, 41);
 
1367
}
 
1368
 
 
1369
/*!
 
1370
 * VIOCGETFID (22) - Get file ID quickly
 
1371
 *
 
1372
 * \ingroup pioctl
 
1373
 *
 
1374
 * \param[in] ain       not in use
 
1375
 * \param[out] aout     fid of requested file
 
1376
 *
 
1377
 * \retval EINVAL       Error if some of the initial arguments aren't set
 
1378
 *
 
1379
 * \post get the file id of some file
 
1380
 */
 
1381
DECL_PIOCTL(PGetFID)
 
1382
{
 
1383
    AFS_STATCNT(PGetFID);
 
1384
    if (!avc)
 
1385
        return EINVAL;
 
1386
    if (afs_pd_putBytes(aout, &avc->f.fid, sizeof(struct VenusFid)) != 0)
 
1387
        return EINVAL;
 
1388
    return 0;
 
1389
}
 
1390
 
 
1391
/*!
 
1392
 * VIOCSETAL (1) - Set access control list
 
1393
 *
 
1394
 * \ingroup pioctl
 
1395
 *
 
1396
 * \param[in] ain       the ACL being set
 
1397
 * \param[out] aout     the ACL being set returned
 
1398
 *
 
1399
 * \retval EINVAL       Error if some of the standard args aren't set
 
1400
 *
 
1401
 * \post Changed ACL, via direct writing to the wire
 
1402
 */
 
1403
int
 
1404
dummy_PSetAcl(char *ain, char *aout)
 
1405
{
 
1406
    return 0;
 
1407
}
 
1408
 
 
1409
DECL_PIOCTL(PSetAcl)
 
1410
{
 
1411
    afs_int32 code;
 
1412
    struct afs_conn *tconn;
 
1413
    struct AFSOpaque acl;
 
1414
    struct AFSVolSync tsync;
 
1415
    struct AFSFetchStatus OutStatus;
 
1416
    struct rx_connection *rxconn;
 
1417
    XSTATS_DECLS;
 
1418
 
 
1419
    AFS_STATCNT(PSetAcl);
 
1420
    if (!avc)
 
1421
        return EINVAL;
 
1422
 
 
1423
    if (afs_pd_getStringPtr(ain, &acl.AFSOpaque_val) != 0)
 
1424
        return EINVAL;
 
1425
    acl.AFSOpaque_len = strlen(acl.AFSOpaque_val) + 1;
 
1426
    if (acl.AFSOpaque_len > 1024)
 
1427
        return EINVAL;
 
1428
 
 
1429
    do {
 
1430
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
1431
        if (tconn) {
 
1432
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_STOREACL);
 
1433
            RX_AFS_GUNLOCK();
 
1434
            code =
 
1435
                RXAFS_StoreACL(rxconn, (struct AFSFid *)&avc->f.fid.Fid,
 
1436
                               &acl, &OutStatus, &tsync);
 
1437
            RX_AFS_GLOCK();
 
1438
            XSTATS_END_TIME;
 
1439
        } else
 
1440
            code = -1;
 
1441
    } while (afs_Analyze
 
1442
             (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_STOREACL,
 
1443
              SHARED_LOCK, NULL));
 
1444
 
 
1445
    /* now we've forgotten all of the access info */
 
1446
    ObtainWriteLock(&afs_xcbhash, 455);
 
1447
    avc->callback = 0;
 
1448
    afs_DequeueCallback(avc);
 
1449
    avc->f.states &= ~(CStatd | CUnique);
 
1450
    ReleaseWriteLock(&afs_xcbhash);
 
1451
    if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
 
1452
        osi_dnlc_purgedp(avc);
 
1453
 
 
1454
    /* SXW - Should we flush metadata here? */
 
1455
    return code;
 
1456
}
 
1457
 
 
1458
int afs_defaultAsynchrony = 0;
 
1459
 
 
1460
/*!
 
1461
 * VIOC_STOREBEHIND (47) Adjust store asynchrony
 
1462
 *
 
1463
 * \ingroup pioctl
 
1464
 *
 
1465
 * \param[in] ain       sbstruct (store behind structure) input
 
1466
 * \param[out] aout     resulting sbstruct
 
1467
 *
 
1468
 * \retval EPERM
 
1469
 *      Error if the user doesn't have super-user credentials
 
1470
 * \retval EACCES
 
1471
 *      Error if there isn't enough access to not check the mode bits
 
1472
 *
 
1473
 * \post
 
1474
 *      Changes either the default asynchrony (the amount of data that
 
1475
 *      can remain to be written when the cache manager returns control
 
1476
 *      to the user), or the asyncrony for the specified file.
 
1477
 */
 
1478
DECL_PIOCTL(PStoreBehind)
 
1479
{
 
1480
    struct sbstruct sbr;
 
1481
 
 
1482
    if (afs_pd_getBytes(ain, &sbr, sizeof(struct sbstruct)) != 0)
 
1483
        return EINVAL;
 
1484
 
 
1485
    if (sbr.sb_default != -1) {
 
1486
        if (afs_osi_suser(*acred))
 
1487
            afs_defaultAsynchrony = sbr.sb_default;
 
1488
        else
 
1489
            return EPERM;
 
1490
    }
 
1491
 
 
1492
    if (avc && (sbr.sb_thisfile != -1)) {
 
1493
        if (afs_AccessOK
 
1494
            (avc, PRSFS_WRITE | PRSFS_ADMINISTER, areq, DONT_CHECK_MODE_BITS))
 
1495
            avc->asynchrony = sbr.sb_thisfile;
 
1496
        else
 
1497
            return EACCES;
 
1498
    }
 
1499
 
 
1500
    memset(&sbr, 0, sizeof(sbr));
 
1501
    sbr.sb_default = afs_defaultAsynchrony;
 
1502
    if (avc) {
 
1503
        sbr.sb_thisfile = avc->asynchrony;
 
1504
    }
 
1505
 
 
1506
    return afs_pd_putBytes(aout, &sbr, sizeof(sbr));
 
1507
}
 
1508
 
 
1509
/*!
 
1510
 * VIOC_GCPAGS (48) - Disable automatic PAG gc'ing
 
1511
 *
 
1512
 * \ingroup pioctl
 
1513
 *
 
1514
 * \param[in] ain       not in use
 
1515
 * \param[out] aout     not in use
 
1516
 *
 
1517
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
1518
 *
 
1519
 * \post set the gcpags to GCPAGS_USERDISABLED
 
1520
 */
 
1521
DECL_PIOCTL(PGCPAGs)
 
1522
{
 
1523
    if (!afs_osi_suser(*acred)) {
 
1524
        return EACCES;
 
1525
    }
 
1526
    afs_gcpags = AFS_GCPAGS_USERDISABLED;
 
1527
    return 0;
 
1528
}
 
1529
 
 
1530
/*!
 
1531
 * VIOCGETAL (2) - Get access control list
 
1532
 *
 
1533
 * \ingroup pioctl
 
1534
 *
 
1535
 * \param[in] ain       not in use
 
1536
 * \param[out] aout     the ACL
 
1537
 *
 
1538
 * \retval EINVAL       Error if some of the standard args aren't set
 
1539
 * \retval ERANGE       Error if the vnode of the file id is too large
 
1540
 * \retval -1           Error if getting the ACL failed
 
1541
 *
 
1542
 * \post Obtain the ACL, based on file ID
 
1543
 *
 
1544
 * \notes
 
1545
 *      There is a hack to tell which type of ACL is being returned, checks
 
1546
 *      the top 2-bytes of the input size to judge what type of ACL it is,
 
1547
 *      only for dfs xlator ACLs
 
1548
 */
 
1549
DECL_PIOCTL(PGetAcl)
 
1550
{
 
1551
    struct AFSOpaque acl;
 
1552
    struct AFSVolSync tsync;
 
1553
    struct AFSFetchStatus OutStatus;
 
1554
    afs_int32 code;
 
1555
    struct afs_conn *tconn;
 
1556
    struct AFSFid Fid;
 
1557
    struct rx_connection *rxconn;
 
1558
    XSTATS_DECLS;
 
1559
 
 
1560
    AFS_STATCNT(PGetAcl);
 
1561
    if (!avc)
 
1562
        return EINVAL;
 
1563
    Fid.Volume = avc->f.fid.Fid.Volume;
 
1564
    Fid.Vnode = avc->f.fid.Fid.Vnode;
 
1565
    Fid.Unique = avc->f.fid.Fid.Unique;
 
1566
    if (avc->f.states & CForeign) {
 
1567
        /*
 
1568
         * For a dfs xlator acl we have a special hack so that the
 
1569
         * xlator will distinguish which type of acl will return. So
 
1570
         * we currently use the top 2-bytes (vals 0-4) to tell which
 
1571
         * type of acl to bring back. Horrible hack but this will
 
1572
         * cause the least number of changes to code size and interfaces.
 
1573
         */
 
1574
        if (Fid.Vnode & 0xc0000000)
 
1575
            return ERANGE;
 
1576
        Fid.Vnode |= (ain->remaining << 30);
 
1577
    }
 
1578
    acl.AFSOpaque_val = aout->ptr;
 
1579
    do {
 
1580
        tconn = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
1581
        if (tconn) {
 
1582
            acl.AFSOpaque_val[0] = '\0';
 
1583
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHACL);
 
1584
            RX_AFS_GUNLOCK();
 
1585
            code = RXAFS_FetchACL(rxconn, &Fid, &acl, &OutStatus, &tsync);
 
1586
            RX_AFS_GLOCK();
 
1587
            XSTATS_END_TIME;
 
1588
        } else
 
1589
            code = -1;
 
1590
    } while (afs_Analyze
 
1591
             (tconn, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHACL,
 
1592
              SHARED_LOCK, NULL));
 
1593
 
 
1594
    if (code == 0) {
 
1595
        if (acl.AFSOpaque_len == 0)
 
1596
            afs_pd_skip(aout, 1); /* leave the NULL */
 
1597
        else
 
1598
            afs_pd_skip(aout, acl.AFSOpaque_len); /* Length of the ACL */
 
1599
    }
 
1600
    return code;
 
1601
}
 
1602
 
 
1603
/*!
 
1604
 * PNoop returns success.  Used for functions which are not implemented
 
1605
 * or are no longer in use.
 
1606
 *
 
1607
 * \ingroup pioctl
 
1608
 *
 
1609
 * \retval Always returns success
 
1610
 *
 
1611
 * \notes
 
1612
 *      Functions involved in this:
 
1613
 *      17 (VIOCENGROUP) -- used to be enable group;
 
1614
 *      18 (VIOCDISGROUP) -- used to be disable group;
 
1615
 *      2 (?) -- get/set cache-bypass size threshold
 
1616
 */
 
1617
DECL_PIOCTL(PNoop)
 
1618
{
 
1619
    AFS_STATCNT(PNoop);
 
1620
    return 0;
 
1621
}
 
1622
 
 
1623
/*!
 
1624
 * PBogus returns fail.  Used for functions which are not implemented or
 
1625
 * are no longer in use.
 
1626
 *
 
1627
 * \ingroup pioctl
 
1628
 *
 
1629
 * \retval EINVAL       Always returns this value
 
1630
 *
 
1631
 * \notes
 
1632
 *      Functions involved in this:
 
1633
 *      0 (?);
 
1634
 *      4 (?);
 
1635
 *      6 (?);
 
1636
 *      7 (VIOCSTAT);
 
1637
 *      8 (?);
 
1638
 *      13 (VIOCGETTIME) -- used to be quick check time;
 
1639
 *      15 (VIOCPREFETCH) -- prefetch is now special-cased; see pioctl code!;
 
1640
 *      16 (VIOCNOP) -- used to be testing code;
 
1641
 *      19 (VIOCLISTGROUPS) -- used to be list group;
 
1642
 *      23 (VIOCWAITFOREVER) -- used to be waitforever;
 
1643
 *      57 (VIOC_FPRIOSTATUS) -- arla: set file prio;
 
1644
 *      58 (VIOC_FHGET) -- arla: fallback getfh;
 
1645
 *      59 (VIOC_FHOPEN) -- arla: fallback fhopen;
 
1646
 *      60 (VIOC_XFSDEBUG) -- arla: controls xfsdebug;
 
1647
 *      61 (VIOC_ARLADEBUG) -- arla: controls arla debug;
 
1648
 *      62 (VIOC_AVIATOR) -- arla: debug interface;
 
1649
 *      63 (VIOC_XFSDEBUG_PRINT) -- arla: print xfs status;
 
1650
 *      64 (VIOC_CALCULATE_CACHE) -- arla: force cache check;
 
1651
 *      65 (VIOC_BREAKCELLBACK) -- arla: break callback;
 
1652
 *      68 (?) -- arla: fetch stats;
 
1653
 */
 
1654
DECL_PIOCTL(PBogus)
 
1655
{
 
1656
    AFS_STATCNT(PBogus);
 
1657
    return EINVAL;
 
1658
}
 
1659
 
 
1660
/*!
 
1661
 * VIOC_FILE_CELL_NAME (30) - Get cell in which file lives
 
1662
 *
 
1663
 * \ingroup pioctl
 
1664
 *
 
1665
 * \param[in] ain       not in use (avc used to pass in file id)
 
1666
 * \param[out] aout     cell name
 
1667
 *
 
1668
 * \retval EINVAL       Error if some of the standard args aren't set
 
1669
 * \retval ESRCH        Error if the file isn't part of a cell
 
1670
 *
 
1671
 * \post Get a cell based on a passed in file id
 
1672
 */
 
1673
DECL_PIOCTL(PGetFileCell)
 
1674
{
 
1675
    struct cell *tcell;
 
1676
 
 
1677
    AFS_STATCNT(PGetFileCell);
 
1678
    if (!avc)
 
1679
        return EINVAL;
 
1680
    tcell = afs_GetCell(avc->f.fid.Cell, READ_LOCK);
 
1681
    if (!tcell)
 
1682
        return ESRCH;
 
1683
 
 
1684
    if (afs_pd_putString(aout, tcell->cellName) != 0)
 
1685
        return EINVAL;
 
1686
 
 
1687
    afs_PutCell(tcell, READ_LOCK);
 
1688
    return 0;
 
1689
}
 
1690
 
 
1691
/*!
 
1692
 * VIOC_GET_WS_CELL (31) - Get cell in which workstation lives
 
1693
 *
 
1694
 * \ingroup pioctl
 
1695
 *
 
1696
 * \param[in] ain       not in use
 
1697
 * \param[out] aout     cell name
 
1698
 *
 
1699
 * \retval EIO
 
1700
 *      Error if the afs daemon hasn't started yet
 
1701
 * \retval ESRCH
 
1702
 *      Error if the machine isn't part of a cell, for whatever reason
 
1703
 *
 
1704
 * \post Get the primary cell that the machine is a part of.
 
1705
 */
 
1706
DECL_PIOCTL(PGetWSCell)
 
1707
{
 
1708
    struct cell *tcell = NULL;
 
1709
 
 
1710
    AFS_STATCNT(PGetWSCell);
 
1711
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
1712
        return EIO;             /* Inappropriate ioctl for device */
 
1713
 
 
1714
    tcell = afs_GetPrimaryCell(READ_LOCK);
 
1715
    if (!tcell)                 /* no primary cell? */
 
1716
        return ESRCH;
 
1717
 
 
1718
    if (afs_pd_putString(aout, tcell->cellName) != 0)
 
1719
        return EINVAL;
 
1720
    afs_PutCell(tcell, READ_LOCK);
 
1721
    return 0;
 
1722
}
 
1723
 
 
1724
/*!
 
1725
 * VIOC_GET_PRIMARY_CELL (33) - Get primary cell for caller
 
1726
 *
 
1727
 * \ingroup pioctl
 
1728
 *
 
1729
 * \param[in] ain       not in use (user id found via areq)
 
1730
 * \param[out] aout     cell name
 
1731
 *
 
1732
 * \retval ESRCH
 
1733
 *      Error if the user id doesn't have a primary cell specified
 
1734
 *
 
1735
 * \post Get the primary cell for a certain user, based on the user's uid
 
1736
 */
 
1737
DECL_PIOCTL(PGetUserCell)
 
1738
{
 
1739
    afs_int32 i;
 
1740
    struct unixuser *tu;
 
1741
    struct cell *tcell;
 
1742
 
 
1743
    AFS_STATCNT(PGetUserCell);
 
1744
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
1745
        return EIO;             /* Inappropriate ioctl for device */
 
1746
 
 
1747
    /* return the cell name of the primary cell for this user */
 
1748
    i = UHash(areq->uid);
 
1749
    ObtainWriteLock(&afs_xuser, 224);
 
1750
    for (tu = afs_users[i]; tu; tu = tu->next) {
 
1751
        if (tu->uid == areq->uid && (tu->states & UPrimary)) {
 
1752
            tu->refCount++;
 
1753
            ReleaseWriteLock(&afs_xuser);
 
1754
            break;
 
1755
        }
 
1756
    }
 
1757
    if (tu) {
 
1758
        tcell = afs_GetCell(tu->cell, READ_LOCK);
 
1759
        afs_PutUser(tu, WRITE_LOCK);
 
1760
        if (!tcell)
 
1761
            return ESRCH;
 
1762
        else {
 
1763
            if (afs_pd_putString(aout, tcell->cellName) != 0)
 
1764
                return E2BIG;
 
1765
            afs_PutCell(tcell, READ_LOCK);
 
1766
        }
 
1767
    } else {
 
1768
        ReleaseWriteLock(&afs_xuser);
 
1769
    }
 
1770
    return 0;
 
1771
}
 
1772
 
 
1773
/*!
 
1774
 * VIOCSETTOK (3) - Set authentication tokens
 
1775
 *
 
1776
 * \ingroup pioctl
 
1777
 *
 
1778
 * \param[in] ain       the krb tickets from which to set the afs tokens
 
1779
 * \param[out] aout     not in use
 
1780
 *
 
1781
 * \retval EINVAL
 
1782
 *      Error if the ticket is either too long or too short
 
1783
 * \retval EIO
 
1784
 *      Error if the AFS initState is below 101
 
1785
 * \retval ESRCH
 
1786
 *      Error if the cell for which the Token is being set can't be found
 
1787
 *
 
1788
 * \post
 
1789
 *      Set the Tokens for a specific cell name, unless there is none set,
 
1790
 *      then default to primary
 
1791
 *
 
1792
 */
 
1793
DECL_PIOCTL(PSetTokens)
 
1794
{
 
1795
    afs_int32 i;
 
1796
    struct unixuser *tu;
 
1797
    struct ClearToken clear;
 
1798
    struct cell *tcell;
 
1799
    char *stp, *stpNew;
 
1800
    char *cellName;
 
1801
    int stLen, stLenOld;
 
1802
    struct vrequest treq;
 
1803
    afs_int32 flag, set_parent_pag = 0;
 
1804
 
 
1805
    AFS_STATCNT(PSetTokens);
 
1806
    if (!afs_resourceinit_flag) {
 
1807
        return EIO;
 
1808
    }
 
1809
 
 
1810
    if (afs_pd_getInt(ain, &stLen) != 0)
 
1811
        return EINVAL;
 
1812
 
 
1813
    stp = afs_pd_where(ain);    /* remember where the ticket is */
 
1814
    if (stLen < 0 || stLen > MAXKTCTICKETLEN)
 
1815
        return EINVAL;          /* malloc may fail */
 
1816
    if (afs_pd_skip(ain, stLen) != 0)
 
1817
        return EINVAL;
 
1818
 
 
1819
    if (afs_pd_getInt(ain, &i) != 0)
 
1820
        return EINVAL;
 
1821
    if (i != sizeof(struct ClearToken))
 
1822
        return EINVAL;
 
1823
 
 
1824
    if (afs_pd_getBytes(ain, &clear, sizeof(struct ClearToken)) !=0)
 
1825
        return EINVAL;
 
1826
 
 
1827
    if (clear.AuthHandle == -1)
 
1828
        clear.AuthHandle = 999; /* more rxvab compat stuff */
 
1829
 
 
1830
    if (afs_pd_remaining(ain) != 0) {
 
1831
        /* still stuff left?  we've got primary flag and cell name.
 
1832
         * Set these */
 
1833
 
 
1834
        if (afs_pd_getInt(ain, &flag) != 0)
 
1835
            return EINVAL;
 
1836
 
 
1837
        /* some versions of gcc appear to need != 0 in order to get this
 
1838
         * right */
 
1839
        if ((flag & 0x8000) != 0) {     /* XXX Use Constant XXX */
 
1840
            flag &= ~0x8000;
 
1841
            set_parent_pag = 1;
 
1842
        }
 
1843
 
 
1844
        if (afs_pd_getStringPtr(ain, &cellName) != 0)
 
1845
            return EINVAL;
 
1846
 
 
1847
        /* rest is cell name, look it up */
 
1848
        tcell = afs_GetCellByName(cellName, READ_LOCK);
 
1849
        if (!tcell)
 
1850
            goto nocell;
 
1851
    } else {
 
1852
        /* default to primary cell, primary id */
 
1853
        flag = 1;               /* primary id */
 
1854
        tcell = afs_GetPrimaryCell(READ_LOCK);
 
1855
        if (!tcell)
 
1856
            goto nocell;
 
1857
    }
 
1858
    i = tcell->cellNum;
 
1859
    afs_PutCell(tcell, READ_LOCK);
 
1860
    if (set_parent_pag) {
 
1861
        afs_uint32 pag;
 
1862
#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
1863
        char procname[256];
 
1864
        osi_procname(procname, 256);
 
1865
        afs_warnuser("Process %d (%s) tried to change pags in PSetTokens\n",
 
1866
                     MyPidxx2Pid(MyPidxx), procname);
 
1867
        if (!setpag(osi_curproc(), acred, -1, &pag, 1)) {
 
1868
#else
 
1869
        if (!setpag(acred, -1, &pag, 1)) {
 
1870
#endif
 
1871
            afs_InitReq(&treq, *acred);
 
1872
            areq = &treq;
 
1873
        }
 
1874
    }
 
1875
 
 
1876
    stpNew = (char *)afs_osi_Alloc(stLen);
 
1877
    if (stpNew == NULL) {
 
1878
        return ENOMEM;
 
1879
    }
 
1880
    memcpy(stpNew, stp, stLen);
 
1881
 
 
1882
    /* now we just set the tokens */
 
1883
    tu = afs_GetUser(areq->uid, i, WRITE_LOCK); /* i has the cell # */
 
1884
    stp = tu->stp;
 
1885
    stLenOld = tu->stLen;
 
1886
 
 
1887
    tu->vid = clear.ViceId;
 
1888
    tu->stp = stpNew;
 
1889
    tu->stLen = stLen;
 
1890
    tu->ct = clear;
 
1891
#ifndef AFS_NOSTATS
 
1892
    afs_stats_cmfullperf.authent.TicketUpdates++;
 
1893
    afs_ComputePAGStats();
 
1894
#endif /* AFS_NOSTATS */
 
1895
    tu->states |= UHasTokens;
 
1896
    tu->states &= ~UTokensBad;
 
1897
    afs_SetPrimary(tu, flag);
 
1898
    tu->tokenTime = osi_Time();
 
1899
    afs_ResetUserConns(tu);
 
1900
    afs_NotifyUser(tu, UTokensObtained);
 
1901
    afs_PutUser(tu, WRITE_LOCK);
 
1902
 
 
1903
    if (stp) {
 
1904
        afs_osi_Free(stp, stLenOld);
 
1905
    }
 
1906
 
 
1907
    return 0;
 
1908
 
 
1909
  nocell:
 
1910
    {
 
1911
        int t1;
 
1912
        t1 = afs_initState;
 
1913
        if (t1 < 101)
 
1914
            return EIO;
 
1915
        else
 
1916
            return ESRCH;
 
1917
    }
 
1918
}
 
1919
 
 
1920
/*!
 
1921
 * VIOCGETVOLSTAT (4) - Get volume status
 
1922
 *
 
1923
 * \ingroup pioctl
 
1924
 *
 
1925
 * \param[in] ain       not in use
 
1926
 * \param[out] aout     status of the volume
 
1927
 *
 
1928
 * \retval EINVAL       Error if some of the standard args aren't set
 
1929
 *
 
1930
 * \post
 
1931
 *      The status of a volume (based on the FID of the volume), or an
 
1932
 *      offline message /motd
 
1933
 */
 
1934
DECL_PIOCTL(PGetVolumeStatus)
 
1935
{
 
1936
    char volName[32];
 
1937
    char *offLineMsg = afs_osi_Alloc(256);
 
1938
    char *motd = afs_osi_Alloc(256);
 
1939
    struct afs_conn *tc;
 
1940
    afs_int32 code = 0;
 
1941
    struct AFSFetchVolumeStatus volstat;
 
1942
    char *Name;
 
1943
    struct rx_connection *rxconn;
 
1944
    XSTATS_DECLS;
 
1945
 
 
1946
    osi_Assert(offLineMsg != NULL);
 
1947
    osi_Assert(motd != NULL);
 
1948
    AFS_STATCNT(PGetVolumeStatus);
 
1949
    if (!avc) {
 
1950
        code = EINVAL;
 
1951
        goto out;
 
1952
    }
 
1953
    Name = volName;
 
1954
    do {
 
1955
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
1956
        if (tc) {
 
1957
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS);
 
1958
            RX_AFS_GUNLOCK();
 
1959
            code =
 
1960
                RXAFS_GetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &volstat,
 
1961
                                      &Name, &offLineMsg, &motd);
 
1962
            RX_AFS_GLOCK();
 
1963
            XSTATS_END_TIME;
 
1964
        } else
 
1965
            code = -1;
 
1966
    } while (afs_Analyze
 
1967
             (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_GETVOLUMESTATUS,
 
1968
              SHARED_LOCK, NULL));
 
1969
 
 
1970
    if (code)
 
1971
        goto out;
 
1972
    /* Copy all this junk into msg->im_data, keeping track of the lengths. */
 
1973
    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
 
1974
        return E2BIG;
 
1975
    if (afs_pd_putString(aout, volName) != 0)
 
1976
        return E2BIG;
 
1977
    if (afs_pd_putString(aout, offLineMsg) != 0)
 
1978
        return E2BIG;
 
1979
    if (afs_pd_putString(aout, motd) != 0)
 
1980
        return E2BIG;
 
1981
  out:
 
1982
    afs_osi_Free(offLineMsg, 256);
 
1983
    afs_osi_Free(motd, 256);
 
1984
    return code;
 
1985
}
 
1986
 
 
1987
/*!
 
1988
 * VIOCSETVOLSTAT (5) - Set volume status
 
1989
 *
 
1990
 * \ingroup pioctl
 
1991
 *
 
1992
 * \param[in] ain
 
1993
 *      values to set the status at, offline message, message of the day,
 
1994
 *      volume name, minimum quota, maximum quota
 
1995
 * \param[out] aout
 
1996
 *      status of a volume, offlines messages, minimum quota, maximumm quota
 
1997
 *
 
1998
 * \retval EINVAL
 
1999
 *      Error if some of the standard args aren't set
 
2000
 * \retval EROFS
 
2001
 *      Error if the volume is read only, or a backup volume
 
2002
 * \retval ENODEV
 
2003
 *      Error if the volume can't be accessed
 
2004
 * \retval E2BIG
 
2005
 *      Error if the volume name, offline message, and motd are too big
 
2006
 *
 
2007
 * \post
 
2008
 *      Set the status of a volume, including any offline messages,
 
2009
 *      a minimum quota, and a maximum quota
 
2010
 */
 
2011
DECL_PIOCTL(PSetVolumeStatus)
 
2012
{
 
2013
    char *volName;
 
2014
    char *offLineMsg;
 
2015
    char *motd;
 
2016
    struct afs_conn *tc;
 
2017
    afs_int32 code = 0;
 
2018
    struct AFSFetchVolumeStatus volstat;
 
2019
    struct AFSStoreVolumeStatus storeStat;
 
2020
    struct volume *tvp;
 
2021
    struct rx_connection *rxconn;
 
2022
    XSTATS_DECLS;
 
2023
 
 
2024
    AFS_STATCNT(PSetVolumeStatus);
 
2025
    if (!avc)
 
2026
        return EINVAL;
 
2027
 
 
2028
    tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
 
2029
    if (tvp) {
 
2030
        if (tvp->states & (VRO | VBackup)) {
 
2031
            afs_PutVolume(tvp, READ_LOCK);
 
2032
            return EROFS;
 
2033
        }
 
2034
        afs_PutVolume(tvp, READ_LOCK);
 
2035
    } else
 
2036
        return ENODEV;
 
2037
 
 
2038
 
 
2039
    if (afs_pd_getBytes(ain, &volstat, sizeof(AFSFetchVolumeStatus)) != 0)
 
2040
        return EINVAL;
 
2041
 
 
2042
    if (afs_pd_getStringPtr(ain, &volName) != 0)
 
2043
        return EINVAL;
 
2044
    if (strlen(volName) > 32)
 
2045
        return E2BIG;
 
2046
 
 
2047
    if (afs_pd_getStringPtr(ain, &offLineMsg) != 0)
 
2048
        return EINVAL;
 
2049
    if (strlen(offLineMsg) > 256)
 
2050
        return E2BIG;
 
2051
 
 
2052
    if (afs_pd_getStringPtr(ain, &motd) != 0)
 
2053
        return EINVAL;
 
2054
    if (strlen(motd) > 256)
 
2055
        return E2BIG;
 
2056
 
 
2057
    /* Done reading ... */
 
2058
 
 
2059
    storeStat.Mask = 0;
 
2060
    if (volstat.MinQuota != -1) {
 
2061
        storeStat.MinQuota = volstat.MinQuota;
 
2062
        storeStat.Mask |= AFS_SETMINQUOTA;
 
2063
    }
 
2064
    if (volstat.MaxQuota != -1) {
 
2065
        storeStat.MaxQuota = volstat.MaxQuota;
 
2066
        storeStat.Mask |= AFS_SETMAXQUOTA;
 
2067
    }
 
2068
    do {
 
2069
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
2070
        if (tc) {
 
2071
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS);
 
2072
            RX_AFS_GUNLOCK();
 
2073
            code =
 
2074
                RXAFS_SetVolumeStatus(rxconn, avc->f.fid.Fid.Volume, &storeStat,
 
2075
                                      volName, offLineMsg, motd);
 
2076
            RX_AFS_GLOCK();
 
2077
            XSTATS_END_TIME;
 
2078
        } else
 
2079
            code = -1;
 
2080
    } while (afs_Analyze
 
2081
             (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_SETVOLUMESTATUS,
 
2082
              SHARED_LOCK, NULL));
 
2083
 
 
2084
    if (code)
 
2085
        return code;
 
2086
    /* we are sending parms back to make compat. with prev system.  should
 
2087
     * change interface later to not ask for current status, just set new
 
2088
     * status */
 
2089
 
 
2090
    if (afs_pd_putBytes(aout, &volstat, sizeof(VolumeStatus)) != 0)
 
2091
        return EINVAL;
 
2092
    if (afs_pd_putString(aout, volName) != 0)
 
2093
        return EINVAL;
 
2094
    if (afs_pd_putString(aout, offLineMsg) != 0)
 
2095
        return EINVAL;
 
2096
    if (afs_pd_putString(aout, motd) != 0)
 
2097
        return EINVAL;
 
2098
 
 
2099
    return code;
 
2100
}
 
2101
 
 
2102
/*!
 
2103
 * VIOCFLUSH (6) - Invalidate cache entry
 
2104
 *
 
2105
 * \ingroup pioctl
 
2106
 *
 
2107
 * \param[in] ain       not in use
 
2108
 * \param[out] aout     not in use
 
2109
 *
 
2110
 * \retval EINVAL       Error if some of the standard args aren't set
 
2111
 *
 
2112
 * \post Flush any information the cache manager has on an entry
 
2113
 */
 
2114
DECL_PIOCTL(PFlush)
 
2115
{
 
2116
    AFS_STATCNT(PFlush);
 
2117
    if (!avc)
 
2118
        return EINVAL;
 
2119
#ifdef AFS_BOZONLOCK_ENV
 
2120
    afs_BozonLock(&avc->pvnLock, avc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
 
2121
#endif
 
2122
    ObtainWriteLock(&avc->lock, 225);
 
2123
    afs_ResetVCache(avc, *acred);
 
2124
    ReleaseWriteLock(&avc->lock);
 
2125
#ifdef AFS_BOZONLOCK_ENV
 
2126
    afs_BozonUnlock(&avc->pvnLock, avc);
 
2127
#endif
 
2128
    return 0;
 
2129
}
 
2130
 
 
2131
/*!
 
2132
 * VIOC_AFS_STAT_MT_PT (29) - Stat mount point
 
2133
 *
 
2134
 * \ingroup pioctl
 
2135
 *
 
2136
 * \param[in] ain
 
2137
 *      the last component in a path, related to mountpoint that we're
 
2138
 *      looking for information about
 
2139
 * \param[out] aout
 
2140
 *      volume, cell, link data
 
2141
 *
 
2142
 * \retval EINVAL       Error if some of the standard args aren't set
 
2143
 * \retval ENOTDIR      Error if the 'mount point' argument isn't a directory
 
2144
 * \retval EIO          Error if the link data can't be accessed
 
2145
 *
 
2146
 * \post Get the volume, and cell, as well as the link data for a mount point
 
2147
 */
 
2148
DECL_PIOCTL(PNewStatMount)
 
2149
{
 
2150
    afs_int32 code;
 
2151
    struct vcache *tvc;
 
2152
    struct dcache *tdc;
 
2153
    struct VenusFid tfid;
 
2154
    char *bufp;
 
2155
    char *name;
 
2156
    struct sysname_info sysState;
 
2157
    afs_size_t offset, len;
 
2158
 
 
2159
    AFS_STATCNT(PNewStatMount);
 
2160
    if (!avc)
 
2161
        return EINVAL;
 
2162
 
 
2163
    if (afs_pd_getStringPtr(ain, &name) != 0)
 
2164
        return EINVAL;
 
2165
 
 
2166
    code = afs_VerifyVCache(avc, areq);
 
2167
    if (code)
 
2168
        return code;
 
2169
    if (vType(avc) != VDIR) {
 
2170
        return ENOTDIR;
 
2171
    }
 
2172
    tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
 
2173
    if (!tdc)
 
2174
        return ENOENT;
 
2175
    Check_AtSys(avc, name, &sysState, areq);
 
2176
    ObtainReadLock(&tdc->lock);
 
2177
    do {
 
2178
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
 
2179
    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
 
2180
    ReleaseReadLock(&tdc->lock);
 
2181
    afs_PutDCache(tdc);         /* we're done with the data */
 
2182
    bufp = sysState.name;
 
2183
    if (code) {
 
2184
        goto out;
 
2185
    }
 
2186
    tfid.Cell = avc->f.fid.Cell;
 
2187
    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
 
2188
    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
 
2189
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
 
2190
    } else {
 
2191
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
 
2192
    }
 
2193
    if (!tvc) {
 
2194
        code = ENOENT;
 
2195
        goto out;
 
2196
    }
 
2197
    if (tvc->mvstat != 1) {
 
2198
        afs_PutVCache(tvc);
 
2199
        code = EINVAL;
 
2200
        goto out;
 
2201
    }
 
2202
    ObtainWriteLock(&tvc->lock, 226);
 
2203
    code = afs_HandleLink(tvc, areq);
 
2204
    if (code == 0) {
 
2205
        if (tvc->linkData) {
 
2206
            if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
 
2207
                code = EINVAL;
 
2208
            else {
 
2209
                /* we have the data */
 
2210
                if (afs_pd_putString(aout, tvc->linkData) != 0)
 
2211
                    code = EINVAL;
 
2212
            }
 
2213
        } else
 
2214
            code = EIO;
 
2215
    }
 
2216
    ReleaseWriteLock(&tvc->lock);
 
2217
    afs_PutVCache(tvc);
 
2218
  out:
 
2219
    if (sysState.allocked)
 
2220
        osi_FreeLargeSpace(bufp);
 
2221
    return code;
 
2222
}
 
2223
 
 
2224
/*!
 
2225
 * VIOCGETTOK (8) - Get authentication tokens
 
2226
 *
 
2227
 * \ingroup pioctl
 
2228
 *
 
2229
 * \param[in] ain       cellid to return tokens for
 
2230
 * \param[out] aout     token
 
2231
 *
 
2232
 * \retval EIO
 
2233
 *      Error if the afs daemon hasn't started yet
 
2234
 * \retval EDOM
 
2235
 *      Error if the input parameter is out of the bounds of the available
 
2236
 *      tokens
 
2237
 * \retval ENOTCONN
 
2238
 *      Error if there aren't tokens for this cell
 
2239
 *
 
2240
 * \post
 
2241
 *      If the input paramater exists, get the token that corresponds to
 
2242
 *      the parameter value, if there is no token at this value, get the
 
2243
 *      token for the first cell
 
2244
 *
 
2245
 * \notes "it's a weird interface (from comments in the code)"
 
2246
 */
 
2247
 
 
2248
DECL_PIOCTL(PGetTokens)
 
2249
{
 
2250
    struct cell *tcell;
 
2251
    afs_int32 i;
 
2252
    struct unixuser *tu;
 
2253
    afs_int32 iterator = 0;
 
2254
    int newStyle;
 
2255
    int code = E2BIG;
 
2256
 
 
2257
    AFS_STATCNT(PGetTokens);
 
2258
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2259
        return EIO;             /* Inappropriate ioctl for device */
 
2260
 
 
2261
    /* weird interface.  If input parameter is present, it is an integer and
 
2262
     * we're supposed to return the parm'th tokens for this unix uid.
 
2263
     * If not present, we just return tokens for cell 1.
 
2264
     * If counter out of bounds, return EDOM.
 
2265
     * If no tokens for the particular cell, return ENOTCONN.
 
2266
     * Also, if this mysterious parm is present, we return, along with the
 
2267
     * tokens, the primary cell indicator (an afs_int32 0) and the cell name
 
2268
     * at the end, in that order.
 
2269
     */
 
2270
    newStyle = (afs_pd_remaining(ain) > 0);
 
2271
    if (newStyle) {
 
2272
        if (afs_pd_getInt(ain, &iterator) != 0)
 
2273
            return EINVAL;
 
2274
    }
 
2275
    i = UHash(areq->uid);
 
2276
    ObtainReadLock(&afs_xuser);
 
2277
    for (tu = afs_users[i]; tu; tu = tu->next) {
 
2278
        if (newStyle) {
 
2279
            if (tu->uid == areq->uid && (tu->states & UHasTokens)) {
 
2280
                if (iterator-- == 0)
 
2281
                    break;      /* are we done yet? */
 
2282
            }
 
2283
        } else {
 
2284
            if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell))
 
2285
                break;
 
2286
        }
 
2287
    }
 
2288
    if (tu) {
 
2289
        /*
 
2290
         * No need to hold a read lock on each user entry
 
2291
         */
 
2292
        tu->refCount++;
 
2293
    }
 
2294
    ReleaseReadLock(&afs_xuser);
 
2295
 
 
2296
    if (!tu) {
 
2297
        return EDOM;
 
2298
    }
 
2299
    if (((tu->states & UHasTokens) == 0)
 
2300
        || (tu->ct.EndTimestamp < osi_Time())) {
 
2301
        tu->states |= (UTokensBad | UNeedsReset);
 
2302
        afs_NotifyUser(tu, UTokensDropped);
 
2303
        afs_PutUser(tu, READ_LOCK);
 
2304
        return ENOTCONN;
 
2305
    }
 
2306
    iterator = tu->stLen;       /* for compat, we try to return 56 byte tix if they fit */
 
2307
    if (iterator < 56)
 
2308
        iterator = 56;          /* # of bytes we're returning */
 
2309
 
 
2310
    if (afs_pd_putInt(aout, iterator) != 0)
 
2311
        goto out;
 
2312
    if (afs_pd_putBytes(aout, tu->stp, tu->stLen) != 0)
 
2313
        goto out;
 
2314
    if (tu->stLen < 56) {
 
2315
        /* Tokens are always 56 bytes or larger */
 
2316
        if (afs_pd_skip(aout, iterator - tu->stLen) != 0) {
 
2317
            goto out;
 
2318
        }
 
2319
    }
 
2320
 
 
2321
    if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
 
2322
        goto out;
 
2323
    if (afs_pd_putBytes(aout, &tu->ct, sizeof(struct ClearToken)) != 0)
 
2324
        goto out;
 
2325
 
 
2326
    if (newStyle) {
 
2327
        /* put out primary id and cell name, too */
 
2328
        iterator = (tu->states & UPrimary ? 1 : 0);
 
2329
        if (afs_pd_putInt(aout, iterator) != 0)
 
2330
            goto out;
 
2331
        tcell = afs_GetCell(tu->cell, READ_LOCK);
 
2332
        if (tcell) {
 
2333
            if (afs_pd_putString(aout, tcell->cellName) != 0)
 
2334
                goto out;
 
2335
            afs_PutCell(tcell, READ_LOCK);
 
2336
        } else
 
2337
            if (afs_pd_putString(aout, "") != 0)
 
2338
                goto out;
 
2339
    }
 
2340
    /* Got here, all is good */
 
2341
    code = 0;
 
2342
out:
 
2343
    afs_PutUser(tu, READ_LOCK);
 
2344
    return code;
 
2345
}
 
2346
 
 
2347
/*!
 
2348
 * VIOCUNLOG (9) - Invalidate tokens
 
2349
 *
 
2350
 * \ingroup pioctl
 
2351
 *
 
2352
 * \param[in] ain       not in use
 
2353
 * \param[out] aout     not in use
 
2354
 *
 
2355
 * \retval EIO  Error if the afs daemon hasn't been started yet
 
2356
 *
 
2357
 * \post remove tokens from a user, specified by the user id
 
2358
 *
 
2359
 * \notes sets the token's time to 0, which then causes it to be removed
 
2360
 * \notes Unlog is the same as un-pag in OpenAFS
 
2361
 */
 
2362
DECL_PIOCTL(PUnlog)
 
2363
{
 
2364
    afs_int32 i;
 
2365
    struct unixuser *tu;
 
2366
 
 
2367
    AFS_STATCNT(PUnlog);
 
2368
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2369
        return EIO;             /* Inappropriate ioctl for device */
 
2370
 
 
2371
    i = UHash(areq->uid);
 
2372
    ObtainWriteLock(&afs_xuser, 227);
 
2373
    for (tu = afs_users[i]; tu; tu = tu->next) {
 
2374
        if (tu->uid == areq->uid) {
 
2375
            tu->vid = UNDEFVID;
 
2376
            tu->states &= ~UHasTokens;
 
2377
            /* security is not having to say you're sorry */
 
2378
            memset(&tu->ct, 0, sizeof(struct ClearToken));
 
2379
            tu->refCount++;
 
2380
            ReleaseWriteLock(&afs_xuser);
 
2381
            afs_NotifyUser(tu, UTokensDropped);
 
2382
            /* We have to drop the lock over the call to afs_ResetUserConns,
 
2383
             * since it obtains the afs_xvcache lock.  We could also keep
 
2384
             * the lock, and modify ResetUserConns to take parm saying we
 
2385
             * obtained the lock already, but that is overkill.  By keeping
 
2386
             * the "tu" pointer held over the released lock, we guarantee
 
2387
             * that we won't lose our place, and that we'll pass over
 
2388
             * every user conn that existed when we began this call.
 
2389
             */
 
2390
            afs_ResetUserConns(tu);
 
2391
            tu->refCount--;
 
2392
            ObtainWriteLock(&afs_xuser, 228);
 
2393
#ifdef UKERNEL
 
2394
            /* set the expire times to 0, causes
 
2395
             * afs_GCUserData to remove this entry
 
2396
             */
 
2397
            tu->ct.EndTimestamp = 0;
 
2398
            tu->tokenTime = 0;
 
2399
#endif /* UKERNEL */
 
2400
        }
 
2401
    }
 
2402
    ReleaseWriteLock(&afs_xuser);
 
2403
    return 0;
 
2404
}
 
2405
 
 
2406
/*!
 
2407
 * VIOC_AFS_MARINER_HOST (32) - Get/set mariner (cache manager monitor) host
 
2408
 *
 
2409
 * \ingroup pioctl
 
2410
 *
 
2411
 * \param[in] ain       host address to be set
 
2412
 * \param[out] aout     old host address
 
2413
 *
 
2414
 * \post
 
2415
 *      depending on whether or not a variable is set, either get the host
 
2416
 *      for the cache manager monitor, or set the old address and give it
 
2417
 *      a new address
 
2418
 *
 
2419
 * \notes Errors turn off mariner
 
2420
 */
 
2421
DECL_PIOCTL(PMariner)
 
2422
{
 
2423
    afs_int32 newHostAddr;
 
2424
    afs_int32 oldHostAddr;
 
2425
 
 
2426
    AFS_STATCNT(PMariner);
 
2427
    if (afs_mariner)
 
2428
        memcpy((char *)&oldHostAddr, (char *)&afs_marinerHost,
 
2429
               sizeof(afs_int32));
 
2430
    else
 
2431
        oldHostAddr = 0xffffffff;       /* disabled */
 
2432
 
 
2433
    if (afs_pd_getInt(ain, &newHostAddr) != 0)
 
2434
        return EINVAL;
 
2435
 
 
2436
    if (newHostAddr == 0xffffffff) {
 
2437
        /* disable mariner operations */
 
2438
        afs_mariner = 0;
 
2439
    } else if (newHostAddr) {
 
2440
        afs_mariner = 1;
 
2441
        afs_marinerHost = newHostAddr;
 
2442
    }
 
2443
 
 
2444
    if (afs_pd_putInt(aout, oldHostAddr) != 0)
 
2445
        return E2BIG;
 
2446
 
 
2447
    return 0;
 
2448
}
 
2449
 
 
2450
/*!
 
2451
 * VIOCCKSERV (10) - Check that servers are up
 
2452
 *
 
2453
 * \ingroup pioctl
 
2454
 *
 
2455
 * \param[in] ain       name of the cell
 
2456
 * \param[out] aout     current down server list
 
2457
 *
 
2458
 * \retval EIO          Error if the afs daemon hasn't started yet
 
2459
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
2460
 * \retval ENOENT       Error if we are unable to obtain the cell
 
2461
 *
 
2462
 * \post
 
2463
 *      Either a fast check (where it doesn't contact servers) or a
 
2464
 *      local check (checks local cell only)
 
2465
 */
 
2466
DECL_PIOCTL(PCheckServers)
 
2467
{
 
2468
    int i;
 
2469
    struct server *ts;
 
2470
    afs_int32 temp;
 
2471
    char *cellName = NULL;
 
2472
    struct cell *cellp;
 
2473
    struct chservinfo *pcheck;
 
2474
 
 
2475
    AFS_STATCNT(PCheckServers);
 
2476
 
 
2477
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2478
        return EIO;             /* Inappropriate ioctl for device */
 
2479
 
 
2480
    /* This is tricky, because we need to peak at the datastream to see
 
2481
     * what we're getting. For now, let's cheat. */
 
2482
 
 
2483
    /* ain contains either an int32 or a string */
 
2484
    if (ain->remaining == 0)
 
2485
        return EINVAL;
 
2486
 
 
2487
    if (*(afs_int32 *)ain->ptr == 0x12345678) { /* For afs3.3 version */
 
2488
        pcheck = afs_pd_inline(ain, sizeof(*pcheck));
 
2489
        if (pcheck == NULL)
 
2490
            return EINVAL;
 
2491
 
 
2492
        if (pcheck->tinterval >= 0) {
 
2493
            if (afs_pd_putInt(aout, afs_probe_interval) != 0)
 
2494
                return E2BIG;
 
2495
            if (pcheck->tinterval > 0) {
 
2496
                if (!afs_osi_suser(*acred))
 
2497
                    return EACCES;
 
2498
                afs_probe_interval = pcheck->tinterval;
 
2499
            }
 
2500
            return 0;
 
2501
        }
 
2502
        temp = pcheck->tflags;
 
2503
        if (pcheck->tsize)
 
2504
            cellName = pcheck->tbuffer;
 
2505
    } else {                    /* For pre afs3.3 versions */
 
2506
        if (afs_pd_getInt(ain, &temp) != 0)
 
2507
            return EINVAL;
 
2508
        if (afs_pd_remaining(ain) > 0) {
 
2509
            if (afs_pd_getStringPtr(ain, &cellName) != 0)
 
2510
                return EINVAL;
 
2511
        }
 
2512
    }
 
2513
 
 
2514
    /*
 
2515
     * 1: fast check, don't contact servers.
 
2516
     * 2: local cell only.
 
2517
     */
 
2518
    if (cellName) {
 
2519
        /* have cell name, too */
 
2520
        cellp = afs_GetCellByName(cellName, READ_LOCK);
 
2521
        if (!cellp)
 
2522
            return ENOENT;
 
2523
    } else
 
2524
        cellp = NULL;
 
2525
    if (!cellp && (temp & 2)) {
 
2526
        /* use local cell */
 
2527
        cellp = afs_GetPrimaryCell(READ_LOCK);
 
2528
    }
 
2529
    if (!(temp & 1)) {          /* if not fast, call server checker routine */
 
2530
        afs_CheckServers(1, cellp);     /* check down servers */
 
2531
        afs_CheckServers(0, cellp);     /* check up servers */
 
2532
    }
 
2533
    /* now return the current down server list */
 
2534
    ObtainReadLock(&afs_xserver);
 
2535
    for (i = 0; i < NSERVERS; i++) {
 
2536
        for (ts = afs_servers[i]; ts; ts = ts->next) {
 
2537
            if (cellp && ts->cell != cellp)
 
2538
                continue;       /* cell spec'd and wrong */
 
2539
            if ((ts->flags & SRVR_ISDOWN)
 
2540
                && ts->addr->sa_portal != ts->cell->vlport) {
 
2541
                afs_pd_putInt(aout, ts->addr->sa_ip);
 
2542
            }
 
2543
        }
 
2544
    }
 
2545
    ReleaseReadLock(&afs_xserver);
 
2546
    if (cellp)
 
2547
        afs_PutCell(cellp, READ_LOCK);
 
2548
    return 0;
 
2549
}
 
2550
 
 
2551
/*!
 
2552
 * VIOCCKBACK (11) - Check backup volume mappings
 
2553
 *
 
2554
 * \ingroup pioctl
 
2555
 *
 
2556
 * \param[in] ain       not in use
 
2557
 * \param[out] aout     not in use
 
2558
 *
 
2559
 * \retval EIO          Error if the afs daemon hasn't started yet
 
2560
 *
 
2561
 * \post
 
2562
 *      Check the root volume, and then check the names if the volume
 
2563
 *      check variable is set to force, has expired, is busy, or if
 
2564
 *      the mount points variable is set
 
2565
 */
 
2566
DECL_PIOCTL(PCheckVolNames)
 
2567
{
 
2568
    AFS_STATCNT(PCheckVolNames);
 
2569
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2570
        return EIO;             /* Inappropriate ioctl for device */
 
2571
 
 
2572
    afs_CheckRootVolume();
 
2573
    afs_CheckVolumeNames(AFS_VOLCHECK_FORCE | AFS_VOLCHECK_EXPIRED |
 
2574
                         AFS_VOLCHECK_BUSY | AFS_VOLCHECK_MTPTS);
 
2575
    return 0;
 
2576
}
 
2577
 
 
2578
/*!
 
2579
 * VIOCCKCONN (12) - Check connections for a user
 
2580
 *
 
2581
 * \ingroup pioctl
 
2582
 *
 
2583
 * \param[in] ain       not in use
 
2584
 * \param[out] aout     not in use
 
2585
 *
 
2586
 * \retval EACCESS
 
2587
 *      Error if no user is specififed, the user has no tokens set,
 
2588
 *      or if the user's tokens are bad
 
2589
 *
 
2590
 * \post
 
2591
 *      check to see if a user has the correct authentication.
 
2592
 *      If so, allow access.
 
2593
 *
 
2594
 * \notes Check the connections to all the servers specified
 
2595
 */
 
2596
DECL_PIOCTL(PCheckAuth)
 
2597
{
 
2598
    int i;
 
2599
    struct srvAddr *sa;
 
2600
    struct afs_conn *tc;
 
2601
    struct unixuser *tu;
 
2602
    afs_int32 retValue;
 
2603
 
 
2604
    AFS_STATCNT(PCheckAuth);
 
2605
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2606
        return EIO;             /* Inappropriate ioctl for device */
 
2607
 
 
2608
    retValue = 0;
 
2609
    tu = afs_GetUser(areq->uid, 1, READ_LOCK);  /* check local cell authentication */
 
2610
    if (!tu)
 
2611
        retValue = EACCES;
 
2612
    else {
 
2613
        /* we have a user */
 
2614
        ObtainReadLock(&afs_xsrvAddr);
 
2615
        ObtainReadLock(&afs_xconn);
 
2616
 
 
2617
        /* any tokens set? */
 
2618
        if ((tu->states & UHasTokens) == 0)
 
2619
            retValue = EACCES;
 
2620
        /* all connections in cell 1 working? */
 
2621
        for (i = 0; i < NSERVERS; i++) {
 
2622
            for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
 
2623
                for (tc = sa->conns; tc; tc = tc->next) {
 
2624
                    if (tc->user == tu && (tu->states & UTokensBad))
 
2625
                        retValue = EACCES;
 
2626
                }
 
2627
            }
 
2628
        }
 
2629
        ReleaseReadLock(&afs_xsrvAddr);
 
2630
        ReleaseReadLock(&afs_xconn);
 
2631
        afs_PutUser(tu, READ_LOCK);
 
2632
    }
 
2633
    if (afs_pd_putInt(aout, retValue) != 0)
 
2634
        return E2BIG;
 
2635
    return 0;
 
2636
}
 
2637
 
 
2638
static int
 
2639
Prefetch(uparmtype apath, struct afs_ioctl *adata, int afollow,
 
2640
         afs_ucred_t *acred)
 
2641
{
 
2642
    char *tp;
 
2643
    afs_int32 code;
 
2644
#if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
 
2645
    size_t bufferSize;
 
2646
#else
 
2647
    u_int bufferSize;
 
2648
#endif
 
2649
 
 
2650
    AFS_STATCNT(Prefetch);
 
2651
    if (!apath)
 
2652
        return EINVAL;
 
2653
    tp = osi_AllocLargeSpace(1024);
 
2654
    AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
 
2655
    if (code) {
 
2656
        osi_FreeLargeSpace(tp);
 
2657
        return code;
 
2658
    }
 
2659
    if (afs_BBusy()) {          /* do this as late as possible */
 
2660
        osi_FreeLargeSpace(tp);
 
2661
        return EWOULDBLOCK;     /* pretty close */
 
2662
    }
 
2663
    afs_BQueue(BOP_PATH, (struct vcache *)0, 0, 0, acred, (afs_size_t) 0,
 
2664
               (afs_size_t) 0, tp, (void *)0, (void *)0);
 
2665
    return 0;
 
2666
}
 
2667
 
 
2668
/*!
 
2669
 * VIOCWHEREIS (14) - Find out where a volume is located
 
2670
 *
 
2671
 * \ingroup pioctl
 
2672
 *
 
2673
 * \param[in] ain       not in use
 
2674
 * \param[out] aout     volume location
 
2675
 *
 
2676
 * \retval EINVAL       Error if some of the default arguments don't exist
 
2677
 * \retval ENODEV       Error if there is no such volume
 
2678
 *
 
2679
 * \post fine a volume, based on a volume file id
 
2680
 *
 
2681
 * \notes check each of the servers specified
 
2682
 */
 
2683
DECL_PIOCTL(PFindVolume)
 
2684
{
 
2685
    struct volume *tvp;
 
2686
    struct server *ts;
 
2687
    afs_int32 i;
 
2688
    int code = 0;
 
2689
 
 
2690
    AFS_STATCNT(PFindVolume);
 
2691
    if (!avc)
 
2692
        return EINVAL;
 
2693
    tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
 
2694
    if (!tvp)
 
2695
        return ENODEV;
 
2696
 
 
2697
    for (i = 0; i < AFS_MAXHOSTS; i++) {
 
2698
        ts = tvp->serverHost[i];
 
2699
        if (!ts)
 
2700
            break;
 
2701
        if (afs_pd_putInt(aout, ts->addr->sa_ip) != 0) {
 
2702
            code = E2BIG;
 
2703
            goto out;
 
2704
        }
 
2705
    }
 
2706
    if (i < AFS_MAXHOSTS) {
 
2707
        /* still room for terminating NULL, add it on */
 
2708
        if (afs_pd_putInt(aout, 0) != 0) {
 
2709
            code = E2BIG;
 
2710
            goto out;
 
2711
        }
 
2712
    }
 
2713
out:
 
2714
    afs_PutVolume(tvp, READ_LOCK);
 
2715
    return code;
 
2716
}
 
2717
 
 
2718
/*!
 
2719
 * VIOCACCESS (20) - Access using PRS_FS bits
 
2720
 *
 
2721
 * \ingroup pioctl
 
2722
 *
 
2723
 * \param[in] ain       PRS_FS bits
 
2724
 * \param[out] aout     not in use
 
2725
 *
 
2726
 * \retval EINVAL       Error if some of the initial arguments aren't set
 
2727
 * \retval EACCES       Error if access is denied
 
2728
 *
 
2729
 * \post check to make sure access is allowed
 
2730
 */
 
2731
DECL_PIOCTL(PViceAccess)
 
2732
{
 
2733
    afs_int32 code;
 
2734
    afs_int32 temp;
 
2735
 
 
2736
    AFS_STATCNT(PViceAccess);
 
2737
    if (!avc)
 
2738
        return EINVAL;
 
2739
 
 
2740
    code = afs_VerifyVCache(avc, areq);
 
2741
    if (code)
 
2742
        return code;
 
2743
 
 
2744
    if (afs_pd_getInt(ain, &temp) != 0)
 
2745
        return EINVAL;
 
2746
 
 
2747
    code = afs_AccessOK(avc, temp, areq, CHECK_MODE_BITS);
 
2748
    if (code)
 
2749
        return 0;
 
2750
    else
 
2751
        return EACCES;
 
2752
}
 
2753
 
 
2754
/*!
 
2755
 * VIOC_GETPAG (13) - Get PAG value
 
2756
 *
 
2757
 * \ingroup pioctl
 
2758
 *
 
2759
 * \param[in] ain       not in use
 
2760
 * \param[out] aout     PAG value or NOPAG
 
2761
 *
 
2762
 * \post get PAG value for the caller's cred
 
2763
 */
 
2764
DECL_PIOCTL(PGetPAG)
 
2765
{
 
2766
    afs_int32 pag;
 
2767
 
 
2768
    pag = PagInCred(*acred);
 
2769
 
 
2770
    return afs_pd_putInt(aout, pag);
 
2771
}
 
2772
 
 
2773
DECL_PIOCTL(PPrecache)
 
2774
{
 
2775
    afs_int32 newValue;
 
2776
 
 
2777
    /*AFS_STATCNT(PPrecache);*/
 
2778
    if (!afs_osi_suser(*acred))
 
2779
        return EACCES;
 
2780
 
 
2781
    if (afs_pd_getInt(ain, &newValue) != 0)
 
2782
        return EINVAL;
 
2783
 
 
2784
    afs_preCache = newValue*1024;
 
2785
    return 0;
 
2786
}
 
2787
 
 
2788
/*!
 
2789
 * VIOCSETCACHESIZE (24) - Set venus cache size in 1000 units
 
2790
 *
 
2791
 * \ingroup pioctl
 
2792
 *
 
2793
 * \param[in] ain       the size the venus cache should be set to
 
2794
 * \param[out] aout     not in use
 
2795
 *
 
2796
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
2797
 * \retval EROFS        Error if the cache is set to be in memory
 
2798
 *
 
2799
 * \post
 
2800
 *      Set the cache size based on user input.  If no size is given,
 
2801
 *      set it to the default OpenAFS cache size.
 
2802
 *
 
2803
 * \notes
 
2804
 *      recompute the general cache parameters for every single block allocated
 
2805
 */
 
2806
DECL_PIOCTL(PSetCacheSize)
 
2807
{
 
2808
    afs_int32 newValue;
 
2809
    int waitcnt = 0;
 
2810
 
 
2811
    AFS_STATCNT(PSetCacheSize);
 
2812
 
 
2813
    if (!afs_osi_suser(*acred))
 
2814
        return EACCES;
 
2815
    /* too many things are setup initially in mem cache version */
 
2816
    if (cacheDiskType == AFS_FCACHE_TYPE_MEM)
 
2817
        return EROFS;
 
2818
    if (afs_pd_getInt(ain, &newValue) != 0)
 
2819
        return EINVAL;
 
2820
    if (newValue == 0)
 
2821
        afs_cacheBlocks = afs_stats_cmperf.cacheBlocksOrig;
 
2822
    else {
 
2823
        if (newValue < afs_min_cache)
 
2824
            afs_cacheBlocks = afs_min_cache;
 
2825
        else
 
2826
            afs_cacheBlocks = newValue;
 
2827
    }
 
2828
    afs_stats_cmperf.cacheBlocksTotal = afs_cacheBlocks;
 
2829
    afs_ComputeCacheParms();    /* recompute basic cache parameters */
 
2830
    afs_MaybeWakeupTruncateDaemon();
 
2831
    while (waitcnt++ < 100 && afs_cacheBlocks < afs_blocksUsed) {
 
2832
        afs_osi_Wait(1000, 0, 0);
 
2833
        afs_MaybeWakeupTruncateDaemon();
 
2834
    }
 
2835
    return 0;
 
2836
}
 
2837
 
 
2838
#define MAXGCSTATS      16
 
2839
/*!
 
2840
 * VIOCGETCACHEPARMS (40) - Get cache stats
 
2841
 *
 
2842
 * \ingroup pioctl
 
2843
 *
 
2844
 * \param[in] ain       afs index flags
 
2845
 * \param[out] aout     cache blocks, blocks used, blocks files (in an array)
 
2846
 *
 
2847
 * \post Get the cache blocks, and how many of the cache blocks there are
 
2848
 */
 
2849
DECL_PIOCTL(PGetCacheSize)
 
2850
{
 
2851
    afs_int32 results[MAXGCSTATS];
 
2852
    afs_int32 flags;
 
2853
    struct dcache * tdc;
 
2854
    int i, size;
 
2855
 
 
2856
    AFS_STATCNT(PGetCacheSize);
 
2857
 
 
2858
    if (afs_pd_remaining(ain) == sizeof(afs_int32)) {
 
2859
        afs_pd_getInt(ain, &flags); /* can't error, we just checked size */
 
2860
    } else if (afs_pd_remaining(ain) == 0) {
 
2861
        flags = 0;
 
2862
    } else {
 
2863
        return EINVAL;
 
2864
    }
 
2865
 
 
2866
    memset(results, 0, sizeof(results));
 
2867
    results[0] = afs_cacheBlocks;
 
2868
    results[1] = afs_blocksUsed;
 
2869
    results[2] = afs_cacheFiles;
 
2870
 
 
2871
    if (1 == flags){
 
2872
        for (i = 0; i < afs_cacheFiles; i++) {
 
2873
            if (afs_indexFlags[i] & IFFree) results[3]++;
 
2874
        }
 
2875
    } else if (2 == flags){
 
2876
        for (i = 0; i < afs_cacheFiles; i++) {
 
2877
            if (afs_indexFlags[i] & IFFree) results[3]++;
 
2878
            if (afs_indexFlags[i] & IFEverUsed) results[4]++;
 
2879
            if (afs_indexFlags[i] & IFDataMod) results[5]++;
 
2880
            if (afs_indexFlags[i] & IFDirtyPages) results[6]++;
 
2881
            if (afs_indexFlags[i] & IFAnyPages) results[7]++;
 
2882
            if (afs_indexFlags[i] & IFDiscarded) results[8]++;
 
2883
 
 
2884
            tdc = afs_indexTable[i];
 
2885
            if (tdc){
 
2886
                results[9]++;
 
2887
                size = tdc->validPos;
 
2888
                if ( 0 < size && size < (1<<12) ) results[10]++;
 
2889
                else if (size < (1<<14) ) results[11]++;
 
2890
                else if (size < (1<<16) ) results[12]++;
 
2891
                else if (size < (1<<18) ) results[13]++;
 
2892
                else if (size < (1<<20) ) results[14]++;
 
2893
                else if (size >= (1<<20) ) results[15]++;
 
2894
            }
 
2895
        }
 
2896
    }
 
2897
    return afs_pd_putBytes(aout, results, sizeof(results));
 
2898
}
 
2899
 
 
2900
/*!
 
2901
 * VIOCFLUSHCB (25) - Flush callback only
 
2902
 *
 
2903
 * \ingroup pioctl
 
2904
 *
 
2905
 * \param[in] ain       not in use
 
2906
 * \param[out] aout     not in use
 
2907
 *
 
2908
 * \retval EINVAL       Error if some of the standard args aren't set
 
2909
 * \retval 0            0 returned if the volume is set to read-only
 
2910
 *
 
2911
 * \post
 
2912
 *      Flushes callbacks, by setting the length of callbacks to one,
 
2913
 *      setting the next callback to be sent to the CB_DROPPED value,
 
2914
 *      and then dequeues everything else.
 
2915
 */
 
2916
DECL_PIOCTL(PRemoveCallBack)
 
2917
{
 
2918
    struct afs_conn *tc;
 
2919
    afs_int32 code = 0;
 
2920
    struct AFSCallBack CallBacks_Array[1];
 
2921
    struct AFSCBFids theFids;
 
2922
    struct AFSCBs theCBs;
 
2923
    struct rx_connection *rxconn;
 
2924
    XSTATS_DECLS;
 
2925
 
 
2926
    AFS_STATCNT(PRemoveCallBack);
 
2927
    if (!avc)
 
2928
        return EINVAL;
 
2929
    if (avc->f.states & CRO)
 
2930
        return 0;               /* read-only-ness can't change */
 
2931
    ObtainWriteLock(&avc->lock, 229);
 
2932
    theFids.AFSCBFids_len = 1;
 
2933
    theCBs.AFSCBs_len = 1;
 
2934
    theFids.AFSCBFids_val = (struct AFSFid *)&avc->f.fid.Fid;
 
2935
    theCBs.AFSCBs_val = CallBacks_Array;
 
2936
    CallBacks_Array[0].CallBackType = CB_DROPPED;
 
2937
    if (avc->callback) {
 
2938
        do {
 
2939
            tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
2940
            if (tc) {
 
2941
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS);
 
2942
                RX_AFS_GUNLOCK();
 
2943
                code = RXAFS_GiveUpCallBacks(rxconn, &theFids, &theCBs);
 
2944
                RX_AFS_GLOCK();
 
2945
                XSTATS_END_TIME;
 
2946
            }
 
2947
            /* don't set code on failure since we wouldn't use it */
 
2948
        } while (afs_Analyze
 
2949
                 (tc, rxconn, code, &avc->f.fid, areq,
 
2950
                  AFS_STATS_FS_RPCIDX_GIVEUPCALLBACKS, SHARED_LOCK, NULL));
 
2951
 
 
2952
        ObtainWriteLock(&afs_xcbhash, 457);
 
2953
        afs_DequeueCallback(avc);
 
2954
        avc->callback = 0;
 
2955
        avc->f.states &= ~(CStatd | CUnique);
 
2956
        ReleaseWriteLock(&afs_xcbhash);
 
2957
        if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
 
2958
            osi_dnlc_purgedp(avc);
 
2959
    }
 
2960
    ReleaseWriteLock(&avc->lock);
 
2961
    return 0;
 
2962
}
 
2963
 
 
2964
/*!
 
2965
 * VIOCNEWCELL (26) - Configure new cell
 
2966
 *
 
2967
 * \ingroup pioctl
 
2968
 *
 
2969
 * \param[in] ain
 
2970
 *      the name of the cell, the hosts that will be a part of the cell,
 
2971
 *      whether or not it's linked with another cell, the other cell it's
 
2972
 *      linked with, the file server port, and the volume server port
 
2973
 * \param[out] aout
 
2974
 *      not in use
 
2975
 *
 
2976
 * \retval EIO          Error if the afs daemon hasn't started yet
 
2977
 * \retval EACCES       Error if the user doesn't have super-user cedentials
 
2978
 * \retval EINVAL       Error if some 'magic' var doesn't have a certain bit set
 
2979
 *
 
2980
 * \post creates a new cell
 
2981
 */
 
2982
DECL_PIOCTL(PNewCell)
 
2983
{
 
2984
    afs_int32 cellHosts[AFS_MAXCELLHOSTS], magic = 0;
 
2985
    char *newcell = NULL;
 
2986
    char *linkedcell = NULL;
 
2987
    afs_int32 code, ls;
 
2988
    afs_int32 linkedstate = 0;
 
2989
    afs_int32 fsport = 0, vlport = 0;
 
2990
    int skip;
 
2991
 
 
2992
    AFS_STATCNT(PNewCell);
 
2993
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
2994
        return EIO;             /* Inappropriate ioctl for device */
 
2995
 
 
2996
    if (!afs_osi_suser(*acred))
 
2997
        return EACCES;
 
2998
 
 
2999
    if (afs_pd_getInt(ain, &magic) != 0)
 
3000
        return EINVAL;
 
3001
    if (magic != 0x12345678)
 
3002
        return EINVAL;
 
3003
 
 
3004
    /* A 3.4 fs newcell command will pass an array of AFS_MAXCELLHOSTS
 
3005
     * server addresses while the 3.5 fs newcell command passes
 
3006
     * AFS_MAXHOSTS. To figure out which is which, check if the cellname
 
3007
     * is good.
 
3008
     *
 
3009
     * This whole logic is bogus, because it relies on the newer command
 
3010
     * sending its 12th address as 0.
 
3011
     */
 
3012
    if ((afs_pd_remaining(ain) < AFS_MAXCELLHOSTS +3) * sizeof(afs_int32))
 
3013
        return EINVAL;
 
3014
 
 
3015
    newcell = afs_pd_where(ain) + (AFS_MAXCELLHOSTS + 3) * sizeof(afs_int32);
 
3016
    if (newcell[0] != '\0') {
 
3017
        skip = 0;
 
3018
    } else {
 
3019
        skip = AFS_MAXHOSTS - AFS_MAXCELLHOSTS;
 
3020
    }
 
3021
 
 
3022
    /* AFS_MAXCELLHOSTS (=8) is less than AFS_MAXHOSTS (=13) */
 
3023
    if (afs_pd_getBytes(ain, &cellHosts,
 
3024
                        AFS_MAXCELLHOSTS * sizeof(afs_int32)) != 0)
 
3025
        return EINVAL;
 
3026
    if (afs_pd_skip(ain, skip * sizeof(afs_int32)) !=0)
 
3027
        return EINVAL;
 
3028
 
 
3029
    if (afs_pd_getInt(ain, &fsport) != 0)
 
3030
        return EINVAL;
 
3031
    if (fsport < 1024)
 
3032
        fsport = 0;             /* Privileged ports not allowed */
 
3033
 
 
3034
    if (afs_pd_getInt(ain, &vlport) != 0)
 
3035
        return EINVAL;
 
3036
    if (vlport < 1024)
 
3037
        vlport = 0;             /* Privileged ports not allowed */
 
3038
 
 
3039
    if (afs_pd_getInt(ain, &ls) != 0)
 
3040
        return EINVAL;
 
3041
 
 
3042
    if (afs_pd_getStringPtr(ain, &newcell) != 0)
 
3043
        return EINVAL;
 
3044
 
 
3045
    if (ls & 1) {
 
3046
        if (afs_pd_getStringPtr(ain, &linkedcell) != 0)
 
3047
            return EINVAL;
 
3048
        linkedstate |= CLinkedCell;
 
3049
    }
 
3050
 
 
3051
    linkedstate |= CNoSUID;     /* setuid is disabled by default for fs newcell */
 
3052
    code =
 
3053
        afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport,
 
3054
                    vlport, (int)0);
 
3055
    return code;
 
3056
}
 
3057
 
 
3058
DECL_PIOCTL(PNewAlias)
 
3059
{
 
3060
    /* create a new cell alias */
 
3061
    char *realName, *aliasName;
 
3062
 
 
3063
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3064
        return EIO;             /* Inappropriate ioctl for device */
 
3065
 
 
3066
    if (!afs_osi_suser(*acred))
 
3067
        return EACCES;
 
3068
 
 
3069
    if (afs_pd_getStringPtr(ain, &aliasName) != 0)
 
3070
        return EINVAL;
 
3071
    if (afs_pd_getStringPtr(ain, &realName) != 0)
 
3072
        return EINVAL;
 
3073
 
 
3074
    return afs_NewCellAlias(aliasName, realName);
 
3075
}
 
3076
 
 
3077
/*!
 
3078
 * VIOCGETCELL (27) - Get cell info
 
3079
 *
 
3080
 * \ingroup pioctl
 
3081
 *
 
3082
 * \param[in] ain       The cell index of a specific cell
 
3083
 * \param[out] aout     list of servers in the cell
 
3084
 *
 
3085
 * \retval EIO          Error if the afs daemon hasn't started yet
 
3086
 * \retval EDOM         Error if there is no cell asked about
 
3087
 *
 
3088
 * \post Lists the cell's server names and and addresses
 
3089
 */
 
3090
DECL_PIOCTL(PListCells)
 
3091
{
 
3092
    afs_int32 whichCell;
 
3093
    struct cell *tcell = 0;
 
3094
    afs_int32 i;
 
3095
    int code;
 
3096
 
 
3097
    AFS_STATCNT(PListCells);
 
3098
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3099
        return EIO;             /* Inappropriate ioctl for device */
 
3100
 
 
3101
    if (afs_pd_getInt(ain, &whichCell) != 0)
 
3102
        return EINVAL;
 
3103
 
 
3104
    tcell = afs_GetCellByIndex(whichCell, READ_LOCK);
 
3105
    if (!tcell)
 
3106
        return EDOM;
 
3107
 
 
3108
    code = E2BIG;
 
3109
 
 
3110
    for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
 
3111
        if (tcell->cellHosts[i] == 0)
 
3112
            break;
 
3113
        if (afs_pd_putInt(aout, tcell->cellHosts[i]->addr->sa_ip) != 0)
 
3114
            goto out;
 
3115
    }
 
3116
    for (;i < AFS_MAXCELLHOSTS; i++) {
 
3117
        if (afs_pd_putInt(aout, 0) != 0)
 
3118
            goto out;
 
3119
    }
 
3120
    if (afs_pd_putString(aout, tcell->cellName) != 0)
 
3121
        goto out;
 
3122
    code = 0;
 
3123
 
 
3124
out:
 
3125
    afs_PutCell(tcell, READ_LOCK);
 
3126
    return code;
 
3127
}
 
3128
 
 
3129
DECL_PIOCTL(PListAliases)
 
3130
{
 
3131
    afs_int32 whichAlias;
 
3132
    struct cell_alias *tcalias = 0;
 
3133
    int code;
 
3134
 
 
3135
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3136
        return EIO;             /* Inappropriate ioctl for device */
 
3137
 
 
3138
    if (afs_pd_getInt(ain, &whichAlias) != 0)
 
3139
        return EINVAL;
 
3140
 
 
3141
    tcalias = afs_GetCellAlias(whichAlias);
 
3142
    if (tcalias == NULL)
 
3143
        return EDOM;
 
3144
 
 
3145
    code = E2BIG;
 
3146
    if (afs_pd_putString(aout, tcalias->alias) != 0)
 
3147
        goto out;
 
3148
    if (afs_pd_putString(aout, tcalias->cell) != 0)
 
3149
        goto out;
 
3150
 
 
3151
    code = 0;
 
3152
out:
 
3153
    afs_PutCellAlias(tcalias);
 
3154
    return code;
 
3155
}
 
3156
 
 
3157
/*!
 
3158
 * VIOC_AFS_DELETE_MT_PT (28) - Delete mount point
 
3159
 *
 
3160
 * \ingroup pioctl
 
3161
 *
 
3162
 * \param[in] ain       the name of the file in this dir to remove
 
3163
 * \param[out] aout     not in use
 
3164
 *
 
3165
 * \retval EINVAL
 
3166
 *      Error if some of the standard args aren't set
 
3167
 * \retval ENOTDIR
 
3168
 *      Error if the argument to remove is not a directory
 
3169
 * \retval ENOENT
 
3170
 *      Error if there is no cache to remove the mount point from or
 
3171
 *      if a vcache doesn't exist
 
3172
 *
 
3173
 * \post
 
3174
 *      Ensure that everything is OK before deleting the mountpoint.
 
3175
 *      If not, don't delete.  Delete a mount point based on a file id.
 
3176
 */
 
3177
DECL_PIOCTL(PRemoveMount)
 
3178
{
 
3179
    afs_int32 code;
 
3180
    char *bufp;
 
3181
    char *name;
 
3182
    struct sysname_info sysState;
 
3183
    afs_size_t offset, len;
 
3184
    struct afs_conn *tc;
 
3185
    struct dcache *tdc;
 
3186
    struct vcache *tvc;
 
3187
    struct AFSFetchStatus OutDirStatus;
 
3188
    struct VenusFid tfid;
 
3189
    struct AFSVolSync tsync;
 
3190
    struct rx_connection *rxconn;
 
3191
    XSTATS_DECLS;
 
3192
 
 
3193
    /* "ain" is the name of the file in this dir to remove */
 
3194
 
 
3195
    AFS_STATCNT(PRemoveMount);
 
3196
    if (!avc)
 
3197
        return EINVAL;
 
3198
    if (afs_pd_getStringPtr(ain, &name) != 0)
 
3199
        return EINVAL;
 
3200
 
 
3201
    code = afs_VerifyVCache(avc, areq);
 
3202
    if (code)
 
3203
        return code;
 
3204
    if (vType(avc) != VDIR)
 
3205
        return ENOTDIR;
 
3206
 
 
3207
    tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);   /* test for error below */
 
3208
    if (!tdc)
 
3209
        return ENOENT;
 
3210
    Check_AtSys(avc, name, &sysState, areq);
 
3211
    ObtainReadLock(&tdc->lock);
 
3212
    do {
 
3213
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
 
3214
    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
 
3215
    ReleaseReadLock(&tdc->lock);
 
3216
    bufp = sysState.name;
 
3217
    if (code) {
 
3218
        afs_PutDCache(tdc);
 
3219
        goto out;
 
3220
    }
 
3221
    tfid.Cell = avc->f.fid.Cell;
 
3222
    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
 
3223
    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
 
3224
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
 
3225
    } else {
 
3226
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
 
3227
    }
 
3228
    if (!tvc) {
 
3229
        code = ENOENT;
 
3230
        afs_PutDCache(tdc);
 
3231
        goto out;
 
3232
    }
 
3233
    if (tvc->mvstat != 1) {
 
3234
        afs_PutDCache(tdc);
 
3235
        afs_PutVCache(tvc);
 
3236
        code = EINVAL;
 
3237
        goto out;
 
3238
    }
 
3239
    ObtainWriteLock(&tvc->lock, 230);
 
3240
    code = afs_HandleLink(tvc, areq);
 
3241
    if (!code) {
 
3242
        if (tvc->linkData) {
 
3243
            if ((tvc->linkData[0] != '#') && (tvc->linkData[0] != '%'))
 
3244
                code = EINVAL;
 
3245
        } else
 
3246
            code = EIO;
 
3247
    }
 
3248
    ReleaseWriteLock(&tvc->lock);
 
3249
    osi_dnlc_purgedp(tvc);
 
3250
    afs_PutVCache(tvc);
 
3251
    if (code) {
 
3252
        afs_PutDCache(tdc);
 
3253
        goto out;
 
3254
    }
 
3255
    ObtainWriteLock(&avc->lock, 231);
 
3256
    osi_dnlc_remove(avc, bufp, tvc);
 
3257
    do {
 
3258
        tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
 
3259
        if (tc) {
 
3260
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
 
3261
            RX_AFS_GUNLOCK();
 
3262
            code =
 
3263
                RXAFS_RemoveFile(rxconn, (struct AFSFid *)&avc->f.fid.Fid, bufp,
 
3264
                                 &OutDirStatus, &tsync);
 
3265
            RX_AFS_GLOCK();
 
3266
            XSTATS_END_TIME;
 
3267
        } else
 
3268
            code = -1;
 
3269
    } while (afs_Analyze
 
3270
             (tc, rxconn, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_REMOVEFILE,
 
3271
              SHARED_LOCK, NULL));
 
3272
 
 
3273
    if (code) {
 
3274
        if (tdc)
 
3275
            afs_PutDCache(tdc);
 
3276
        ReleaseWriteLock(&avc->lock);
 
3277
        goto out;
 
3278
    }
 
3279
    if (tdc) {
 
3280
        /* we have the thing in the cache */
 
3281
        ObtainWriteLock(&tdc->lock, 661);
 
3282
        if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
 
3283
            /* we can do it locally */
 
3284
            code = afs_dir_Delete(tdc, bufp);
 
3285
            if (code) {
 
3286
                ZapDCE(tdc);    /* surprise error -- invalid value */
 
3287
                DZap(tdc);
 
3288
            }
 
3289
        }
 
3290
        ReleaseWriteLock(&tdc->lock);
 
3291
        afs_PutDCache(tdc);     /* drop ref count */
 
3292
    }
 
3293
    avc->f.states &= ~CUnique;  /* For the dfs xlator */
 
3294
    ReleaseWriteLock(&avc->lock);
 
3295
    code = 0;
 
3296
  out:
 
3297
    if (sysState.allocked)
 
3298
        osi_FreeLargeSpace(bufp);
 
3299
    return code;
 
3300
}
 
3301
 
 
3302
/*!
 
3303
 * VIOC_GETCELLSTATUS (35) - Get cell status info
 
3304
 *
 
3305
 * \ingroup pioctl
 
3306
 *
 
3307
 * \param[in] ain       The cell you want status information on
 
3308
 * \param[out] aout     cell state (as a struct)
 
3309
 *
 
3310
 * \retval EIO          Error if the afs daemon hasn't started yet
 
3311
 * \retval ENOENT       Error if the cell doesn't exist
 
3312
 *
 
3313
 * \post Returns the state of the cell as defined in a struct cell
 
3314
 */
 
3315
DECL_PIOCTL(PGetCellStatus)
 
3316
{
 
3317
    struct cell *tcell;
 
3318
    char *cellName;
 
3319
    afs_int32 temp;
 
3320
 
 
3321
    AFS_STATCNT(PGetCellStatus);
 
3322
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3323
        return EIO;             /* Inappropriate ioctl for device */
 
3324
 
 
3325
    if (afs_pd_getStringPtr(ain, &cellName) != 0)
 
3326
        return EINVAL;
 
3327
 
 
3328
    tcell = afs_GetCellByName(cellName, READ_LOCK);
 
3329
    if (!tcell)
 
3330
        return ENOENT;
 
3331
    temp = tcell->states;
 
3332
    afs_PutCell(tcell, READ_LOCK);
 
3333
 
 
3334
    return afs_pd_putInt(aout, temp);
 
3335
}
 
3336
 
 
3337
/*!
 
3338
 * VIOC_SETCELLSTATUS (36) - Set corresponding info
 
3339
 *
 
3340
 * \ingroup pioctl
 
3341
 *
 
3342
 * \param[in] ain
 
3343
 *      The cell you want to set information about, and the values you
 
3344
 *      want to set
 
3345
 * \param[out] aout
 
3346
 *      not in use
 
3347
 *
 
3348
 * \retval EIO          Error if the afs daemon hasn't started yet
 
3349
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
3350
 *
 
3351
 * \post
 
3352
 *      Set the state of the cell in a defined struct cell, based on
 
3353
 *      whether or not SetUID is allowed
 
3354
 */
 
3355
DECL_PIOCTL(PSetCellStatus)
 
3356
{
 
3357
    struct cell *tcell;
 
3358
    char *cellName;
 
3359
    afs_int32 flags0, flags1;
 
3360
 
 
3361
    if (!afs_osi_suser(*acred))
 
3362
        return EACCES;
 
3363
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3364
        return EIO;             /* Inappropriate ioctl for device */
 
3365
 
 
3366
    if (afs_pd_getInt(ain, &flags0) != 0)
 
3367
        return EINVAL;
 
3368
    if (afs_pd_getInt(ain, &flags1) != 0)
 
3369
        return EINVAL;
 
3370
    if (afs_pd_getStringPtr(ain, &cellName) != 0)
 
3371
        return EINVAL;
 
3372
 
 
3373
    tcell = afs_GetCellByName(cellName, WRITE_LOCK);
 
3374
    if (!tcell)
 
3375
        return ENOENT;
 
3376
    if (flags0 & CNoSUID)
 
3377
        tcell->states |= CNoSUID;
 
3378
    else
 
3379
        tcell->states &= ~CNoSUID;
 
3380
    afs_PutCell(tcell, WRITE_LOCK);
 
3381
    return 0;
 
3382
}
 
3383
 
 
3384
/*!
 
3385
 * VIOC_FLUSHVOLUME (37) - Flush whole volume's data
 
3386
 *
 
3387
 * \ingroup pioctl
 
3388
 *
 
3389
 * \param[in] ain       not in use (args in avc)
 
3390
 * \param[out] aout     not in use
 
3391
 *
 
3392
 * \retval EINVAL       Error if some of the standard args aren't set
 
3393
 * \retval EIO          Error if the afs daemon hasn't started yet
 
3394
 *
 
3395
 * \post
 
3396
 *      Flush all cached contents of a volume.  Exactly what stays and what
 
3397
 *      goes depends on the platform.
 
3398
 *
 
3399
 * \notes
 
3400
 *      Does not flush a file that a user has open and is using, because
 
3401
 *      it will be re-created on next write.  Also purges the dnlc,
 
3402
 *      because things are screwed up.
 
3403
 */
 
3404
DECL_PIOCTL(PFlushVolumeData)
 
3405
{
 
3406
    afs_int32 i;
 
3407
    struct dcache *tdc;
 
3408
    struct vcache *tvc;
 
3409
    struct volume *tv;
 
3410
    afs_int32 cell, volume;
 
3411
    struct afs_q *tq, *uq;
 
3412
#ifdef AFS_DARWIN80_ENV
 
3413
    vnode_t vp;
 
3414
#endif
 
3415
 
 
3416
    AFS_STATCNT(PFlushVolumeData);
 
3417
    if (!avc)
 
3418
        return EINVAL;
 
3419
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3420
        return EIO;             /* Inappropriate ioctl for device */
 
3421
 
 
3422
    volume = avc->f.fid.Fid.Volume;     /* who to zap */
 
3423
    cell = avc->f.fid.Cell;
 
3424
 
 
3425
    /*
 
3426
     * Clear stat'd flag from all vnodes from this volume; this will
 
3427
     * invalidate all the vcaches associated with the volume.
 
3428
     */
 
3429
 loop:
 
3430
    ObtainReadLock(&afs_xvcache);
 
3431
    i = VCHashV(&avc->f.fid);
 
3432
    for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
 
3433
            uq = QPrev(tq);
 
3434
            tvc = QTOVH(tq);
 
3435
            if (tvc->f.fid.Fid.Volume == volume && tvc->f.fid.Cell == cell) {
 
3436
                if (tvc->f.states & CVInit) {
 
3437
                    ReleaseReadLock(&afs_xvcache);
 
3438
                    afs_osi_Sleep(&tvc->f.states);
 
3439
                    goto loop;
 
3440
                }
 
3441
#ifdef AFS_DARWIN80_ENV
 
3442
                if (tvc->f.states & CDeadVnode) {
 
3443
                    ReleaseReadLock(&afs_xvcache);
 
3444
                    afs_osi_Sleep(&tvc->f.states);
 
3445
                    goto loop;
 
3446
                }
 
3447
                vp = AFSTOV(tvc);
 
3448
                if (vnode_get(vp))
 
3449
                    continue;
 
3450
                if (vnode_ref(vp)) {
 
3451
                    AFS_GUNLOCK();
 
3452
                    vnode_put(vp);
 
3453
                    AFS_GLOCK();
 
3454
                    continue;
 
3455
                }
 
3456
#else
 
3457
                AFS_FAST_HOLD(tvc);
 
3458
#endif
 
3459
                ReleaseReadLock(&afs_xvcache);
 
3460
#ifdef AFS_BOZONLOCK_ENV
 
3461
                afs_BozonLock(&tvc->pvnLock, tvc);      /* Since afs_TryToSmush will do a pvn_vptrunc */
 
3462
#endif
 
3463
                ObtainWriteLock(&tvc->lock, 232);
 
3464
 
 
3465
                ObtainWriteLock(&afs_xcbhash, 458);
 
3466
                afs_DequeueCallback(tvc);
 
3467
                tvc->f.states &= ~(CStatd | CDirty);
 
3468
                ReleaseWriteLock(&afs_xcbhash);
 
3469
                if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
 
3470
                    osi_dnlc_purgedp(tvc);
 
3471
                afs_TryToSmush(tvc, *acred, 1);
 
3472
                ReleaseWriteLock(&tvc->lock);
 
3473
#ifdef AFS_BOZONLOCK_ENV
 
3474
                afs_BozonUnlock(&tvc->pvnLock, tvc);
 
3475
#endif
 
3476
#ifdef AFS_DARWIN80_ENV
 
3477
                vnode_put(AFSTOV(tvc));
 
3478
#endif
 
3479
                ObtainReadLock(&afs_xvcache);
 
3480
                uq = QPrev(tq);
 
3481
                /* our tvc ptr is still good until now */
 
3482
                AFS_FAST_RELE(tvc);
 
3483
            }
 
3484
        }
 
3485
    ReleaseReadLock(&afs_xvcache);
 
3486
 
 
3487
 
 
3488
    ObtainWriteLock(&afs_xdcache, 328); /* needed to flush any stuff */
 
3489
    for (i = 0; i < afs_cacheFiles; i++) {
 
3490
        if (!(afs_indexFlags[i] & IFEverUsed))
 
3491
            continue;           /* never had any data */
 
3492
        tdc = afs_GetValidDSlot(i);
 
3493
        if (!tdc) {
 
3494
            continue;
 
3495
        }
 
3496
        if (tdc->refCount <= 1) {    /* too high, in use by running sys call */
 
3497
            ReleaseReadLock(&tdc->tlock);
 
3498
            if (tdc->f.fid.Fid.Volume == volume && tdc->f.fid.Cell == cell) {
 
3499
                if (!(afs_indexFlags[i] & IFDataMod)) {
 
3500
                    /* if the file is modified, but has a ref cnt of only 1,
 
3501
                     * then someone probably has the file open and is writing
 
3502
                     * into it. Better to skip flushing such a file, it will be
 
3503
                     * brought back immediately on the next write anyway.
 
3504
                     *
 
3505
                     * If we *must* flush, then this code has to be rearranged
 
3506
                     * to call afs_storeAllSegments() first */
 
3507
                    afs_FlushDCache(tdc);
 
3508
                }
 
3509
            }
 
3510
        } else {
 
3511
            ReleaseReadLock(&tdc->tlock);
 
3512
        }
 
3513
        afs_PutDCache(tdc);     /* bumped by getdslot */
 
3514
    }
 
3515
    ReleaseWriteLock(&afs_xdcache);
 
3516
 
 
3517
    ObtainReadLock(&afs_xvolume);
 
3518
    for (i = 0; i < NVOLS; i++) {
 
3519
        for (tv = afs_volumes[i]; tv; tv = tv->next) {
 
3520
            if (tv->volume == volume) {
 
3521
                afs_ResetVolumeInfo(tv);
 
3522
                break;
 
3523
            }
 
3524
        }
 
3525
    }
 
3526
    ReleaseReadLock(&afs_xvolume);
 
3527
 
 
3528
    /* probably, a user is doing this, probably, because things are screwed up.
 
3529
     * maybe it's the dnlc's fault? */
 
3530
    osi_dnlc_purge();
 
3531
    return 0;
 
3532
}
 
3533
 
 
3534
 
 
3535
/*!
 
3536
 * VIOCGETVCXSTATUS (41) - gets vnode x status
 
3537
 *
 
3538
 * \ingroup pioctl
 
3539
 *
 
3540
 * \param[in] ain
 
3541
 *      not in use (avc used)
 
3542
 * \param[out] aout
 
3543
 *      vcxstat: the file id, the data version, any lock, the parent vnode,
 
3544
 *      the parent unique id, the trunc position, the callback, cbExpires,
 
3545
 *      what access is being made, what files are open,
 
3546
 *      any users executing/writing, the flock count, the states,
 
3547
 *      the move stat
 
3548
 *
 
3549
 * \retval EINVAL
 
3550
 *      Error if some of the initial default arguments aren't set
 
3551
 * \retval EACCES
 
3552
 *      Error if access to check the mode bits is denied
 
3553
 *
 
3554
 * \post
 
3555
 *      gets stats for the vnode, a struct listed in vcxstat
 
3556
 */
 
3557
DECL_PIOCTL(PGetVnodeXStatus)
 
3558
{
 
3559
    afs_int32 code;
 
3560
    struct vcxstat stat;
 
3561
    afs_int32 mode, i;
 
3562
 
 
3563
/*  AFS_STATCNT(PGetVnodeXStatus); */
 
3564
    if (!avc)
 
3565
        return EINVAL;
 
3566
    code = afs_VerifyVCache(avc, areq);
 
3567
    if (code)
 
3568
        return code;
 
3569
    if (vType(avc) == VDIR)
 
3570
        mode = PRSFS_LOOKUP;
 
3571
    else
 
3572
        mode = PRSFS_READ;
 
3573
    if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
 
3574
        return EACCES;
 
3575
 
 
3576
    memset(&stat, 0, sizeof(struct vcxstat));
 
3577
    stat.fid = avc->f.fid;
 
3578
    hset32(stat.DataVersion, hgetlo(avc->f.m.DataVersion));
 
3579
    stat.lock = avc->lock;
 
3580
    stat.parentVnode = avc->f.parent.vnode;
 
3581
    stat.parentUnique = avc->f.parent.unique;
 
3582
    hset(stat.flushDV, avc->flushDV);
 
3583
    hset(stat.mapDV, avc->mapDV);
 
3584
    stat.truncPos = avc->f.truncPos;
 
3585
    {                   /* just grab the first two - won't break anything... */
 
3586
        struct axscache *ac;
 
3587
 
 
3588
        for (i = 0, ac = avc->Access; ac && i < CPSIZE; i++, ac = ac->next) {
 
3589
            stat.randomUid[i] = ac->uid;
 
3590
            stat.randomAccess[i] = ac->axess;
 
3591
        }
 
3592
    }
 
3593
    stat.callback = afs_data_pointer_to_int32(avc->callback);
 
3594
    stat.cbExpires = avc->cbExpires;
 
3595
    stat.anyAccess = avc->f.anyAccess;
 
3596
    stat.opens = avc->opens;
 
3597
    stat.execsOrWriters = avc->execsOrWriters;
 
3598
    stat.flockCount = avc->flockCount;
 
3599
    stat.mvstat = avc->mvstat;
 
3600
    stat.states = avc->f.states;
 
3601
    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat));
 
3602
}
 
3603
 
 
3604
 
 
3605
DECL_PIOCTL(PGetVnodeXStatus2)
 
3606
{
 
3607
    afs_int32 code;
 
3608
    struct vcxstat2 stat;
 
3609
    afs_int32 mode;
 
3610
 
 
3611
    if (!avc)
 
3612
        return EINVAL;
 
3613
    code = afs_VerifyVCache(avc, areq);
 
3614
    if (code)
 
3615
        return code;
 
3616
    if (vType(avc) == VDIR)
 
3617
        mode = PRSFS_LOOKUP;
 
3618
    else
 
3619
        mode = PRSFS_READ;
 
3620
    if (!afs_AccessOK(avc, mode, areq, CHECK_MODE_BITS))
 
3621
        return EACCES;
 
3622
 
 
3623
    memset(&stat, 0, sizeof(struct vcxstat2));
 
3624
 
 
3625
    stat.cbExpires = avc->cbExpires;
 
3626
    stat.anyAccess = avc->f.anyAccess;
 
3627
    stat.mvstat = avc->mvstat;
 
3628
    stat.callerAccess = afs_GetAccessBits(avc, ~0, areq);
 
3629
 
 
3630
    return afs_pd_putBytes(aout, &stat, sizeof(struct vcxstat2));
 
3631
}
 
3632
 
 
3633
 
 
3634
/*!
 
3635
 * VIOC_AFS_SYSNAME (38) - Change @sys value
 
3636
 *
 
3637
 * \ingroup pioctl
 
3638
 *
 
3639
 * \param[in] ain       new value for @sys
 
3640
 * \param[out] aout     count, entry, list (debug values?)
 
3641
 *
 
3642
 * \retval EINVAL
 
3643
 *      Error if afsd isn't running, the new sysname is too large,
 
3644
 *      the new sysname causes issues (starts with a . or ..),
 
3645
 *      there is no PAG set in the credentials, or the user of a PAG
 
3646
 *      can't be found
 
3647
 * \retval EACCES
 
3648
 *      Error if the user doesn't have super-user credentials
 
3649
 *
 
3650
 * \post
 
3651
 *      Set the value of @sys if these things work: if the input isn't
 
3652
 *      too long or if input doesn't start with . or ..
 
3653
 *
 
3654
 * \notes
 
3655
 *      We require root for local sysname changes, but not for remote
 
3656
 *      (since we don't really believe remote uids anyway)
 
3657
 *      outname[] shouldn't really be needed- this is left as an
 
3658
 *      exercise for the reader.
 
3659
 */
 
3660
DECL_PIOCTL(PSetSysName)
 
3661
{
 
3662
    char *inname = NULL;
 
3663
    char outname[MAXSYSNAME];
 
3664
    afs_int32 setsysname;
 
3665
    int foundname = 0;
 
3666
    struct afs_exporter *exporter;
 
3667
    struct unixuser *au;
 
3668
    afs_int32 pag, error;
 
3669
    int t, count, num = 0, allpags = 0;
 
3670
    char **sysnamelist;
 
3671
    struct afs_pdata validate;
 
3672
 
 
3673
    AFS_STATCNT(PSetSysName);
 
3674
    if (!afs_globalVFS) {
 
3675
        /* Afsd is NOT running; disable it */
 
3676
#if defined(KERNEL_HAVE_UERROR)
 
3677
        return (setuerror(EINVAL), EINVAL);
 
3678
#else
 
3679
        return (EINVAL);
 
3680
#endif
 
3681
    }
 
3682
    if (afs_pd_getInt(ain, &setsysname) != 0)
 
3683
        return EINVAL;
 
3684
    if (setsysname & 0x8000) {
 
3685
        allpags = 1;
 
3686
        setsysname &= ~0x8000;
 
3687
    }
 
3688
    if (setsysname) {
 
3689
 
 
3690
        /* Check my args */
 
3691
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
 
3692
            return EINVAL;
 
3693
        validate = *ain;
 
3694
        for (count = 0; count < setsysname; count++) {
 
3695
            if (afs_pd_getStringPtr(&validate, &inname) != 0)
 
3696
                return EINVAL;
 
3697
            t = strlen(inname);
 
3698
            if (t >= MAXSYSNAME || t <= 0)
 
3699
                return EINVAL;
 
3700
            /* check for names that can shoot us in the foot */
 
3701
            if (inname[0] == '.' && (inname[1] == 0
 
3702
                || (inname[1] == '.' && inname[2] == 0)))
 
3703
                return EINVAL;
 
3704
        }
 
3705
        /* args ok, so go back to the beginning of that section */
 
3706
 
 
3707
        if (afs_pd_getStringPtr(ain, &inname) != 0)
 
3708
            return EINVAL;
 
3709
        num = count;
 
3710
    }
 
3711
    if (afs_cr_gid(*acred) == RMTUSER_REQ ||
 
3712
        afs_cr_gid(*acred) == RMTUSER_REQ_PRIV) {   /* Handles all exporters */
 
3713
        if (allpags && afs_cr_gid(*acred) != RMTUSER_REQ_PRIV) {
 
3714
            return EPERM;
 
3715
        }
 
3716
        pag = PagInCred(*acred);
 
3717
        if (pag == NOPAG) {
 
3718
            return EINVAL;      /* Better than panicing */
 
3719
        }
 
3720
        if (!(au = afs_FindUser(pag, -1, READ_LOCK))) {
 
3721
            return EINVAL;      /* Better than panicing */
 
3722
        }
 
3723
        if (!(exporter = au->exporter)) {
 
3724
            afs_PutUser(au, READ_LOCK);
 
3725
            return EINVAL;      /* Better than panicing */
 
3726
        }
 
3727
        error = EXP_SYSNAME(exporter, inname, &sysnamelist,
 
3728
                            &num, allpags);
 
3729
        if (error) {
 
3730
            if (error == ENODEV)
 
3731
                foundname = 0;  /* sysname not set yet! */
 
3732
            else {
 
3733
                afs_PutUser(au, READ_LOCK);
 
3734
                return error;
 
3735
            }
 
3736
        } else {
 
3737
            foundname = num;
 
3738
            strcpy(outname, sysnamelist[0]);
 
3739
        }
 
3740
        afs_PutUser(au, READ_LOCK);
 
3741
        if (setsysname)
 
3742
            afs_sysnamegen++;
 
3743
    } else {
 
3744
        /* Not xlating, so local case */
 
3745
        if (!afs_sysname)
 
3746
            osi_Panic("PSetSysName: !afs_sysname\n");
 
3747
        if (!setsysname) {      /* user just wants the info */
 
3748
            strcpy(outname, afs_sysname);
 
3749
            foundname = afs_sysnamecount;
 
3750
            sysnamelist = afs_sysnamelist;
 
3751
        } else {                /* Local guy; only root can change sysname */
 
3752
            if (!afs_osi_suser(*acred))
 
3753
                return EACCES;
 
3754
 
 
3755
            /* allpags makes no sense for local use */
 
3756
            if (allpags)
 
3757
                return EINVAL;
 
3758
 
 
3759
            /* clear @sys entries from the dnlc, once afs_lookup can
 
3760
             * do lookups of @sys entries and thinks it can trust them */
 
3761
            /* privs ok, store the entry, ... */
 
3762
 
 
3763
            if (strlen(inname) >= MAXSYSNAME-1)
 
3764
                return EINVAL;
 
3765
            strcpy(afs_sysname, inname);
 
3766
 
 
3767
            if (setsysname > 1) {       /* ... or list */
 
3768
                for (count = 1; count < setsysname; ++count) {
 
3769
                    if (!afs_sysnamelist[count])
 
3770
                        osi_Panic
 
3771
                           ("PSetSysName: no afs_sysnamelist entry to write\n");
 
3772
                    if (afs_pd_getString(ain, afs_sysnamelist[count],
 
3773
                                         MAXSYSNAME) != 0)
 
3774
                        return EINVAL;
 
3775
                }
 
3776
            }
 
3777
            afs_sysnamecount = setsysname;
 
3778
            afs_sysnamegen++;
 
3779
        }
 
3780
    }
 
3781
    if (!setsysname) {
 
3782
        if (afs_pd_putInt(aout, foundname) != 0)
 
3783
            return E2BIG;
 
3784
        if (foundname) {
 
3785
            if (afs_pd_putString(aout, outname) != 0)
 
3786
                return E2BIG;
 
3787
            for (count = 1; count < foundname; ++count) {    /* ... or list. */
 
3788
                if (!sysnamelist[count])
 
3789
                    osi_Panic
 
3790
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
 
3791
                t = strlen(sysnamelist[count]);
 
3792
                if (t >= MAXSYSNAME)
 
3793
                    osi_Panic("PSetSysName: sysname entry garbled\n");
 
3794
                if (afs_pd_putString(aout, sysnamelist[count]) != 0)
 
3795
                    return E2BIG;
 
3796
            }
 
3797
        }
 
3798
    }
 
3799
    return 0;
 
3800
}
 
3801
 
 
3802
/* sequential search through the list of touched cells is not a good
 
3803
 * long-term solution here. For small n, though, it should be just
 
3804
 * fine.  Should consider special-casing the local cell for large n.
 
3805
 * Likewise for PSetSPrefs.
 
3806
 *
 
3807
 * s - number of ids in array l[] -- NOT index of last id
 
3808
 * l - array of cell ids which have volumes that need to be sorted
 
3809
 * vlonly - sort vl servers or file servers?
 
3810
 */
 
3811
static void *
 
3812
ReSortCells_cb(struct cell *cell, void *arg)
 
3813
{
 
3814
    afs_int32 *p = (afs_int32 *) arg;
 
3815
    afs_int32 *l = p + 1;
 
3816
    int i, s = p[0];
 
3817
 
 
3818
    for (i = 0; i < s; i++) {
 
3819
        if (l[i] == cell->cellNum) {
 
3820
            ObtainWriteLock(&cell->lock, 690);
 
3821
            afs_SortServers(cell->cellHosts, AFS_MAXCELLHOSTS);
 
3822
            ReleaseWriteLock(&cell->lock);
 
3823
        }
 
3824
    }
 
3825
 
 
3826
    return NULL;
 
3827
}
 
3828
 
 
3829
static void
 
3830
ReSortCells(int s, afs_int32 * l, int vlonly)
 
3831
{
 
3832
    int i;
 
3833
    struct volume *j;
 
3834
    int k;
 
3835
 
 
3836
    if (vlonly) {
 
3837
        afs_int32 *p;
 
3838
        p = afs_osi_Alloc(sizeof(afs_int32) * (s + 1));
 
3839
        osi_Assert(p != NULL);
 
3840
        p[0] = s;
 
3841
        memcpy(p + 1, l, s * sizeof(afs_int32));
 
3842
        afs_TraverseCells(&ReSortCells_cb, p);
 
3843
        afs_osi_Free(p, sizeof(afs_int32) * (s + 1));
 
3844
        return;
 
3845
    }
 
3846
 
 
3847
    ObtainReadLock(&afs_xvolume);
 
3848
    for (i = 0; i < NVOLS; i++) {
 
3849
        for (j = afs_volumes[i]; j; j = j->next) {
 
3850
            for (k = 0; k < s; k++)
 
3851
                if (j->cell == l[k]) {
 
3852
                    ObtainWriteLock(&j->lock, 233);
 
3853
                    afs_SortServers(j->serverHost, AFS_MAXHOSTS);
 
3854
                    ReleaseWriteLock(&j->lock);
 
3855
                    break;
 
3856
                }
 
3857
        }
 
3858
    }
 
3859
    ReleaseReadLock(&afs_xvolume);
 
3860
}
 
3861
 
 
3862
 
 
3863
static int debugsetsp = 0;
 
3864
static int
 
3865
afs_setsprefs(struct spref *sp, unsigned int num, unsigned int vlonly)
 
3866
{
 
3867
    struct srvAddr *sa;
 
3868
    int i, j, k, matches, touchedSize;
 
3869
    struct server *srvr = NULL;
 
3870
    afs_int32 touched[34];
 
3871
    int isfs;
 
3872
 
 
3873
    touchedSize = 0;
 
3874
    for (k = 0; k < num; sp++, k++) {
 
3875
        if (debugsetsp) {
 
3876
            afs_warn("sp host=%x, rank=%d\n", sp->host.s_addr, sp->rank);
 
3877
        }
 
3878
        matches = 0;
 
3879
        ObtainReadLock(&afs_xserver);
 
3880
 
 
3881
        i = SHash(sp->host.s_addr);
 
3882
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
 
3883
            if (sa->sa_ip == sp->host.s_addr) {
 
3884
                srvr = sa->server;
 
3885
                isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
 
3886
                    || (sa->sa_portal == AFS_FSPORT);
 
3887
                if ((!vlonly && isfs) || (vlonly && !isfs)) {
 
3888
                    matches++;
 
3889
                    break;
 
3890
                }
 
3891
            }
 
3892
        }
 
3893
 
 
3894
        if (sa && matches) {    /* found one! */
 
3895
            if (debugsetsp) {
 
3896
                afs_warn("sa ip=%x, ip_rank=%d\n", sa->sa_ip, sa->sa_iprank);
 
3897
            }
 
3898
            sa->sa_iprank = sp->rank + afs_randomMod15();
 
3899
            afs_SortOneServer(sa->server);
 
3900
 
 
3901
            if (srvr->cell) {
 
3902
                /* if we don't know yet what cell it's in, this is moot */
 
3903
                for (j = touchedSize - 1;
 
3904
                     j >= 0 && touched[j] != srvr->cell->cellNum; j--)
 
3905
                    /* is it in our list of touched cells ?  */ ;
 
3906
                if (j < 0) {    /* no, it's not */
 
3907
                    touched[touchedSize++] = srvr->cell->cellNum;
 
3908
                    if (touchedSize >= 32) {    /* watch for ovrflow */
 
3909
                        ReleaseReadLock(&afs_xserver);
 
3910
                        ReSortCells(touchedSize, touched, vlonly);
 
3911
                        touchedSize = 0;
 
3912
                        ObtainReadLock(&afs_xserver);
 
3913
                    }
 
3914
                }
 
3915
            }
 
3916
        }
 
3917
 
 
3918
        ReleaseReadLock(&afs_xserver);
 
3919
        /* if we didn't find one, start to create one. */
 
3920
        /* Note that it doesn't have a cell yet...     */
 
3921
        if (!matches) {
 
3922
            afs_uint32 temp = sp->host.s_addr;
 
3923
            srvr =
 
3924
                afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT),
 
3925
                              WRITE_LOCK, (afsUUID *) 0, 0, NULL);
 
3926
            srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
 
3927
            afs_PutServer(srvr, WRITE_LOCK);
 
3928
        }
 
3929
    }                           /* for all cited preferences */
 
3930
 
 
3931
    ReSortCells(touchedSize, touched, vlonly);
 
3932
    return 0;
 
3933
}
 
3934
 
 
3935
/*!
 
3936
 * VIOC_SETPREFS (46) - Set server ranks
 
3937
 *
 
3938
 * \param[in] ain       the sprefs value you want the sprefs to be set to
 
3939
 * \param[out] aout     not in use
 
3940
 *
 
3941
 * \retval EIO
 
3942
 *      Error if the afs daemon hasn't started yet
 
3943
 * \retval EACCES
 
3944
 *      Error if the user doesn't have super-user credentials
 
3945
 * \retval EINVAL
 
3946
 *      Error if the struct setsprefs is too large or if it multiplied
 
3947
 *      by the number of servers is too large
 
3948
 *
 
3949
 * \post set the sprefs using the afs_setsprefs() function
 
3950
 */
 
3951
DECL_PIOCTL(PSetSPrefs)
 
3952
{
 
3953
    struct setspref *ssp;
 
3954
    char *ainPtr;
 
3955
    size_t ainSize;
 
3956
 
 
3957
    AFS_STATCNT(PSetSPrefs);
 
3958
 
 
3959
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
3960
        return EIO;             /* Inappropriate ioctl for device */
 
3961
 
 
3962
    if (!afs_osi_suser(*acred))
 
3963
        return EACCES;
 
3964
 
 
3965
    /* The I/O handling here is ghastly, as it relies on overrunning the ends
 
3966
     * of arrays. But, i'm not quite brave enough to change it yet. */
 
3967
    ainPtr = ain->ptr;
 
3968
    ainSize = ain->remaining;
 
3969
 
 
3970
    if (ainSize < sizeof(struct setspref))
 
3971
        return EINVAL;
 
3972
 
 
3973
    ssp = (struct setspref *)ainPtr;
 
3974
    if (ainSize < (sizeof(struct setspref)
 
3975
                   + sizeof(struct spref) * (ssp->num_servers-1)))
 
3976
        return EINVAL;
 
3977
 
 
3978
    afs_setsprefs(&(ssp->servers[0]), ssp->num_servers,
 
3979
                  (ssp->flags & DBservers));
 
3980
    return 0;
 
3981
}
 
3982
 
 
3983
/*
 
3984
 * VIOC_SETPREFS33 (42) - Set server ranks (deprecated)
 
3985
 *
 
3986
 * \param[in] ain       the server preferences to be set
 
3987
 * \param[out] aout     not in use
 
3988
 *
 
3989
 * \retval EIO          Error if the afs daemon hasn't started yet
 
3990
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
3991
 *
 
3992
 * \post set the server preferences, calling a function
 
3993
 *
 
3994
 * \notes this may only be performed by the local root user.
 
3995
 */
 
3996
DECL_PIOCTL(PSetSPrefs33)
 
3997
{
 
3998
    AFS_STATCNT(PSetSPrefs);
 
3999
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
4000
        return EIO;             /* Inappropriate ioctl for device */
 
4001
 
 
4002
 
 
4003
    if (!afs_osi_suser(*acred))
 
4004
        return EACCES;
 
4005
 
 
4006
    afs_setsprefs((struct spref *)afs_pd_where(ain),
 
4007
                  afs_pd_remaining(ain) / sizeof(struct spref),
 
4008
                  0 /*!vlonly */ );
 
4009
    return 0;
 
4010
}
 
4011
 
 
4012
/*
 
4013
 * VIOC_GETSPREFS (43) - Get server ranks
 
4014
 *
 
4015
 * \ingroup pioctl
 
4016
 *
 
4017
 * \param[in] ain       the server preferences to get
 
4018
 * \param[out] aout     the server preferences information
 
4019
 *
 
4020
 * \retval EIO          Error if the afs daemon hasn't started yet
 
4021
 * \retval ENOENT       Error if the sprefrequest is too large
 
4022
 *
 
4023
 * \post Get the sprefs
 
4024
 *
 
4025
 * \notes
 
4026
 *      in the hash table of server structs, all servers with the same
 
4027
 *      IP address; will be on the same overflow chain; This could be
 
4028
 *      sped slightly in some circumstances by having it cache the
 
4029
 *      immediately previous slot in the hash table and some
 
4030
 *      supporting information; Only reports file servers now.
 
4031
 */
 
4032
DECL_PIOCTL(PGetSPrefs)
 
4033
{
 
4034
    struct sprefrequest spin;   /* input */
 
4035
    struct sprefinfo *spout;    /* output */
 
4036
    struct spref *srvout;       /* one output component */
 
4037
    int i, j;                   /* counters for hash table traversal */
 
4038
    struct server *srvr;        /* one of CM's server structs */
 
4039
    struct srvAddr *sa;
 
4040
    int vlonly;                 /* just return vlservers ? */
 
4041
    int isfs;
 
4042
 
 
4043
    AFS_STATCNT(PGetSPrefs);
 
4044
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
4045
        return EIO;             /* Inappropriate ioctl for device */
 
4046
 
 
4047
    /* Work out from the size whether we've got a new, or old, style pioctl */
 
4048
    if (afs_pd_remaining(ain) < sizeof(struct sprefrequest)) {
 
4049
        if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest_33)) != 0)
 
4050
           return ENOENT;
 
4051
        vlonly = 0;
 
4052
        spin.flags = 0;
 
4053
    } else {
 
4054
        if (afs_pd_getBytes(ain, &spin, sizeof(struct sprefrequest)) != 0)
 
4055
           return EINVAL;
 
4056
        vlonly = (spin.flags & DBservers);
 
4057
    }
 
4058
 
 
4059
    /* This code relies on overflowing arrays. It's ghastly, but I'm not
 
4060
     * quite brave enough to tackle it yet ...
 
4061
     */
 
4062
 
 
4063
    /* struct sprefinfo includes 1 server struct...  that size gets added
 
4064
     * in during the loop that follows.
 
4065
     */
 
4066
    spout = afs_pd_inline(aout,
 
4067
                          sizeof(struct sprefinfo) - sizeof(struct spref));
 
4068
    spout->next_offset = spin.offset;
 
4069
    spout->num_servers = 0;
 
4070
    srvout = spout->servers;
 
4071
 
 
4072
    ObtainReadLock(&afs_xserver);
 
4073
    for (i = 0, j = 0; j < NSERVERS; j++) {     /* sift through hash table */
 
4074
        for (sa = afs_srvAddrs[j]; sa; sa = sa->next_bkt, i++) {
 
4075
            if (spin.offset > (unsigned short)i) {
 
4076
                continue;       /* catch up to where we left off */
 
4077
            }
 
4078
            spout->next_offset++;
 
4079
 
 
4080
            srvr = sa->server;
 
4081
            isfs = (srvr->cell && (sa->sa_portal == srvr->cell->fsport))
 
4082
                || (sa->sa_portal == AFS_FSPORT);
 
4083
 
 
4084
            if ((vlonly && isfs) || (!vlonly && !isfs)) {
 
4085
                /* only report ranks for vl servers */
 
4086
                continue;
 
4087
            }
 
4088
 
 
4089
            /* Check we've actually got the space we're about to use */
 
4090
            if (afs_pd_inline(aout, sizeof(struct spref)) == NULL) {
 
4091
                ReleaseReadLock(&afs_xserver);  /* no more room! */
 
4092
                return 0;
 
4093
            }
 
4094
 
 
4095
            srvout->host.s_addr = sa->sa_ip;
 
4096
            srvout->rank = sa->sa_iprank;
 
4097
            spout->num_servers++;
 
4098
            srvout++;
 
4099
        }
 
4100
    }
 
4101
    ReleaseReadLock(&afs_xserver);
 
4102
 
 
4103
    spout->next_offset = 0;     /* start over from the beginning next time */
 
4104
 
 
4105
    return 0;
 
4106
}
 
4107
 
 
4108
/* Enable/Disable the specified exporter. Must be root to disable an exporter */
 
4109
int afs_NFSRootOnly = 1;
 
4110
/*!
 
4111
 * VIOC_EXPORTAFS (39) - Export afs to nfs clients
 
4112
 *
 
4113
 * \ingroup pioctl
 
4114
 *
 
4115
 * \param[in] ain
 
4116
 *      an integer containing the desired exportee flags
 
4117
 * \param[out] aout
 
4118
 *      an integer containing the current exporter flags
 
4119
 *
 
4120
 * \retval ENODEV       Error if the exporter doesn't exist
 
4121
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
4122
 *
 
4123
 * \post
 
4124
 *      Changes the state of various values to reflect the change
 
4125
 *      of the export values between nfs and afs.
 
4126
 *
 
4127
 * \notes Legacy code obtained from IBM.
 
4128
 */
 
4129
DECL_PIOCTL(PExportAfs)
 
4130
{
 
4131
    afs_int32 export, newint = 0;
 
4132
    afs_int32 type, changestate, handleValue, convmode, pwsync, smounts;
 
4133
    afs_int32 rempags = 0, pagcb = 0;
 
4134
    struct afs_exporter *exporter;
 
4135
 
 
4136
    AFS_STATCNT(PExportAfs);
 
4137
    if (afs_pd_getInt(ain, &handleValue) != 0)
 
4138
        return EINVAL;
 
4139
    type = handleValue >> 24;
 
4140
    if (type == 0x71) {
 
4141
        newint = 1;
 
4142
        type = 1;               /* nfs */
 
4143
    }
 
4144
    exporter = exporter_find(type);
 
4145
    if (newint) {
 
4146
        export = handleValue & 3;
 
4147
        changestate = handleValue & 0xfff;
 
4148
        smounts = (handleValue >> 2) & 3;
 
4149
        pwsync = (handleValue >> 4) & 3;
 
4150
        convmode = (handleValue >> 6) & 3;
 
4151
        rempags = (handleValue >> 8) & 3;
 
4152
        pagcb = (handleValue >> 10) & 3;
 
4153
    } else {
 
4154
        changestate = (handleValue >> 16) & 0x1;
 
4155
        convmode = (handleValue >> 16) & 0x2;
 
4156
        pwsync = (handleValue >> 16) & 0x4;
 
4157
        smounts = (handleValue >> 16) & 0x8;
 
4158
        export = handleValue & 0xff;
 
4159
    }
 
4160
    if (!exporter) {
 
4161
        /*  Failed finding desired exporter; */
 
4162
        return ENODEV;
 
4163
    }
 
4164
    if (!changestate) {
 
4165
        handleValue = exporter->exp_states;
 
4166
        if (afs_pd_putInt(aout, handleValue) != 0)
 
4167
            return E2BIG;
 
4168
    } else {
 
4169
        if (!afs_osi_suser(*acred))
 
4170
            return EACCES;      /* Only superuser can do this */
 
4171
        if (newint) {
 
4172
            if (export & 2) {
 
4173
                if (export & 1)
 
4174
                    exporter->exp_states |= EXP_EXPORTED;
 
4175
                else
 
4176
                    exporter->exp_states &= ~EXP_EXPORTED;
 
4177
            }
 
4178
            if (convmode & 2) {
 
4179
                if (convmode & 1)
 
4180
                    exporter->exp_states |= EXP_UNIXMODE;
 
4181
                else
 
4182
                    exporter->exp_states &= ~EXP_UNIXMODE;
 
4183
            }
 
4184
            if (pwsync & 2) {
 
4185
                if (pwsync & 1)
 
4186
                    exporter->exp_states |= EXP_PWSYNC;
 
4187
                else
 
4188
                    exporter->exp_states &= ~EXP_PWSYNC;
 
4189
            }
 
4190
            if (smounts & 2) {
 
4191
                if (smounts & 1) {
 
4192
                    afs_NFSRootOnly = 0;
 
4193
                    exporter->exp_states |= EXP_SUBMOUNTS;
 
4194
                } else {
 
4195
                    afs_NFSRootOnly = 1;
 
4196
                    exporter->exp_states &= ~EXP_SUBMOUNTS;
 
4197
                }
 
4198
            }
 
4199
            if (rempags & 2) {
 
4200
                if (rempags & 1)
 
4201
                    exporter->exp_states |= EXP_CLIPAGS;
 
4202
                else
 
4203
                    exporter->exp_states &= ~EXP_CLIPAGS;
 
4204
            }
 
4205
            if (pagcb & 2) {
 
4206
                if (pagcb & 1)
 
4207
                    exporter->exp_states |= EXP_CALLBACK;
 
4208
                else
 
4209
                    exporter->exp_states &= ~EXP_CALLBACK;
 
4210
            }
 
4211
            handleValue = exporter->exp_states;
 
4212
            if (afs_pd_putInt(aout, handleValue) != 0)
 
4213
                return E2BIG;
 
4214
        } else {
 
4215
            if (export)
 
4216
                exporter->exp_states |= EXP_EXPORTED;
 
4217
            else
 
4218
                exporter->exp_states &= ~EXP_EXPORTED;
 
4219
            if (convmode)
 
4220
                exporter->exp_states |= EXP_UNIXMODE;
 
4221
            else
 
4222
                exporter->exp_states &= ~EXP_UNIXMODE;
 
4223
            if (pwsync)
 
4224
                exporter->exp_states |= EXP_PWSYNC;
 
4225
            else
 
4226
                exporter->exp_states &= ~EXP_PWSYNC;
 
4227
            if (smounts) {
 
4228
                afs_NFSRootOnly = 0;
 
4229
                exporter->exp_states |= EXP_SUBMOUNTS;
 
4230
            } else {
 
4231
                afs_NFSRootOnly = 1;
 
4232
                exporter->exp_states &= ~EXP_SUBMOUNTS;
 
4233
            }
 
4234
        }
 
4235
    }
 
4236
 
 
4237
    return 0;
 
4238
}
 
4239
 
 
4240
/*!
 
4241
 * VIOC_GAG (44) - Silence Cache Manager
 
4242
 *
 
4243
 * \ingroup pioctl
 
4244
 *
 
4245
 * \param[in] ain       the flags to either gag or de-gag the cache manager
 
4246
 * \param[out] aout     not in use
 
4247
 *
 
4248
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
4249
 *
 
4250
 * \post set the gag flags, then show these flags
 
4251
 */
 
4252
DECL_PIOCTL(PGag)
 
4253
{
 
4254
    struct gaginfo *gagflags;
 
4255
 
 
4256
    if (!afs_osi_suser(*acred))
 
4257
        return EACCES;
 
4258
 
 
4259
    gagflags = afs_pd_inline(ain, sizeof(*gagflags));
 
4260
    if (gagflags == NULL)
 
4261
        return EINVAL;
 
4262
    afs_showflags = gagflags->showflags;
 
4263
 
 
4264
    return 0;
 
4265
}
 
4266
 
 
4267
/*!
 
4268
 * VIOC_TWIDDLE (45) - Adjust RX knobs
 
4269
 *
 
4270
 * \ingroup pioctl
 
4271
 *
 
4272
 * \param[in] ain       the previous settings of the 'knobs'
 
4273
 * \param[out] aout     not in use
 
4274
 *
 
4275
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
4276
 *
 
4277
 * \post build out the struct rxp, from a struct rx
 
4278
 */
 
4279
DECL_PIOCTL(PTwiddleRx)
 
4280
{
 
4281
    struct rxparams *rxp;
 
4282
 
 
4283
    if (!afs_osi_suser(*acred))
 
4284
        return EACCES;
 
4285
 
 
4286
    rxp = afs_pd_inline(ain, sizeof(*rxp));
 
4287
    if (rxp == NULL)
 
4288
        return EINVAL;
 
4289
 
 
4290
    if (rxp->rx_initReceiveWindow)
 
4291
        rx_initReceiveWindow = rxp->rx_initReceiveWindow;
 
4292
    if (rxp->rx_maxReceiveWindow)
 
4293
        rx_maxReceiveWindow = rxp->rx_maxReceiveWindow;
 
4294
    if (rxp->rx_initSendWindow)
 
4295
        rx_initSendWindow = rxp->rx_initSendWindow;
 
4296
    if (rxp->rx_maxSendWindow)
 
4297
        rx_maxSendWindow = rxp->rx_maxSendWindow;
 
4298
    if (rxp->rxi_nSendFrags)
 
4299
        rxi_nSendFrags = rxp->rxi_nSendFrags;
 
4300
    if (rxp->rxi_nRecvFrags)
 
4301
        rxi_nRecvFrags = rxp->rxi_nRecvFrags;
 
4302
    if (rxp->rxi_OrphanFragSize)
 
4303
        rxi_OrphanFragSize = rxp->rxi_OrphanFragSize;
 
4304
    if (rxp->rx_maxReceiveSize) {
 
4305
        rx_maxReceiveSize = rxp->rx_maxReceiveSize;
 
4306
        rx_maxReceiveSizeUser = rxp->rx_maxReceiveSize;
 
4307
    }
 
4308
    if (rxp->rx_MyMaxSendSize)
 
4309
        rx_MyMaxSendSize = rxp->rx_MyMaxSendSize;
 
4310
 
 
4311
    return 0;
 
4312
}
 
4313
 
 
4314
/*!
 
4315
 * VIOC_GETINITPARAMS (49) - Get initial cache manager parameters
 
4316
 *
 
4317
 * \ingroup pioctl
 
4318
 *
 
4319
 * \param[in] ain       not in use
 
4320
 * \param[out] aout     initial cache manager params
 
4321
 *
 
4322
 * \retval E2BIG
 
4323
 *      Error if the initial parameters are bigger than some PIGGYSIZE
 
4324
 *
 
4325
 * \post return the initial cache manager parameters
 
4326
 */
 
4327
DECL_PIOCTL(PGetInitParams)
 
4328
{
 
4329
    if (sizeof(struct cm_initparams) > PIGGYSIZE)
 
4330
        return E2BIG;
 
4331
 
 
4332
    return afs_pd_putBytes(aout, &cm_initParams,
 
4333
                           sizeof(struct cm_initparams));
 
4334
}
 
4335
 
 
4336
#ifdef AFS_SGI65_ENV
 
4337
/* They took crget() from us, so fake it. */
 
4338
static cred_t *
 
4339
crget(void)
 
4340
{
 
4341
    cred_t *cr;
 
4342
    cr = crdup(get_current_cred());
 
4343
    memset(cr, 0, sizeof(cred_t));
 
4344
#if CELL || CELL_PREPARE
 
4345
    cr->cr_id = -1;
 
4346
#endif
 
4347
    return cr;
 
4348
}
 
4349
#endif
 
4350
 
 
4351
/*!
 
4352
 * VIOC_GETRXKCRYPT (55) - Get rxkad encryption flag
 
4353
 *
 
4354
 * \ingroup pioctl
 
4355
 *
 
4356
 * \param[in] ain       not in use
 
4357
 * \param[out] aout     value of cryptall
 
4358
 *
 
4359
 * \post Turns on, or disables, rxkad encryption by setting the cryptall global
 
4360
 */
 
4361
DECL_PIOCTL(PGetRxkcrypt)
 
4362
{
 
4363
    return afs_pd_putInt(aout, cryptall);
 
4364
}
 
4365
 
 
4366
/*!
 
4367
 * VIOC_SETRXKCRYPT (56) - Set rxkad encryption flag
 
4368
 *
 
4369
 * \ingroup pioctl
 
4370
 *
 
4371
 * \param[in] ain       the argument whether or not things should be encrypted
 
4372
 * \param[out] aout     not in use
 
4373
 *
 
4374
 * \retval EPERM
 
4375
 *      Error if the user doesn't have super-user credentials
 
4376
 * \retval EINVAL
 
4377
 *      Error if the input is too big, or if the input is outside the
 
4378
 *      bounds of what it can be set to
 
4379
 *
 
4380
 * \post set whether or not things should be encrypted
 
4381
 *
 
4382
 * \notes
 
4383
 *      may need to be modified at a later date to take into account
 
4384
 *      other values for cryptall (beyond true or false)
 
4385
 */
 
4386
DECL_PIOCTL(PSetRxkcrypt)
 
4387
{
 
4388
    afs_int32 tmpval;
 
4389
 
 
4390
    if (!afs_osi_suser(*acred))
 
4391
        return EPERM;
 
4392
    if (afs_pd_getInt(ain, &tmpval) != 0)
 
4393
        return EINVAL;
 
4394
    /* if new mappings added later this will need to be changed */
 
4395
    if (tmpval != 0 && tmpval != 1)
 
4396
        return EINVAL;
 
4397
    cryptall = tmpval;
 
4398
    return 0;
 
4399
}
 
4400
 
 
4401
#ifdef AFS_NEED_CLIENTCONTEXT
 
4402
/*
 
4403
 * Create new credentials to correspond to a remote user with given
 
4404
 * <hostaddr, uid, g0, g1>.  This allows a server running as root to
 
4405
 * provide pioctl (and other) services to foreign clients (i.e. nfs
 
4406
 * clients) by using this call to `become' the client.
 
4407
 */
 
4408
#define PSETPAG         110
 
4409
#define PIOCTL_HEADER   6
 
4410
static int
 
4411
HandleClientContext(struct afs_ioctl *ablob, int *com,
 
4412
                    afs_ucred_t **acred, afs_ucred_t *credp)
 
4413
{
 
4414
    char *ain, *inData;
 
4415
    afs_uint32 hostaddr;
 
4416
    afs_int32 uid, g0, g1, i, code, pag, exporter_type, isroot = 0;
 
4417
    struct afs_exporter *exporter, *outexporter;
 
4418
    afs_ucred_t *newcred;
 
4419
    struct unixuser *au;
 
4420
    afs_uint32 comp = *com & 0xff00;
 
4421
    afs_uint32 h, l;
 
4422
#if defined(AFS_SUN510_ENV)
 
4423
    gid_t gids[2];
 
4424
#endif
 
4425
 
 
4426
#if defined(AFS_SGIMP_ENV)
 
4427
    osi_Assert(ISAFS_GLOCK());
 
4428
#endif
 
4429
    AFS_STATCNT(HandleClientContext);
 
4430
    if (ablob->in_size < PIOCTL_HEADER * sizeof(afs_int32)) {
 
4431
        /* Must at least include the PIOCTL_HEADER header words
 
4432
         * required by the protocol */
 
4433
        return EINVAL;          /* Too small to be good  */
 
4434
    }
 
4435
    ain = inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
 
4436
    AFS_COPYIN(ablob->in, ain, PIOCTL_HEADER * sizeof(afs_int32), code);
 
4437
    if (code) {
 
4438
        osi_FreeLargeSpace(inData);
 
4439
        return code;
 
4440
    }
 
4441
 
 
4442
    /* Extract information for remote user */
 
4443
    hostaddr = *((afs_uint32 *) ain);
 
4444
    ain += sizeof(hostaddr);
 
4445
    uid = *((afs_uint32 *) ain);
 
4446
    ain += sizeof(uid);
 
4447
    g0 = *((afs_uint32 *) ain);
 
4448
    ain += sizeof(g0);
 
4449
    g1 = *((afs_uint32 *) ain);
 
4450
    ain += sizeof(g1);
 
4451
    *com = *((afs_uint32 *) ain);
 
4452
    ain += sizeof(afs_int32);
 
4453
    exporter_type = *((afs_uint32 *) ain);/* In case we support more than NFS */
 
4454
 
 
4455
    /*
 
4456
     * Of course, one must be root for most of these functions, but
 
4457
     * we'll allow (for knfs) you to set things if the pag is 0 and
 
4458
     * you're setting tokens or unlogging.
 
4459
     */
 
4460
    i = (*com) & 0xff;
 
4461
    if (!afs_osi_suser(credp)) {
 
4462
#if defined(AFS_SGI_ENV) && !defined(AFS_SGI64_ENV)
 
4463
        /* Since SGI's suser() returns explicit failure after the call.. */
 
4464
        u.u_error = 0;
 
4465
#endif
 
4466
        /* check for acceptable opcodes for normal folks, which are, so far,
 
4467
         * get/set tokens, sysname, and unlog.
 
4468
         */
 
4469
        if (i != 9 && i != 3 && i != 38 && i != 8) {
 
4470
            osi_FreeLargeSpace(inData);
 
4471
            return EACCES;
 
4472
        }
 
4473
    }
 
4474
 
 
4475
    ablob->in_size -= PIOCTL_HEADER * sizeof(afs_int32);
 
4476
    ablob->in += PIOCTL_HEADER * sizeof(afs_int32);
 
4477
    osi_FreeLargeSpace(inData);
 
4478
    if (uid == 0) {
 
4479
        /*
 
4480
         * We map uid 0 to nobody to match the mapping that the nfs
 
4481
         * server does and to ensure that the suser() calls in the afs
 
4482
         * code fails for remote client roots.
 
4483
         */
 
4484
        uid = afs_nobody;       /* NFS_NOBODY == -2 */
 
4485
        isroot = 1;
 
4486
    }
 
4487
    newcred = crget();
 
4488
#ifdef  AFS_AIX41_ENV
 
4489
    setuerror(0);
 
4490
#endif
 
4491
    afs_set_cr_gid(newcred, isroot ? RMTUSER_REQ_PRIV : RMTUSER_REQ);
 
4492
#ifdef AFS_AIX51_ENV
 
4493
    newcred->cr_groupset.gs_union.un_groups[0] = g0;
 
4494
    newcred->cr_groupset.gs_union.un_groups[1] = g1;
 
4495
#elif defined(AFS_LINUX26_ENV)
 
4496
# ifdef AFS_LINUX26_ONEGROUP_ENV
 
4497
    afs_set_cr_group_info(newcred, groups_alloc(1)); /* nothing sets this */
 
4498
    l = (((g0-0x3f00) & 0x3fff) << 14) | ((g1-0x3f00) & 0x3fff);
 
4499
    h = ((g0-0x3f00) >> 14);
 
4500
    h = ((g1-0x3f00) >> 14) + h + h + h;
 
4501
    GROUP_AT(afs_cr_group_info(newcred), 0) = ((h << 28) | l);
 
4502
# else
 
4503
    afs_set_cr_group_info(newcred, groups_alloc(2));
 
4504
    GROUP_AT(afs_cr_group_info(newcred), 0) = g0;
 
4505
    GROUP_AT(afs_cr_group_info(newcred), 1) = g1;
 
4506
# endif
 
4507
#elif defined(AFS_SUN510_ENV)
 
4508
    gids[0] = g0;
 
4509
    gids[1] = g1;
 
4510
    crsetgroups(newcred, 2, gids);
 
4511
#else
 
4512
    newcred->cr_groups[0] = g0;
 
4513
    newcred->cr_groups[1] = g1;
 
4514
#endif
 
4515
#ifdef AFS_AIX_ENV
 
4516
    newcred->cr_ngrps = 2;
 
4517
#elif !defined(AFS_LINUX26_ENV) && !defined(AFS_SUN510_ENV)
 
4518
# if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX22_ENV) || defined(AFS_FBSD80_ENV)
 
4519
    newcred->cr_ngroups = 2;
 
4520
# else
 
4521
    for (i = 2; i < NGROUPS; i++)
 
4522
        newcred->cr_groups[i] = NOGROUP;
 
4523
# endif
 
4524
#endif
 
4525
    if (!(exporter = exporter_find(exporter_type))) {
 
4526
        /* Exporter wasn't initialized or an invalid exporter type */
 
4527
        crfree(newcred);
 
4528
        return EINVAL;
 
4529
    }
 
4530
    if (exporter->exp_states & EXP_PWSYNC) {
 
4531
        if (uid != afs_cr_uid(credp)) {
 
4532
            crfree(newcred);
 
4533
            return ENOEXEC;     /* XXX Find a better errno XXX */
 
4534
        }
 
4535
    }
 
4536
    afs_set_cr_uid(newcred, uid);       /* Only temporary  */
 
4537
    code = EXP_REQHANDLER(exporter, &newcred, hostaddr, &pag, &outexporter);
 
4538
    /* The client's pag is the only unique identifier for it */
 
4539
    afs_set_cr_uid(newcred, pag);
 
4540
    *acred = newcred;
 
4541
    if (!code && *com == PSETPAG) {
 
4542
        /* Special case for 'setpag' */
 
4543
        afs_uint32 pagvalue = genpag();
 
4544
 
 
4545
        au = afs_GetUser(pagvalue, -1, WRITE_LOCK); /* a new unixuser struct */
 
4546
        /*
 
4547
         * Note that we leave the 'outexporter' struct held so it won't
 
4548
         * dissappear on us
 
4549
         */
 
4550
        au->exporter = outexporter;
 
4551
        if (ablob->out_size >= 4) {
 
4552
            AFS_COPYOUT((char *)&pagvalue, ablob->out, sizeof(afs_int32),
 
4553
                        code);
 
4554
        }
 
4555
        afs_PutUser(au, WRITE_LOCK);
 
4556
        if (code)
 
4557
            return code;
 
4558
        return PSETPAG;         /*  Special return for setpag  */
 
4559
    } else if (!code) {
 
4560
        EXP_RELE(outexporter);
 
4561
    }
 
4562
    if (!code)
 
4563
        *com = (*com) | comp;
 
4564
    return code;
 
4565
}
 
4566
#endif /* AFS_NEED_CLIENTCONTEXT */
 
4567
 
 
4568
 
 
4569
/*!
 
4570
 * VIOC_GETCPREFS (50) - Get client interface
 
4571
 *
 
4572
 * \ingroup pioctl
 
4573
 *
 
4574
 * \param[in] ain       sprefrequest input
 
4575
 * \param[out] aout     spref information
 
4576
 *
 
4577
 * \retval EIO          Error if the afs daemon hasn't started yet
 
4578
 * \retval EINVAL       Error if some of the standard args aren't set
 
4579
 *
 
4580
 * \post
 
4581
 *      get all interface addresses and other information of the client
 
4582
 *      interface
 
4583
 */
 
4584
DECL_PIOCTL(PGetCPrefs)
 
4585
{
 
4586
    struct sprefrequest *spin;  /* input */
 
4587
    struct sprefinfo *spout;    /* output */
 
4588
    struct spref *srvout;       /* one output component */
 
4589
    int maxNumber;
 
4590
    int i, j;
 
4591
 
 
4592
    AFS_STATCNT(PGetCPrefs);
 
4593
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
4594
        return EIO;             /* Inappropriate ioctl for device */
 
4595
 
 
4596
    spin = afs_pd_inline(ain, sizeof(*spin));
 
4597
    if (spin == NULL)
 
4598
        return EINVAL;
 
4599
 
 
4600
    /* Output spout relies on writing past the end of arrays. It's horrible,
 
4601
     * but I'm not quite brave enough to tackle it yet */
 
4602
    spout = (struct sprefinfo *)aout->ptr;
 
4603
 
 
4604
    maxNumber = spin->num_servers;      /* max addrs this time */
 
4605
    srvout = spout->servers;
 
4606
 
 
4607
    ObtainReadLock(&afs_xinterface);
 
4608
 
 
4609
    /* copy out the client interface information from the
 
4610
     * kernel data structure "interface" to the output buffer
 
4611
     */
 
4612
    for (i = spin->offset, j = 0; (i < afs_cb_interface.numberOfInterfaces)
 
4613
         && (j < maxNumber); i++, j++, srvout++)
 
4614
        srvout->host.s_addr = afs_cb_interface.addr_in[i];
 
4615
 
 
4616
    spout->num_servers = j;
 
4617
    aout->ptr += sizeof(struct sprefinfo) + (j - 1) * sizeof(struct spref);
 
4618
 
 
4619
    if (i >= afs_cb_interface.numberOfInterfaces)
 
4620
        spout->next_offset = 0; /* start from beginning again */
 
4621
    else
 
4622
        spout->next_offset = spin->offset + j;
 
4623
 
 
4624
    ReleaseReadLock(&afs_xinterface);
 
4625
    return 0;
 
4626
}
 
4627
 
 
4628
/*!
 
4629
 * VIOC_SETCPREFS (51) - Set client interface
 
4630
 *
 
4631
 * \ingroup pioctl
 
4632
 *
 
4633
 * \param[in] ain       the interfaces you want set
 
4634
 * \param[out] aout     not in use
 
4635
 *
 
4636
 * \retval EIO          Error if the afs daemon hasn't started yet
 
4637
 * \retval EINVAL       Error if the input is too large for the struct
 
4638
 * \retval ENOMEM       Error if there are too many servers
 
4639
 *
 
4640
 * \post set the callbak interfaces addresses to those of the hosts
 
4641
 */
 
4642
DECL_PIOCTL(PSetCPrefs)
 
4643
{
 
4644
    char *ainPtr;
 
4645
    size_t ainSize;
 
4646
    struct setspref *sin;
 
4647
    int i;
 
4648
 
 
4649
    AFS_STATCNT(PSetCPrefs);
 
4650
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
4651
        return EIO;             /* Inappropriate ioctl for device */
 
4652
 
 
4653
    /* Yuck. Input to this function relies on reading past the end of
 
4654
     * structures. Bodge it for now.
 
4655
     */
 
4656
    ainPtr = ain->ptr;
 
4657
    ainSize = ain->remaining;
 
4658
 
 
4659
    sin = (struct setspref *)ainPtr;
 
4660
 
 
4661
    if (ainSize < sizeof(struct setspref))
 
4662
        return EINVAL;
 
4663
#if 0                           /* num_servers is unsigned */
 
4664
    if (sin->num_servers < 0)
 
4665
        return EINVAL;
 
4666
#endif
 
4667
    if (sin->num_servers > AFS_MAX_INTERFACE_ADDR)
 
4668
        return ENOMEM;
 
4669
 
 
4670
    ObtainWriteLock(&afs_xinterface, 412);
 
4671
    afs_cb_interface.numberOfInterfaces = sin->num_servers;
 
4672
    for (i = 0; (unsigned short)i < sin->num_servers; i++)
 
4673
        afs_cb_interface.addr_in[i] = sin->servers[i].host.s_addr;
 
4674
 
 
4675
    ReleaseWriteLock(&afs_xinterface);
 
4676
    return 0;
 
4677
}
 
4678
 
 
4679
/*!
 
4680
 * VIOC_AFS_FLUSHMOUNT (52) - Flush mount symlink data
 
4681
 *
 
4682
 * \ingroup pioctl
 
4683
 *
 
4684
 * \param[in] ain
 
4685
 *      the last part of a path to a mount point, which tells us what to flush
 
4686
 * \param[out] aout
 
4687
 *      not in use
 
4688
 *
 
4689
 * \retval EINVAL
 
4690
 *      Error if some of the initial arguments aren't set
 
4691
 * \retval ENOTDIR
 
4692
 *      Error if the initial argument for the mount point isn't a directory
 
4693
 * \retval ENOENT
 
4694
 *      Error if the dcache entry isn't set
 
4695
 *
 
4696
 * \post
 
4697
 *      remove all of the mount data from the dcache regarding a
 
4698
 *      certain mount point
 
4699
 */
 
4700
DECL_PIOCTL(PFlushMount)
 
4701
{
 
4702
    afs_int32 code;
 
4703
    struct vcache *tvc;
 
4704
    struct dcache *tdc;
 
4705
    struct VenusFid tfid;
 
4706
    char *bufp;
 
4707
    char *mount;
 
4708
    struct sysname_info sysState;
 
4709
    afs_size_t offset, len;
 
4710
 
 
4711
    AFS_STATCNT(PFlushMount);
 
4712
    if (!avc)
 
4713
        return EINVAL;
 
4714
 
 
4715
    if (afs_pd_getStringPtr(ain, &mount) != 0)
 
4716
        return EINVAL;
 
4717
 
 
4718
    code = afs_VerifyVCache(avc, areq);
 
4719
    if (code)
 
4720
        return code;
 
4721
    if (vType(avc) != VDIR) {
 
4722
        return ENOTDIR;
 
4723
    }
 
4724
    tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 1);
 
4725
    if (!tdc)
 
4726
        return ENOENT;
 
4727
    Check_AtSys(avc, mount, &sysState, areq);
 
4728
    ObtainReadLock(&tdc->lock);
 
4729
    do {
 
4730
        code = afs_dir_Lookup(tdc, sysState.name, &tfid.Fid);
 
4731
    } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
 
4732
    ReleaseReadLock(&tdc->lock);
 
4733
    afs_PutDCache(tdc);         /* we're done with the data */
 
4734
    bufp = sysState.name;
 
4735
    if (code) {
 
4736
        goto out;
 
4737
    }
 
4738
    tfid.Cell = avc->f.fid.Cell;
 
4739
    tfid.Fid.Volume = avc->f.fid.Fid.Volume;
 
4740
    if (!tfid.Fid.Unique && (avc->f.states & CForeign)) {
 
4741
        tvc = afs_LookupVCache(&tfid, areq, NULL, avc, bufp);
 
4742
    } else {
 
4743
        tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
 
4744
    }
 
4745
    if (!tvc) {
 
4746
        code = ENOENT;
 
4747
        goto out;
 
4748
    }
 
4749
    if (tvc->mvstat != 1) {
 
4750
        afs_PutVCache(tvc);
 
4751
        code = EINVAL;
 
4752
        goto out;
 
4753
    }
 
4754
#ifdef AFS_BOZONLOCK_ENV
 
4755
    afs_BozonLock(&tvc->pvnLock, tvc);  /* Since afs_TryToSmush will do a pvn_vptrunc */
 
4756
#endif
 
4757
    ObtainWriteLock(&tvc->lock, 649);
 
4758
    ObtainWriteLock(&afs_xcbhash, 650);
 
4759
    afs_DequeueCallback(tvc);
 
4760
    tvc->f.states &= ~(CStatd | CDirty); /* next reference will re-stat cache entry */
 
4761
    ReleaseWriteLock(&afs_xcbhash);
 
4762
    /* now find the disk cache entries */
 
4763
    afs_TryToSmush(tvc, *acred, 1);
 
4764
    osi_dnlc_purgedp(tvc);
 
4765
    if (tvc->linkData && !(tvc->f.states & CCore)) {
 
4766
        afs_osi_Free(tvc->linkData, strlen(tvc->linkData) + 1);
 
4767
        tvc->linkData = NULL;
 
4768
    }
 
4769
    ReleaseWriteLock(&tvc->lock);
 
4770
#ifdef AFS_BOZONLOCK_ENV
 
4771
    afs_BozonUnlock(&tvc->pvnLock, tvc);
 
4772
#endif
 
4773
    afs_PutVCache(tvc);
 
4774
  out:
 
4775
    if (sysState.allocked)
 
4776
        osi_FreeLargeSpace(bufp);
 
4777
    return code;
 
4778
}
 
4779
 
 
4780
/*!
 
4781
 * VIOC_RXSTAT_PROC (53) - Control process RX statistics
 
4782
 *
 
4783
 * \ingroup pioctl
 
4784
 *
 
4785
 * \param[in] ain       the flags that control which stats to use
 
4786
 * \param[out] aout     not in use
 
4787
 *
 
4788
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
4789
 * \retval EINVAL       Error if the flag input is too long
 
4790
 *
 
4791
 * \post
 
4792
 *      either enable process RPCStats, disable process RPCStats,
 
4793
 *      or clear the process RPCStats
 
4794
 */
 
4795
DECL_PIOCTL(PRxStatProc)
 
4796
{
 
4797
    afs_int32 flags;
 
4798
 
 
4799
    if (!afs_osi_suser(*acred))
 
4800
        return EACCES;
 
4801
 
 
4802
    if (afs_pd_getInt(ain, &flags) != 0)
 
4803
        return EINVAL;
 
4804
 
 
4805
    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
 
4806
        return EINVAL;
 
4807
 
 
4808
    if (flags & AFSCALL_RXSTATS_ENABLE) {
 
4809
        rx_enableProcessRPCStats();
 
4810
    }
 
4811
    if (flags & AFSCALL_RXSTATS_DISABLE) {
 
4812
        rx_disableProcessRPCStats();
 
4813
    }
 
4814
    if (flags & AFSCALL_RXSTATS_CLEAR) {
 
4815
        rx_clearProcessRPCStats(AFS_RX_STATS_CLEAR_ALL);
 
4816
    }
 
4817
    return 0;
 
4818
}
 
4819
 
 
4820
 
 
4821
/*!
 
4822
 * VIOC_RXSTAT_PEER (54) - Control peer RX statistics
 
4823
 *
 
4824
 * \ingroup pioctl
 
4825
 *
 
4826
 * \param[in] ain       the flags that control which statistics to use
 
4827
 * \param[out] aout     not in use
 
4828
 *
 
4829
 * \retval EACCES       Error if the user doesn't have super-user credentials
 
4830
 * \retval EINVAL       Error if the flag input is too long
 
4831
 *
 
4832
 * \post
 
4833
 *      either enable peer RPCStatws, disable peer RPCStats,
 
4834
 *      or clear the peer RPCStats
 
4835
 */
 
4836
DECL_PIOCTL(PRxStatPeer)
 
4837
{
 
4838
    afs_int32 flags;
 
4839
 
 
4840
    if (!afs_osi_suser(*acred))
 
4841
        return EACCES;
 
4842
 
 
4843
    if (afs_pd_getInt(ain, &flags) != 0)
 
4844
        return EINVAL;
 
4845
 
 
4846
    if (!(flags & AFSCALL_RXSTATS_MASK) || (flags & ~AFSCALL_RXSTATS_MASK))
 
4847
        return EINVAL;
 
4848
 
 
4849
    if (flags & AFSCALL_RXSTATS_ENABLE) {
 
4850
        rx_enablePeerRPCStats();
 
4851
    }
 
4852
    if (flags & AFSCALL_RXSTATS_DISABLE) {
 
4853
        rx_disablePeerRPCStats();
 
4854
    }
 
4855
    if (flags & AFSCALL_RXSTATS_CLEAR) {
 
4856
        rx_clearPeerRPCStats(AFS_RX_STATS_CLEAR_ALL);
 
4857
    }
 
4858
    return 0;
 
4859
}
 
4860
 
 
4861
DECL_PIOCTL(PPrefetchFromTape)
 
4862
{
 
4863
    afs_int32 code;
 
4864
    afs_int32 outval;
 
4865
    struct afs_conn *tc;
 
4866
    struct rx_call *tcall;
 
4867
    struct AFSVolSync tsync;
 
4868
    struct AFSFetchStatus OutStatus;
 
4869
    struct AFSCallBack CallBack;
 
4870
    struct VenusFid tfid;
 
4871
    struct AFSFid *Fid;
 
4872
    struct vcache *tvc;
 
4873
    struct rx_connection *rxconn;
 
4874
 
 
4875
    AFS_STATCNT(PSetAcl);
 
4876
    if (!avc)
 
4877
        return EINVAL;
 
4878
 
 
4879
    Fid = afs_pd_inline(ain, sizeof(struct AFSFid));
 
4880
    if (Fid == NULL)
 
4881
        Fid = &avc->f.fid.Fid;
 
4882
 
 
4883
    tfid.Cell = avc->f.fid.Cell;
 
4884
    tfid.Fid.Volume = Fid->Volume;
 
4885
    tfid.Fid.Vnode = Fid->Vnode;
 
4886
    tfid.Fid.Unique = Fid->Unique;
 
4887
 
 
4888
    tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
 
4889
    if (!tvc) {
 
4890
        afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
 
4891
                   ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &avc->f.fid);
 
4892
        return ENOENT;
 
4893
    }
 
4894
    afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD, ICL_TYPE_POINTER, tvc,
 
4895
               ICL_TYPE_FID, &tfid, ICL_TYPE_FID, &tvc->f.fid);
 
4896
 
 
4897
    do {
 
4898
        tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
 
4899
        if (tc) {
 
4900
 
 
4901
            RX_AFS_GUNLOCK();
 
4902
            tcall = rx_NewCall(rxconn);
 
4903
            code =
 
4904
                StartRXAFS_FetchData(tcall, (struct AFSFid *)&tvc->f.fid.Fid, 0,
 
4905
                                     0);
 
4906
            if (!code) {
 
4907
                rx_Read(tcall, (char *)&outval, sizeof(afs_int32));
 
4908
                code =
 
4909
                    EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
 
4910
            }
 
4911
            code = rx_EndCall(tcall, code);
 
4912
            RX_AFS_GLOCK();
 
4913
        } else
 
4914
            code = -1;
 
4915
    } while (afs_Analyze
 
4916
             (tc, rxconn, code, &tvc->f.fid, areq, AFS_STATS_FS_RPCIDX_RESIDENCYRPCS,
 
4917
              SHARED_LOCK, NULL));
 
4918
    /* This call is done only to have the callback things handled correctly */
 
4919
    afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
 
4920
    afs_PutVCache(tvc);
 
4921
 
 
4922
    if (code)
 
4923
        return code;
 
4924
 
 
4925
    return afs_pd_putInt(aout, outval);
 
4926
}
 
4927
 
 
4928
DECL_PIOCTL(PFsCmd)
 
4929
{
 
4930
    afs_int32 code;
 
4931
    struct afs_conn *tc;
 
4932
    struct vcache *tvc;
 
4933
    struct FsCmdInputs *Inputs;
 
4934
    struct FsCmdOutputs *Outputs;
 
4935
    struct VenusFid tfid;
 
4936
    struct AFSFid *Fid;
 
4937
    struct rx_connection *rxconn;
 
4938
 
 
4939
    if (!avc)
 
4940
        return EINVAL;
 
4941
 
 
4942
    Inputs = afs_pd_inline(ain, sizeof(*Inputs));
 
4943
    if (Inputs == NULL)
 
4944
        return EINVAL;
 
4945
 
 
4946
    Outputs = afs_pd_inline(aout, sizeof(*Outputs));
 
4947
    if (Outputs == NULL)
 
4948
        return E2BIG;
 
4949
 
 
4950
    Fid = &Inputs->fid;
 
4951
    if (!Fid->Volume)
 
4952
        Fid = &avc->f.fid.Fid;
 
4953
 
 
4954
    tfid.Cell = avc->f.fid.Cell;
 
4955
    tfid.Fid.Volume = Fid->Volume;
 
4956
    tfid.Fid.Vnode = Fid->Vnode;
 
4957
    tfid.Fid.Unique = Fid->Unique;
 
4958
 
 
4959
    tvc = afs_GetVCache(&tfid, areq, NULL, NULL);
 
4960
    afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD, ICL_TYPE_POINTER, tvc,
 
4961
               ICL_TYPE_INT32, Inputs->command, ICL_TYPE_FID, &tfid);
 
4962
    if (!tvc)
 
4963
        return ENOENT;
 
4964
 
 
4965
    if (Inputs->command) {
 
4966
        do {
 
4967
            tc = afs_Conn(&tvc->f.fid, areq, SHARED_LOCK, &rxconn);
 
4968
            if (tc) {
 
4969
                RX_AFS_GUNLOCK();
 
4970
                code =
 
4971
                    RXAFS_FsCmd(rxconn, Fid, Inputs,
 
4972
                                        (struct FsCmdOutputs *)aout);
 
4973
                RX_AFS_GLOCK();
 
4974
            } else
 
4975
                code = -1;
 
4976
        } while (afs_Analyze
 
4977
                 (tc, rxconn, code, &tvc->f.fid, areq,
 
4978
                  AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, NULL));
 
4979
        /* This call is done to have the callback things handled correctly */
 
4980
        afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
 
4981
    } else {            /* just a status request, return also link data */
 
4982
        code = 0;
 
4983
        Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
 
4984
        Outputs->chars[0] = 0;
 
4985
        if (vType(tvc) == VLNK) {
 
4986
            ObtainWriteLock(&tvc->lock, 555);
 
4987
            if (afs_HandleLink(tvc, areq) == 0)
 
4988
                strncpy((char *)&Outputs->chars, tvc->linkData, MAXCMDCHARS);
 
4989
            ReleaseWriteLock(&tvc->lock);
 
4990
        }
 
4991
    }
 
4992
 
 
4993
    afs_PutVCache(tvc);
 
4994
 
 
4995
    return code;
 
4996
}
 
4997
 
 
4998
DECL_PIOCTL(PNewUuid)
 
4999
{
 
5000
    /*AFS_STATCNT(PNewUuid); */
 
5001
    if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
 
5002
        return EIO;             /* Inappropriate ioctl for device */
 
5003
 
 
5004
    if (!afs_osi_suser(*acred))
 
5005
        return EACCES;
 
5006
 
 
5007
    ObtainWriteLock(&afs_xinterface, 555);
 
5008
    afs_uuid_create(&afs_cb_interface.uuid);
 
5009
    ReleaseWriteLock(&afs_xinterface);
 
5010
    ForceAllNewConnections();
 
5011
    return 0;
 
5012
}
 
5013
 
 
5014
#if defined(AFS_CACHE_BYPASS) && defined(AFS_LINUX24_ENV)
 
5015
 
 
5016
DECL_PIOCTL(PSetCachingThreshold)
 
5017
{
 
5018
    afs_int32 getting = 1;
 
5019
    afs_int32 setting = 1;
 
5020
    afs_int32 threshold = AFS_CACHE_BYPASS_DISABLED;
 
5021
 
 
5022
    if (afs_pd_getInt(ain, &threshold) != 0)
 
5023
        setting = 0;
 
5024
 
 
5025
    if (aout == NULL)
 
5026
        getting = 0;
 
5027
 
 
5028
    if (setting == 0 && getting == 0)
 
5029
        return EINVAL;
 
5030
 
 
5031
    /*
 
5032
     * If setting, set first, and return the value now in effect
 
5033
     */
 
5034
    if (setting) {
 
5035
        if (!afs_osi_suser(*acred))
 
5036
            return EPERM;
 
5037
        cache_bypass_threshold = threshold;
 
5038
        afs_warn("Cache Bypass Threshold set to: %d\n", threshold);
 
5039
        /* TODO:  move to separate pioctl, or enhance pioctl */
 
5040
        cache_bypass_strategy = LARGE_FILES_BYPASS_CACHE;
 
5041
    }
 
5042
 
 
5043
    /* Return the current size threshold */
 
5044
    if (getting)
 
5045
        return afs_pd_putInt(aout, cache_bypass_threshold);
 
5046
 
 
5047
    return(0);
 
5048
}
 
5049
 
 
5050
#endif /* defined(AFS_CACHE_BYPASS) */
 
5051
 
 
5052
DECL_PIOCTL(PCallBackAddr)
 
5053
{
 
5054
#ifndef UKERNEL
 
5055
    afs_uint32 addr, code;
 
5056
    int srvAddrCount;
 
5057
    struct server *ts;
 
5058
    struct srvAddr *sa;
 
5059
    struct afs_conn *tc;
 
5060
    afs_int32 i, j;
 
5061
    struct unixuser *tu;
 
5062
    struct srvAddr **addrs;
 
5063
    struct rx_connection *rxconn;
 
5064
 
 
5065
    /*AFS_STATCNT(PCallBackAddr); */
 
5066
    if (!afs_resourceinit_flag) /* afs deamons havn't started yet */
 
5067
        return EIO;             /* Inappropriate ioctl for device */
 
5068
 
 
5069
    if (!afs_osi_suser(acred))
 
5070
        return EACCES;
 
5071
 
 
5072
    if (afs_pd_getInt(ain, &addr) != 0)
 
5073
        return EINVAL;
 
5074
 
 
5075
    ObtainReadLock(&afs_xinterface);
 
5076
    for (i = 0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
 
5077
        if (afs_cb_interface.addr_in[i] == addr)
 
5078
            break;
 
5079
    }
 
5080
 
 
5081
    ReleaseWriteLock(&afs_xinterface);
 
5082
 
 
5083
    if (afs_cb_interface.addr_in[i] != addr)
 
5084
        return EINVAL;
 
5085
 
 
5086
    ObtainReadLock(&afs_xserver);       /* Necessary? */
 
5087
    ObtainReadLock(&afs_xsrvAddr);
 
5088
 
 
5089
    srvAddrCount = 0;
 
5090
    for (i = 0; i < NSERVERS; i++) {
 
5091
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
 
5092
            srvAddrCount++;
 
5093
        }
 
5094
    }
 
5095
 
 
5096
    addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
 
5097
    osi_Assert(addrs != NULL);
 
5098
    j = 0;
 
5099
    for (i = 0; i < NSERVERS; i++) {
 
5100
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
 
5101
            if (j >= srvAddrCount)
 
5102
                break;
 
5103
            addrs[j++] = sa;
 
5104
        }
 
5105
    }
 
5106
 
 
5107
    ReleaseReadLock(&afs_xsrvAddr);
 
5108
    ReleaseReadLock(&afs_xserver);
 
5109
 
 
5110
    for (i = 0; i < j; i++) {
 
5111
        sa = addrs[i];
 
5112
        ts = sa->server;
 
5113
        if (!ts)
 
5114
            continue;
 
5115
 
 
5116
        /* vlserver has no callback conn */
 
5117
        if (sa->sa_portal == AFS_VLPORT) {
 
5118
            continue;
 
5119
        }
 
5120
 
 
5121
        if (!ts->cell)          /* not really an active server, anyway, it must */
 
5122
            continue;           /* have just been added by setsprefs */
 
5123
 
 
5124
        /* get a connection, even if host is down; bumps conn ref count */
 
5125
        tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
 
5126
        tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
 
5127
                          1 /*force */ , 1 /*create */ , SHARED_LOCK, 0, &rxconn);
 
5128
        afs_PutUser(tu, SHARED_LOCK);
 
5129
        if (!tc)
 
5130
            continue;
 
5131
 
 
5132
        if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
 
5133
            if (sa->sa_flags & SRVADDR_ISDOWN) {
 
5134
                rx_SetConnDeadTime(rxconn, 3);
 
5135
            }
 
5136
#ifdef RX_ENABLE_LOCKS
 
5137
            AFS_GUNLOCK();
 
5138
#endif /* RX_ENABLE_LOCKS */
 
5139
            code = RXAFS_CallBackRxConnAddr(rxconn, &addr);
 
5140
#ifdef RX_ENABLE_LOCKS
 
5141
            AFS_GLOCK();
 
5142
#endif /* RX_ENABLE_LOCKS */
 
5143
        }
 
5144
        afs_PutConn(tc, rxconn, SHARED_LOCK);   /* done with it now */
 
5145
    }                           /* Outer loop over addrs */
 
5146
#endif /* UKERNEL */
 
5147
    return 0;
 
5148
}
 
5149
 
 
5150
DECL_PIOCTL(PDiscon)
 
5151
{
 
5152
    static afs_int32 mode = 1; /* Start up in 'off' */
 
5153
    afs_int32 force = 0;
 
5154
    int code = 0;
 
5155
    char flags[4];
 
5156
    struct vrequest lreq;
 
5157
 
 
5158
    if (afs_pd_getBytes(ain, &flags, 4) == 0) {
 
5159
        if (!afs_osi_suser(*acred))
 
5160
            return EPERM;
 
5161
 
 
5162
        if (flags[0])
 
5163
            mode = flags[0] - 1;
 
5164
        if (flags[1])
 
5165
            afs_ConflictPolicy = flags[1] - 1;
 
5166
        if (flags[2])
 
5167
            force = 1;
 
5168
        if (flags[3]) {
 
5169
            /* Fake InitReq support for UID override */
 
5170
            memset(&lreq, 0, sizeof(lreq));
 
5171
            lreq.uid = flags[3];
 
5172
            areq = &lreq; /* override areq we got */
 
5173
        }
 
5174
 
 
5175
        /*
 
5176
         * All of these numbers are hard coded in fs.c. If they
 
5177
         * change here, they should change there and vice versa
 
5178
         */
 
5179
        switch (mode) {
 
5180
        case 0: /* Disconnect ("offline" mode), breaking all callbacks */
 
5181
            if (!AFS_IS_DISCONNECTED) {
 
5182
                ObtainWriteLock(&afs_discon_lock, 999);
 
5183
                afs_DisconGiveUpCallbacks();
 
5184
                afs_RemoveAllConns();
 
5185
                afs_is_disconnected = 1;
 
5186
                afs_is_discon_rw = 1;
 
5187
                ReleaseWriteLock(&afs_discon_lock);
 
5188
            }
 
5189
            break;
 
5190
        case 1: /* Fully connected, ("online" mode). */
 
5191
            ObtainWriteLock(&afs_discon_lock, 998);
 
5192
 
 
5193
            afs_in_sync = 1;
 
5194
            afs_MarkAllServersUp();
 
5195
            code = afs_ResyncDisconFiles(areq, *acred);
 
5196
            afs_in_sync = 0;
 
5197
 
 
5198
            if (code && !force) {
 
5199
                afs_warnuser("Files not synchronized properly, still in discon state. \n"
 
5200
                       "Please retry or use \"force\".\n");
 
5201
                mode = 0;
 
5202
            } else {
 
5203
                if (force) {
 
5204
                    afs_DisconDiscardAll(*acred);
 
5205
                }
 
5206
                afs_ClearAllStatdFlag();
 
5207
                afs_is_disconnected = 0;
 
5208
                afs_is_discon_rw = 0;
 
5209
                afs_warnuser("\nSync succeeded. You are back online.\n");
 
5210
            }
 
5211
 
 
5212
            ReleaseWriteLock(&afs_discon_lock);
 
5213
            break;
 
5214
        default:
 
5215
            return EINVAL;
 
5216
        }
 
5217
    } else {
 
5218
        return EINVAL;
 
5219
    }
 
5220
 
 
5221
    if (code)
 
5222
        return code;
 
5223
 
 
5224
    return afs_pd_putInt(aout, mode);
 
5225
}
 
5226
 
 
5227
DECL_PIOCTL(PNFSNukeCreds)
 
5228
{
 
5229
    afs_uint32 addr;
 
5230
    afs_int32 i;
 
5231
    struct unixuser *tu;
 
5232
 
 
5233
    AFS_STATCNT(PUnlog);
 
5234
    if (!afs_resourceinit_flag) /* afs daemons haven't started yet */
 
5235
        return EIO;             /* Inappropriate ioctl for device */
 
5236
 
 
5237
    if (afs_pd_getUint(ain, &addr) != 0)
 
5238
        return EINVAL;
 
5239
 
 
5240
    if (afs_cr_gid(*acred) == RMTUSER_REQ_PRIV && !addr) {
 
5241
        tu = afs_GetUser(areq->uid, -1, SHARED_LOCK);
 
5242
        if (!tu->exporter || !(addr = EXP_GETHOST(tu->exporter))) {
 
5243
            afs_PutUser(tu, SHARED_LOCK);
 
5244
            return EACCES;
 
5245
        }
 
5246
        afs_PutUser(tu, SHARED_LOCK);
 
5247
    } else if (!afs_osi_suser(acred)) {
 
5248
        return EACCES;
 
5249
    }
 
5250
 
 
5251
    ObtainWriteLock(&afs_xuser, 227);
 
5252
    for (i = 0; i < NUSERS; i++) {
 
5253
        for (tu = afs_users[i]; tu; tu = tu->next) {
 
5254
            if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
 
5255
                tu->vid = UNDEFVID;
 
5256
                tu->states &= ~UHasTokens;
 
5257
                /* security is not having to say you're sorry */
 
5258
                memset(&tu->ct, 0, sizeof(struct ClearToken));
 
5259
                tu->refCount++;
 
5260
                ReleaseWriteLock(&afs_xuser);
 
5261
                afs_ResetUserConns(tu);
 
5262
                tu->refCount--;
 
5263
                ObtainWriteLock(&afs_xuser, 228);
 
5264
#ifdef UKERNEL
 
5265
                /* set the expire times to 0, causes
 
5266
                 * afs_GCUserData to remove this entry
 
5267
                 */
 
5268
                tu->ct.EndTimestamp = 0;
 
5269
                tu->tokenTime = 0;
 
5270
#endif /* UKERNEL */
 
5271
            }
 
5272
        }
 
5273
    }
 
5274
    ReleaseWriteLock(&afs_xuser);
 
5275
    return 0;
 
5276
}