VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/SharedFolders/vboxvfs_vfsops.c@ 10140

Last change on this file since 10140 was 10140, checked in by vboxsync, 17 years ago

Solaris vboxvfs stuff.

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Id
File size: 18.7 KB
Line 
1/* $Id: vboxvfs_vfsops.c 10140 2008-07-03 08:45:37Z vboxsync $ */
2/** @file
3 * VirtualBox File System Driver for Solaris Guests. VFS operations.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include <sys/types.h>
18#include <sys/mntent.h>
19#include <sys/param.h>
20#include <sys/modctl.h>
21#include <sys/mount.h>
22#include <sys/policy.h>
23#include <sys/ddi.h>
24#include <sys/sunddi.h>
25#include "vboxvfs.h"
26
27#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
28# define LOG_ENABLED
29# define LOG_TO_BACKDOOR
30#endif
31#include <VBox/log.h>
32#include <iprt/string.h>
33#include <iprt/mem.h>
34#include <iprt/err.h>
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** Mount Options */
41#define MNTOPT_VBOXVFS_UID "uid"
42#define MNTOPT_VBOXVFS_GID "gid"
43
44
45/*******************************************************************************
46* Internal Functions *
47*******************************************************************************/
48static int VBoxVFS_Init(int fType, char *pszName);
49static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred);
50static int VBoxVFS_Unmount(vfs_t *pVFS, int fFlags, cred_t *pCred);
51static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode);
52static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat);
53static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid);
54static void VBoxVFS_FreeVFS(vfs_t *pVFS);
55
56static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred);
57static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue);
58
59
60/*******************************************************************************
61* Structures and Typedefs *
62*******************************************************************************/
63/**
64 * mntopts_t: mount options table array
65 */
66static mntopt_t g_VBoxVFSMountOptions[] =
67{
68 /* Option Name Cancel Opt. Default Arg Flags Data */
69 { MNTOPT_VBOXVFS_UID, NULL, NULL, MO_HASVALUE, NULL },
70 { MNTOPT_VBOXVFS_GID, NULL, NULL, MO_HASVALUE, NULL }
71};
72
73/**
74 * mntopts_t: mount options table prototype
75 */
76static mntopts_t g_VBoxVFSMountTableProt =
77{
78 sizeof(g_VBoxVFSMountOptions) / sizeof(mntopt_t),
79 g_VBoxVFSMountOptions
80};
81
82/**
83 * vfsdef_t: driver specific mount options
84 */
85static vfsdef_t g_VBoxVFSDef =
86{
87 VFSDEF_VERSION,
88 DEVICE_NAME,
89 VBoxVFS_Init,
90 VSW_HASPROTO,
91 &g_VBoxVFSMountTableProt
92};
93
94/**
95 * modlfs: loadable file system
96 */
97static struct modlfs g_VBoxVFSLoadMod =
98{
99 &mod_fsops, /* extern from kernel */
100 DEVICE_DESC,
101 &g_VBoxVFSDef
102};
103
104/**
105 * modlinkage: export install/remove/info to the kernel
106 */
107static struct modlinkage g_VBoxVFSModLinkage =
108{
109 MODREV_1, /* loadable module system revision */
110 &g_VBoxVFSLoadMod,
111 NULL /* terminate array of linkage structures */
112};
113
114
115/*******************************************************************************
116* Global Variables *
117*******************************************************************************/
118/** Opaque pointer to list of states. */
119static void *g_pVBoxVFSState;
120/** GCC C++ hack. */
121unsigned __gxx_personality_v0 = 0xdecea5ed;
122/** Global connection to the client. */
123VBSFCLIENT g_VBoxVFSClient;
124/** Global VFS Operations pointer. */
125vfsops_t *g_pVBoxVFS_vfsops;
126/** The file system type identifier. */
127static int g_VBoxVFSType;
128
129
130/**
131 * Kernel entry points
132 */
133int _init(void)
134{
135 LogFlow((DEVICE_NAME ":_init\n"));
136
137 return mod_install(&g_VBoxVFSModLinkage);;
138}
139
140
141int _fini(void)
142{
143 LogFlow((DEVICE_NAME ":_fini\n"));
144
145 int rc = mod_remove(&g_VBoxVFSModLinkage);
146 if (rc)
147 return rc;
148
149 /* Blow away the operation vectors*/
150 vfs_freevfsops_by_type(g_VBoxVFSType);
151 vn_freevnodeops(g_pVBoxVFS_vnodeops);
152}
153
154
155int _info(struct modinfo *pModInfo)
156{
157 LogFlow((DEVICE_NAME ":_info\n"));
158
159 return mod_info(&g_VBoxVFSModLinkage, pModInfo);
160}
161
162
163static int VBoxVFS_Init(int fType, char *pszName)
164{
165 int rc;
166
167 LogFlow((DEVICE_NAME ":VBoxVFS_Init\n"));
168
169 g_VBoxVFSType = fType;
170
171 /* Initialize the R0 guest library. */
172 rc = vboxInit();
173 if (VBOX_SUCCESS(rc))
174 {
175 /* Connect to the host service. */
176 rc = vboxConnect(&g_VBoxVFSClient);
177 if (VBOX_SUCCESS(rc))
178 {
179 /* Use UTF-8 encoding. */
180 rc = vboxCallSetUtf8 (&g_VBoxVFSClient);
181 if (VBOX_SUCCESS(rc))
182 {
183 /* Fill up VFS user entry points. */
184 static const fs_operation_def_t s_VBoxVFS_vfsops_template[] =
185 {
186 VFSNAME_MOUNT, { .vfs_mount = VBoxVFS_Mount },
187 VFSNAME_UNMOUNT, { .vfs_unmount = VBoxVFS_Unmount },
188 VFSNAME_ROOT, { .vfs_root = VBoxVFS_Root },
189 VFSNAME_STATVFS, { .vfs_statvfs = VBoxVFS_Statfs },
190 VFSNAME_VGET, { .vfs_vget = VBoxVFS_VGet },
191 VFSNAME_FREEVFS, { .vfs_freevfs = VBoxVFS_FreeVFS },
192 NULL, NULL
193 };
194
195 rc = vfs_setfsops(fType, s_VBoxVFS_vfsops_template, &g_pVBoxVFS_vfsops);
196 if (!rc)
197 {
198 /* Set VNode operations. */
199 rc = vn_make_ops(pszName, g_VBoxVFS_vnodeops_template, &g_pVBoxVFS_vnodeops);
200 if (!rc)
201 {
202 LogFlow((DEVICE_NAME ":Successfully loaded vboxvfs.\n"));
203 return 0;
204 }
205 else
206 LogRel((DEVICE_NAME ":vn_make_ops failed. rc=%d\n", rc));
207 }
208 else
209 LogRel((DEVICE_NAME ":vfs_setfsops failed. rc=%d\n", rc));
210 }
211 else
212 {
213 LogRel((DEVICE_NAME ":vboxCallSetUtf8 failed. rc=%d\n", rc));
214 rc = EPROTO;
215 }
216 vboxDisconnect(&g_VBoxVFSClient);
217 }
218 else
219 {
220 LogRel((DEVICE_NAME ":Failed to connect to host! rc=%d\n", rc));
221 rc = ENXIO;
222 }
223 vboxUninit();
224 }
225 else
226 {
227 LogRel((DEVICE_NAME ":Failed to initialize R0 lib. rc=%d\n", rc));
228 rc = ENXIO;
229 }
230 return rc;
231}
232
233static int VBoxVFS_Mount(vfs_t *pVFS, vnode_t *pVNode, struct mounta *pMount, cred_t *pCred)
234{
235 int rc = 0;
236 int Uid = 0;
237 int Gid = 0;
238 char *pszShare = NULL;
239 size_t cbShare = NULL;
240 pathname_t PathName;
241 vboxvfs_vnode_t *pVNodeRoot = NULL;
242 vnode_t *pVNodeSpec = NULL;
243 vnode_t *pVNodeDev = NULL;
244 dev_t Dev = 0;
245 SHFLSTRING *pShflShareName = NULL;
246 RTFSOBJINFO FSInfo;
247 size_t cbShflShareName = 0;
248 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = NULL;
249 int AddrSpace = (pMount->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE;
250
251 LogFlow((DEVICE_NAME ":VBoxVFS_Mount\n"));
252
253 /* Check user credentials for mounting in the specified target. */
254 rc = secpolicy_fs_mount(pCred, pVNode, pVFS);
255 if (rc)
256 {
257 LogRel((DEVICE_NAME ":VBoxVFS_Mount: secpolicy_fs_mount failed! invalid credentials.rc=%d\n", rc));
258 return EPERM;
259 }
260
261 /* We can mount to only directories. */
262 if (pVNode->v_type != VDIR)
263 return ENOTDIR;
264
265 /* We don't support remounting. */
266 if (pMount->flags & MS_REMOUNT)
267 return ENOTSUP;
268
269 mutex_enter(&pVNode->v_lock);
270 if ( !(pMount->flags & MS_REMOUNT)
271 && !(pMount->flags & MS_OVERLAY)
272 && (pVNode->v_count != -1 || (pVNode->v_flag & VROOT)))
273 {
274 LogRel((DEVICE_NAME ":VBoxVFS_Mount: device busy.\n"));
275 mutex_exit(&pVNode->v_lock);
276 return EBUSY;
277 }
278 mutex_exit(&pVNode->v_lock);
279
280 /* From what I understood the options are already parsed at a higher level */
281 if ( (pMount->flags & MS_DATA)
282 && pMount->datalen > 0)
283 {
284 LogRel((DEVICE_NAME ":VBoxVFS_Mount: unparsed options not supported.\n"));
285 return EINVAL;
286 }
287
288 /* Get UID argument (optional). */
289 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_UID, &Uid);
290 if (rc < 0)
291 {
292 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid uid value.\n"));
293 return EINVAL;
294 }
295
296 /* Get GID argument (optional). */
297 rc = vboxvfs_GetIntOpt(pVFS, MNTOPT_VBOXVFS_GID, &Gid);
298 if (rc < 0)
299 {
300 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid gid value.\n"));
301 return EINVAL;
302 }
303
304 /* Get special (sharename). */
305 rc = pn_get(pMount->spec, AddrSpace, &PathName);
306 if (!rc)
307 {
308 /* Get the vnode for the special file for storing the device identifier and path. */
309 rc = lookupname(PathName.pn_path, AddrSpace, FOLLOW, NULLVPP, &pVNodeSpec);
310 if (!rc)
311 {
312 /* Check if user has permission to use the special file for mounting. */
313 rc = vboxvfs_CheckMountPerm(pVFS, pMount, pVNodeSpec, pCred);
314 VN_RELE(pVNodeSpec);
315 if (!rc)
316 {
317 Dev = pVNodeSpec->v_rdev;
318 memcpy(pszShare, PathName.pn_path, strlen(PathName.pn_path));
319 cbShare = strlen(pszShare);
320 }
321 else
322 LogRel((DEVICE_NAME ":VBoxVFS_Mount: invalid permissions to mount %s.rc=%d\n", pszShare, rc));
323 rc = EPERM;
324 }
325 else
326 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to lookup sharename.rc=%d\n", rc));
327 rc = EINVAL;
328 }
329 else
330 {
331 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to get special file path.rc=%d\n", rc));
332 rc = EINVAL;
333 }
334 pn_free(&PathName);
335
336 if (!rc)
337 return rc;
338
339 /* Get VNode of the special file being mounted. */
340 pVNodeDev = makespecvp(Dev, VBLK);
341 if (!IS_SWAPVP(pVNodeDev))
342 {
343 /* Open the vnode for mounting. */
344 rc = VOP_OPEN(&pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, pCred, NULL);
345 if (rc)
346 {
347 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to mount.\n"));
348 rc = EINVAL;
349 }
350 }
351 else
352 {
353 LogRel((DEVICE_NAME ":VBoxVFS_Mount: cannot mount from swap.\n"));
354 rc = EINVAL;
355 }
356 if (!rc)
357 {
358 VN_RELE(pVNodeDev);
359 return rc;
360 }
361
362 /* Allocate the global info. structure. */
363 pVBoxVFSGlobalInfo = RTMemAlloc(sizeof(*pVBoxVFSGlobalInfo));
364 if (pVBoxVFSGlobalInfo)
365 {
366 cbShflShareName = offsetof(SHFLSTRING, String.utf8) + cbShare + 1;
367 pShflShareName = RTMemAllocZ(cbShflShareName);
368 if (pShflShareName)
369 {
370 pShflShareName->u16Length = cbShflShareName;
371 pShflShareName->u16Size = cbShflShareName + 1;
372 memcpy (pShflShareName->String.utf8, pszShare, cbShare + 1);
373
374 rc = vboxCallMapFolder(&g_VBoxVFSClient, pShflShareName, &pVBoxVFSGlobalInfo->Map);
375 RTMemFree(pShflShareName);
376 if (VBOX_SUCCESS(rc))
377 rc = 0;
378 else
379 {
380 LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxCallMapFolder failed rc=%d\n", rc));
381 rc = EPROTO;
382 }
383 }
384 else
385 {
386 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAllocZ failed to alloc %d bytes for ShFlShareName.\n", cbShflShareName));
387 rc = ENOMEM;
388 }
389 RTMemFree(pVBoxVFSGlobalInfo);
390 }
391 else
392 {
393 LogRel((DEVICE_NAME ":VBoxVFS_Mount: RTMemAlloc failed to alloc %d bytes for global struct.\n", sizeof(*pVBoxVFSGlobalInfo)));
394 rc = ENOMEM;
395 }
396
397 /* Undo work on failure. */
398 if (rc)
399 goto mntError1;
400
401 /* Initialize the per-filesystem mutex */
402 mutex_init(&pVBoxVFSGlobalInfo->MtxFS, "VBoxVFS_FSMtx", MUTEX_DEFAULT, NULL);
403
404 pVBoxVFSGlobalInfo->Uid = Uid;
405 pVBoxVFSGlobalInfo->Gid = Gid;
406 pVBoxVFSGlobalInfo->pVFS = pVFS;
407 pVBoxVFSGlobalInfo->pVNodeDev = pVNodeDev;
408 pVFS->vfs_data = pVBoxVFSGlobalInfo;
409 pVFS->vfs_fstype = g_VBoxVFSType;
410 pVFS->vfs_dev = Dev;
411 vfs_make_fsid(&pVFS->vfs_fsid, Dev, g_VBoxVFSType);
412
413 /* Allocate root vboxvfs_vnode_t object */
414 pVNodeRoot = RTMemAlloc(sizeof(*pVNodeRoot));
415 if (pVNodeRoot)
416 {
417 /* Initialize vnode protection mutex */
418 mutex_init(&pVNodeRoot->MtxContents, "VBoxVFS_VNodeMtx", MUTEX_DEFAULT, NULL);
419
420 pVBoxVFSGlobalInfo->pVNodeRoot = pVNodeRoot;
421
422 /* Allocate root path */
423 pVNodeRoot->pPath = RTMemAllocZ(sizeof(SHFLSTRING) + 1);
424 if (pVNodeRoot->pPath)
425 {
426 /* Initialize root path */
427 pVNodeRoot->pPath->u16Length = 1;
428 pVNodeRoot->pPath->u16Size = 2;
429 pVNodeRoot->pPath->String.utf8[0] = '/';
430 pVNodeRoot->pPath->String.utf8[1] = '\0';
431
432 /* Stat root node info from host */
433 rc = vboxvfs_Stat(__func__, pVBoxVFSGlobalInfo, pVNodeRoot->pPath, &FSInfo, B_FALSE);
434 if (!rc)
435 {
436 /* Initialize the root vboxvfs_node_t object */
437 vboxvfs_InitVNode(pVBoxVFSGlobalInfo, pVNodeRoot, &FSInfo);
438
439 /* Success! */
440 return 0;
441 }
442 else
443 LogRel((DEVICE_NAME ":VBoxVFS_Mount: vboxvfs_Stat failed rc(errno)=%d\n", rc));
444 RTMemFree(pVNodeRoot->pPath);
445 }
446 else
447 {
448 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to alloc memory for root node path.\n"));
449 rc = ENOMEM;
450 }
451 RTMemFree(pVNodeRoot);
452 }
453 else
454 {
455 LogRel((DEVICE_NAME ":VBoxVFS_Mount: failed to alloc memory for root node.\n"));
456 rc = ENOMEM;
457 }
458
459 /* Undo work in reverse. */
460mntError1:
461 /* Just release the mount location. */
462 VOP_CLOSE(pVNodeDev, (pVFS->vfs_flag & VFS_RDONLY) ? FREAD : FREAD | FWRITE, 1, (offset_t)0, pCred, NULL);
463 VN_RELE(pVNodeDev);
464 return rc;
465}
466
467static int VBoxVFS_Unmount(vfs_t *pVFS, int fUnmount, cred_t *pCred)
468{
469 int rc;
470 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
471
472 LogFlow((DEVICE_NAME ":VBoxVFS_Unmount.\n"));
473
474 /* Check if user can unmount. */
475 rc = secpolicy_fs_unmount(pCred, pVFS);
476 if (rc)
477 {
478 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: insufficient privileges to unmount.rc=%d\n", rc));
479 return EPERM;
480 }
481
482 /* @todo -XXX - Not sure of supporting force unmounts. What this means is that a failed force mount could bring down
483 * the entire system as hanging about vnode releases would no longer be valid after unloading ourselves...
484 */
485 if (fUnmount & MS_FORCE)
486 pVFS->vfs_flag |= VFS_UNMOUNTED;
487
488 /* @todo implement ref-counting of active vnodes & check for busy state here. */
489 /* @todo mutex protection needed here */
490 pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
491
492 rc = vboxCallUnmapFolder(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map);
493 if (VBOX_FAILURE(rc))
494 LogRel((DEVICE_NAME ":VBoxVFS_Unmount: failed to unmap shared folder. rc=%d\n", rc));
495
496 VN_RELE(VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot));
497
498 RTMemFree(pVBoxVFSGlobalInfo->pVNodeRoot->pPath);
499 RTMemFree(pVBoxVFSGlobalInfo->pVNodeRoot);
500 RTMemFree(pVBoxVFSGlobalInfo);
501 pVBoxVFSGlobalInfo = NULL;
502 pVFS->vfs_data = NULL;
503
504 return 0;
505}
506
507static int VBoxVFS_Root(vfs_t *pVFS, vnode_t **ppVNode)
508{
509 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
510 *ppVNode = VBOXVN_TO_VN(pVBoxVFSGlobalInfo->pVNodeRoot);
511 VN_HOLD(*ppVNode);
512
513 return 0;
514}
515
516static int VBoxVFS_Statfs(register vfs_t *pVFS, struct statvfs64 *pStat)
517{
518 SHFLVOLINFO VolumeInfo;
519 uint32_t cbBuffer;
520 vboxvfs_globinfo_t *pVBoxVFSGlobalInfo;
521 dev32_t Dev32;
522 int rc;
523
524 pVBoxVFSGlobalInfo = VFS_TO_VBOXVFS(pVFS);
525 cbBuffer = sizeof(VolumeInfo);
526 rc = vboxCallFSInfo(&g_VBoxVFSClient, &pVBoxVFSGlobalInfo->Map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbBuffer,
527 (PSHFLDIRINFO)&VolumeInfo);
528 if (VBOX_FAILURE(rc))
529 return RTErrConvertToErrno(rc);
530
531 bzero(pStat, sizeof(*pStat));
532 cmpldev(&Dev32, pVFS->vfs_dev);
533 pStat->f_fsid = Dev32;
534 pStat->f_flag = vf_to_stf(pVFS->vfs_flag);
535 pStat->f_bsize = VolumeInfo.ulBytesPerAllocationUnit;
536 pStat->f_frsize = VolumeInfo.ulBytesPerAllocationUnit;
537 pStat->f_bfree = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
538 pStat->f_bavail = VolumeInfo.ullAvailableAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
539 pStat->f_blocks = VolumeInfo.ullTotalAllocationBytes / VolumeInfo.ulBytesPerAllocationUnit;
540 pStat->f_files = 1000;
541 pStat->f_ffree = 1000; /* don't return 0 here since the guest may think that it is not possible to create any more files */
542 pStat->f_namemax = 255; /* @todo is this correct?? */
543
544 strlcpy(pStat->f_basetype, vfssw[pVFS->vfs_fstype].vsw_name, sizeof(pStat->f_basetype));
545 strlcpy(pStat->f_fstr, DEVICE_NAME, sizeof(pStat->f_fstr));
546
547 return 0;
548}
549
550static int VBoxVFS_VGet(vfs_t *pVFS, vnode_t **ppVNode, struct fid *pFid)
551{
552 /* -- TODO -- */
553 return 0;
554}
555
556static void VBoxVFS_FreeVFS(vfs_t *pVFS)
557{
558 vboxDisconnect(&g_VBoxVFSClient);
559 vboxUninit();
560}
561
562static int vboxvfs_CheckMountPerm(vfs_t *pVFS, struct mounta *pMount, vnode_t *pVNodeSpec, cred_t *pCred)
563{
564 /* Check if user has the rights to mount the special file. */
565 int fOpen = FREAD | FWRITE;
566 int fAccess = VREAD | VWRITE;
567 int rc;
568
569 if (pVNodeSpec->v_type != VBLK)
570 return ENOTBLK;
571
572 if ( (pVFS->vfs_flag & VFS_RDONLY)
573 || (pMount->flags & MS_RDONLY))
574 {
575 fOpen = FREAD;
576 fAccess = VREAD;
577 }
578
579 rc = VOP_ACCESS(pVNodeSpec, fAccess, 0, pCred, NULL /* caller_context */);
580 if (!rc)
581 rc = secpolicy_spec_open(pCred, pVNodeSpec, fOpen);
582
583 return rc;
584}
585
586static int vboxvfs_GetIntOpt(vfs_t *pVFS, char *pszOpt, int *pValue)
587{
588 int rc;
589 long Val;
590 char *pchOpt = NULL;
591 char *pchEnd = NULL;
592
593 rc = vfs_optionisset(pVFS, pszOpt, &pchOpt);
594 if (rc)
595 {
596 rc = ddi_strtol(pchOpt, &pchEnd, 10 /* base */, &Val);
597 if ( !rc
598 && Val > INT_MIN
599 && Val < INT_MAX
600 && pchEnd == pchOpt + strlen(pchOpt))
601 {
602 *pValue = (int)Val;
603 return 0;
604 }
605 return -1;
606 }
607 return 1;
608}
609
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette