2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/proc_internal.h>
32 #include <sys/systm.h>
33 #include <sys/systm.h>
34 #include <sys/mount_internal.h>
35 #include <sys/filedesc.h>
36 #include <sys/vnode_internal.h>
37 #include <sys/imageboot.h>
38 #include <kern/assert.h>
40 #include <sys/namei.h>
41 #include <sys/fcntl.h>
42 #include <sys/vnode.h>
43 #include <sys/sysproto.h>
45 #include <miscfs/devfs/devfsdefs.h>
46 #include <libkern/crypto/sha2.h>
47 #include <libkern/crypto/rsa.h>
48 #include <libkern/OSKextLibPrivate.h>
50 #if CONFIG_IMAGEBOOT_IMG4
51 #include <libkern/img4/interface.h>
52 #include <img4/img4.h>
55 #include <kern/kalloc.h>
57 #include <pexpert/pexpert.h>
58 #include <kern/chunklist.h>
60 extern struct filedesc filedesc0
;
62 extern int (*mountroot
)(void);
63 extern char rootdevice
[DEVMAXNAMESIZE
];
66 typedef struct _locker_mount_args
{
67 char lmnt_path
[PATH_MAX
];
68 uint16_t lmnt_preferred_hash
;
69 } locker_mount_args_t
;
72 #define DEBUG_IMAGEBOOT 0
75 #define DBG_TRACE(...) printf("imageboot: " __VA_ARGS__)
77 #define DBG_TRACE(...) do {} while(0)
80 #define AUTHDBG(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
81 #define AUTHPRNT(fmt, args...) do { printf("%s: " fmt "\n", __func__, ##args); } while (0)
82 #define kfree_safe(x) do { if ((x)) { kfree_addr((x)); (x) = NULL; } } while (0)
84 extern int di_root_image(const char *path
, char *devname
, size_t devsz
, dev_t
*dev_p
);
85 extern int di_root_ramfile_buf(void *buf
, size_t bufsz
, char *devname
, size_t devsz
, dev_t
*dev_p
);
87 static boolean_t
imageboot_setup_new(imageboot_type_t type
);
89 vnode_t
imgboot_get_image_file(const char *path
, off_t
*fsize
, int *errp
); /* may be required by chunklist.c */
90 int read_file(const char *path
, void **bufp
, size_t *bufszp
); /* may be required by chunklist.c */
92 #define kIBFilePrefix "file://"
94 __private_extern__
int
95 imageboot_format_is_valid(const char *root_path
)
97 return strncmp(root_path
, kIBFilePrefix
,
98 strlen(kIBFilePrefix
)) == 0;
102 vnode_get_and_drop_always(vnode_t vp
)
109 __private_extern__ imageboot_type_t
110 imageboot_needed(void)
112 imageboot_type_t result
= IMAGEBOOT_NONE
;
113 char *root_path
= NULL
;
115 DBG_TRACE("%s: checking for presence of root path\n", __FUNCTION__
);
117 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
118 if (root_path
== NULL
) {
119 panic("%s: M_NAMEI zone exhausted", __FUNCTION__
);
122 #if CONFIG_LOCKERBOOT
123 if (PE_parse_boot_argn(IMAGEBOOT_LOCKER_ARG
, root_path
, MAXPATHLEN
)) {
124 result
= IMAGEBOOT_LOCKER
;
129 /* Check for first layer */
130 if (!(PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) ||
131 #if CONFIG_IMAGEBOOT_IMG4
132 PE_parse_boot_argn("arp0", root_path
, MAXPATHLEN
) ||
134 PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) ||
135 PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) ||
136 PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
))) {
140 /* Sanity-check first layer */
141 if (imageboot_format_is_valid(root_path
)) {
142 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
147 result
= IMAGEBOOT_DMG
;
149 /* Check for second layer */
150 if (!(PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) ||
151 PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
))) {
155 /* Sanity-check second layer */
156 if (imageboot_format_is_valid(root_path
)) {
157 DBG_TRACE("%s: Found %s\n", __FUNCTION__
, root_path
);
159 panic("%s: Invalid URL scheme for %s\n",
160 __FUNCTION__
, root_path
);
164 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
171 * Swaps in new root filesystem based on image path.
172 * Current root filesystem is removed from mount list and
173 * tagged MNTK_BACKS_ROOT, MNT_ROOTFS is cleared on it, and
174 * "rootvnode" is reset. Root vnode of currentroot filesystem
175 * is returned with usecount (no iocount).
177 __private_extern__
int
178 imageboot_mount_image(const char *root_path
, int height
, imageboot_type_t type
)
183 * Need to stash this here since we may do a kernel_mount() on /, which will
184 * automatically update the rootvnode global. Note that vfs_mountroot() does
185 * not update that global, which is a bit weird.
187 vnode_t old_rootvnode
= rootvnode
;
190 boolean_t update_rootvnode
= FALSE
;
192 if (type
== IMAGEBOOT_DMG
) {
193 error
= di_root_image(root_path
, rootdevice
, DEVMAXNAMESIZE
, &dev
);
195 panic("%s: di_root_image failed: %d\n", __FUNCTION__
, error
);
200 printf("%s: root device 0x%x\n", __FUNCTION__
, rootdev
);
201 error
= vfs_mountroot();
203 panic("vfs_mountroot() failed.\n");
206 update_rootvnode
= TRUE
;
208 #if CONFIG_LOCKERBOOT
209 else if (type
== IMAGEBOOT_LOCKER
) {
210 locker_mount_args_t
*mntargs
= kalloc(sizeof(*mntargs
));
212 panic("could not alloc mount args");
215 strlcpy(mntargs
->lmnt_path
, root_path
, sizeof(mntargs
->lmnt_path
));
216 mntargs
->lmnt_preferred_hash
= 0;
218 DBG_TRACE("%s: mounting locker: %s\n", __FUNCTION__
, root_path
);
219 error
= kernel_mount(LOCKERFS_NAME
, NULLVP
, NULLVP
, "/",
220 mntargs
, sizeof(*mntargs
), 0, 0, vfs_context_kernel());
222 panic("failed to mount locker: %d", error
);
224 kfree(mntargs
, sizeof(*mntargs
));
226 /* Clear the old mount association. */
227 old_rootvnode
->v_mountedhere
= NULL
;
228 rootvnode
->v_mount
->mnt_vnodecovered
= NULL
;
232 panic("invalid imageboot type: %d", type
);
236 * Get the vnode for '/'.
237 * Set fdp->fd_fd.fd_cdir to reference it.
239 if (VFS_ROOT(TAILQ_LAST(&mountlist
, mntlist
), &newdp
, vfs_context_kernel())) {
240 panic("%s: cannot find root vnode", __FUNCTION__
);
242 DBG_TRACE("%s: old root fsname: %s\n", __FUNCTION__
, old_rootvnode
->v_mount
->mnt_vtable
->vfc_name
);
244 if (old_rootvnode
!= NULL
) {
245 /* remember the old rootvnode, but remove it from mountlist */
246 mount_t old_rootfs
= old_rootvnode
->v_mount
;
248 mount_list_remove(old_rootfs
);
249 mount_lock(old_rootfs
);
250 #ifdef CONFIG_IMGSRC_ACCESS
251 old_rootfs
->mnt_kern_flag
|= MNTK_BACKS_ROOT
;
252 #endif /* CONFIG_IMGSRC_ACCESS */
253 old_rootfs
->mnt_flag
&= ~MNT_ROOTFS
;
254 mount_unlock(old_rootfs
);
257 /* switch to the new rootvnode */
258 if (update_rootvnode
) {
262 new_rootfs
= rootvnode
->v_mount
;
263 mount_lock(new_rootfs
);
264 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
265 mount_unlock(new_rootfs
);
269 filedesc0
.fd_cdir
= newdp
;
270 DBG_TRACE("%s: root switched\n", __FUNCTION__
);
272 if (old_rootvnode
!= NULL
) {
273 #ifdef CONFIG_IMGSRC_ACCESS
274 if (height
>= 0 && PE_imgsrc_mount_supported()) {
275 imgsrc_rootvnodes
[height
] = old_rootvnode
;
277 vnode_get_and_drop_always(old_rootvnode
);
280 #pragma unused(height)
281 vnode_get_and_drop_always(old_rootvnode
);
282 #endif /* CONFIG_IMGSRC_ACCESS */
288 read_file(const char *path
, void **bufp
, size_t *bufszp
)
291 struct nameidata ndp
= {};
292 struct vnode
*vp
= NULL
;
296 bool doclose
= false;
298 vfs_context_t ctx
= vfs_context_kernel();
299 proc_t p
= vfs_context_proc(ctx
);
300 kauth_cred_t kerncred
= vfs_context_ucred(ctx
);
302 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
);
303 if ((err
= namei(&ndp
)) != 0) {
304 AUTHPRNT("namei failed (%s) - %d", path
, err
);
310 if ((err
= vnode_size(vp
, &fsize
, ctx
)) != 0) {
311 AUTHPRNT("failed to get vnode size of %s - %d", path
, err
);
315 panic("negative file size");
318 if ((err
= VNOP_OPEN(vp
, FREAD
, ctx
)) != 0) {
319 AUTHPRNT("failed to open %s - %d", path
, err
);
324 /* if bufsz is non-zero, cap the read at bufsz bytes */
325 if (*bufszp
&& *bufszp
< (size_t)fsize
) {
335 if ((err
= vn_rdwr(UIO_READ
, vp
, (caddr_t
)buf
, fsize
, 0, UIO_SYSSPACE
, IO_NODELOCKED
, kerncred
, &resid
, p
)) != 0) {
336 AUTHPRNT("Cannot read %d bytes from %s - %d", (int)fsize
, path
, err
);
341 /* didnt get everything we wanted */
342 AUTHPRNT("Short read of %d bytes from %s - %d", (int)fsize
, path
, resid
);
349 VNOP_CLOSE(vp
, FREAD
, ctx
);
366 #if CONFIG_IMAGEBOOT_IMG4 || CONFIG_IMAGEBOOT_CHUNKLIST
368 imgboot_get_image_file(const char *path
, off_t
*fsize
, int *errp
)
370 struct nameidata ndp
= {};
372 vfs_context_t ctx
= vfs_context_kernel();
375 NDINIT(&ndp
, LOOKUP
, OP_OPEN
, LOCKLEAF
, UIO_SYSSPACE
, CAST_USER_ADDR_T(path
), ctx
);
376 if ((err
= namei(&ndp
)) != 0) {
377 AUTHPRNT("Cannot find %s - error %d", path
, err
);
382 if (vp
->v_type
!= VREG
) {
384 AUTHPRNT("%s it not a regular file", path
);
386 if ((err
= vnode_size(vp
, fsize
, ctx
)) != 0) {
387 AUTHPRNT("Cannot get file size of %s - error %d", path
, err
);
398 #endif /* CONFIG_IMAGEBOOT_CHUNKLIST || CONFIG_IMAGEBOOT_CHUNKLIST */
400 #if CONFIG_IMAGEBOOT_IMG4
402 #define APTICKET_NAME "apticket.der"
405 imgboot_get_apticket_path(const char *rootpath
)
407 size_t plen
= strlen(rootpath
) + sizeof(APTICKET_NAME
);
408 char *path
= kalloc(plen
);
413 strlcpy(path
, rootpath
, plen
);
414 slash
= strrchr(path
, '/');
420 strlcpy(slash
, APTICKET_NAME
, sizeof(APTICKET_NAME
) + 1);
426 authenticate_root_with_img4(const char *rootpath
)
436 DBG_TRACE("Check %s\n", rootpath
);
438 if (img4if
== NULL
) {
439 AUTHPRNT("AppleImage4 is not ready");
443 ticket_path
= imgboot_get_apticket_path(rootpath
);
444 if (ticket_path
== NULL
) {
445 AUTHPRNT("Cannot construct ticket path - out of memory");
449 rv
= read_file(ticket_path
, &tckbuf
, &tcksz
);
451 AUTHPRNT("Cannot get a ticket from %s - %d\n", ticket_path
, rv
);
452 goto out_with_ticket_path
;
455 DBG_TRACE("Got %d bytes of manifest from %s\n", (int)tcksz
, ticket_path
);
457 rv
= img4_init(&i4
, 0, tckbuf
, tcksz
, NULL
);
459 AUTHPRNT("Cannot initialise verification handle - error %d", rv
);
460 goto out_with_ticket_bytes
;
463 vp
= imgboot_get_image_file(rootpath
, NULL
, &rv
);
465 /* Error message had been printed already */
469 rv
= img4_payload_init_with_vnode_4xnu(&i4pl
, 'rosi', vp
, I4PLF_UNWRAPPED
);
471 AUTHPRNT("failed to init payload: %d", rv
);
475 rv
= img4_get_trusted_external_payload(&i4
, &i4pl
, IMG4_ENVIRONMENT_PPL
, NULL
, NULL
);
477 AUTHPRNT("failed to validate root image %s: %d", rootpath
, rv
);
480 img4_payload_destroy(&i4pl
);
483 out_with_ticket_bytes
:
485 out_with_ticket_path
:
486 kfree_safe(ticket_path
);
489 #endif /* CONFIG_IMAGEBOOT_IMG4 */
493 * Attach the image at 'path' as a ramdisk and mount it as our new rootfs.
494 * All existing mounts are first umounted.
497 imageboot_mount_ramdisk(const char *path
)
506 /* Read our target image from disk */
507 err
= read_file(path
, &buf
, &bufsz
);
509 printf("%s: failed: read_file() = %d\n", __func__
, err
);
512 DBG_TRACE("%s: read '%s' sz = %lu\n", __func__
, path
, bufsz
);
514 #if CONFIG_IMGSRC_ACCESS
515 /* Re-add all root mounts to the mount list in the correct order... */
516 mount_list_remove(rootvnode
->v_mount
);
517 for (int i
= 0; i
< MAX_IMAGEBOOT_NESTING
; i
++) {
518 struct vnode
*vn
= imgsrc_rootvnodes
[i
];
521 imgsrc_rootvnodes
[i
] = NULLVP
;
523 mount_t mnt
= vn
->v_mount
;
525 mnt
->mnt_flag
|= MNT_ROOTFS
;
533 mount_list_add(rootvnode
->v_mount
);
536 /* ... and unmount everything */
537 vnode_get_and_drop_always(rootvnode
);
538 filedesc0
.fd_cdir
= NULL
;
542 /* Attach the ramfs image ... */
543 err
= di_root_ramfile_buf(buf
, bufsz
, rootdevice
, DEVMAXNAMESIZE
, &dev
);
545 printf("%s: failed: di_root_ramfile_buf() = %d\n", __func__
, err
);
549 /* ... and mount it */
552 err
= vfs_mountroot();
554 printf("%s: failed: vfs_mountroot() = %d\n", __func__
, err
);
558 /* Switch to new root vnode */
559 if (VFS_ROOT(TAILQ_LAST(&mountlist
, mntlist
), &newdp
, vfs_context_kernel())) {
560 panic("%s: cannot find root vnode", __func__
);
563 rootvnode
->v_flag
|= VROOT
;
564 new_rootfs
= rootvnode
->v_mount
;
565 mount_lock(new_rootfs
);
566 new_rootfs
->mnt_flag
|= MNT_ROOTFS
;
567 mount_unlock(new_rootfs
);
571 filedesc0
.fd_cdir
= newdp
;
573 DBG_TRACE("%s: root switched\n", __func__
);
583 * If the path is in <file://> URL format then we allocate memory and decode it,
584 * otherwise return the same pointer.
586 * Caller is expected to check if the pointers are different.
589 url_to_path(char *url_path
)
591 char *path
= url_path
;
592 size_t len
= strlen(kIBFilePrefix
);
594 if (strncmp(kIBFilePrefix
, url_path
, len
) == 0) {
595 /* its a URL - remove the file:// prefix and percent-decode */
598 len
= strlen(url_path
);
600 /* Make a copy of the path to URL-decode */
601 path
= kalloc(len
+ 1);
603 panic("imageboot path allocation failed - cannot allocate %d bytes\n", (int)len
);
606 strlcpy(path
, url_path
, len
+ 1);
609 panic("Bogus imageboot path URL - missing path\n");
612 DBG_TRACE("%s: root image URL <%s> becomes %s\n", __func__
, url_path
, path
);
619 imageboot_setup_new(imageboot_type_t type
)
622 char *root_path
= NULL
;
624 boolean_t done
= FALSE
;
625 boolean_t auth_root
= TRUE
;
626 boolean_t ramdisk_root
= FALSE
;
628 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
629 assert(root_path
!= NULL
);
631 #if CONFIG_LOCKERBOOT
632 if (type
== IMAGEBOOT_LOCKER
) {
633 if (!PE_parse_boot_argn(IMAGEBOOT_LOCKER_ARG
, root_path
, MAXPATHLEN
)) {
634 panic("locker boot with no locker given");
637 DBG_TRACE("%s: root fsname: %s\n", __FUNCTION__
, rootvnode
->v_mount
->mnt_vtable
->vfc_name
);
640 * The locker path is a path, not a URL, so just pass it directly to
641 * imageboot_mount_image().
643 error
= imageboot_mount_image(root_path
, 0, type
);
645 panic("failed to mount system locker: %d", error
);
651 #endif /* CONFIG_LOCKERBOOT */
653 unsigned imgboot_arg
;
654 if (PE_parse_boot_argn("-rootdmg-ramdisk", &imgboot_arg
, sizeof(imgboot_arg
))) {
658 if (PE_parse_boot_argn(IMAGEBOOT_CONTAINER_ARG
, root_path
, MAXPATHLEN
) == TRUE
) {
659 printf("%s: container image url is %s\n", __FUNCTION__
, root_path
);
660 error
= imageboot_mount_image(root_path
, height
, type
);
662 panic("Failed to mount container image.");
668 if (PE_parse_boot_argn(IMAGEBOOT_AUTHROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
&&
669 PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG
, root_path
, MAXPATHLEN
) == FALSE
) {
671 panic("%s specified without %s or %s?\n", IMAGEBOOT_CONTAINER_ARG
, IMAGEBOOT_AUTHROOT_ARG
, IMAGEBOOT_ROOT_ARG
);
676 printf("%s: root image URL is '%s'\n", __func__
, root_path
);
679 if (auth_root
&& (csr_check(CSR_ALLOW_ANY_RECOVERY_OS
) == 0)) {
680 AUTHPRNT("CSR_ALLOW_ANY_RECOVERY_OS set, skipping root image authentication");
685 /* Make a copy of the path to URL-decode */
686 char *path
= url_to_path(root_path
);
689 #if CONFIG_IMAGEBOOT_CHUNKLIST
691 AUTHDBG("authenticating root image at %s", path
);
692 error
= authenticate_root_with_chunklist(path
);
694 panic("root image authentication failed (err = %d)\n", error
);
696 AUTHDBG("successfully authenticated %s", path
);
701 error
= imageboot_mount_ramdisk(path
);
703 error
= imageboot_mount_image(root_path
, height
, type
);
706 if (path
!= root_path
) {
711 panic("Failed to mount root image (err=%d, auth=%d, ramdisk=%d)\n",
712 error
, auth_root
, ramdisk_root
);
715 #if CONFIG_IMAGEBOOT_CHUNKLIST
717 /* check that the image version matches the running kernel */
718 AUTHDBG("checking root image version");
719 error
= authenticate_root_version_check();
721 panic("root image version check failed");
723 AUTHDBG("root image version matches kernel");
731 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
735 __private_extern__
void
736 imageboot_setup(imageboot_type_t type
)
739 char *root_path
= NULL
;
741 DBG_TRACE("%s: entry\n", __FUNCTION__
);
743 if (rootvnode
== NULL
) {
744 panic("imageboot_setup: rootvnode is NULL.");
748 * New boot-arg scheme:
749 * root-dmg : the dmg that will be the root filesystem, authenticated by default.
750 * auth-root-dmg : same as root-dmg.
751 * container-dmg : an optional dmg that contains the root-dmg.
752 * locker : the locker that will be the root filesystem -- mutually
753 * exclusive with any other boot-arg.
755 if (imageboot_setup_new(type
)) {
759 MALLOC_ZONE(root_path
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
760 assert(root_path
!= NULL
);
763 * Look for outermost disk image to root from. If we're doing a nested boot,
764 * there's some sense in which the outer image never needs to be the root filesystem,
765 * but it does need very similar treatment: it must not be unmounted, needs a fake
766 * device vnode created for it, and should not show up in getfsstat() until exposed
767 * with MNT_IMGSRC. We just make it the temporary root.
769 #if CONFIG_IMAGEBOOT_IMG4
770 if (PE_parse_boot_argn("arp0", root_path
, MAXPATHLEN
)) {
771 char *path
= url_to_path(root_path
);
775 if (authenticate_root_with_img4(path
)) {
776 panic("Root image %s does not match the manifest\n", root_path
);
778 if (path
!= root_path
) {
782 #endif /* CONFIG_IMAGEBOOT_IMG4 */
783 if ((PE_parse_boot_argn("rp", root_path
, MAXPATHLEN
) == FALSE
) &&
784 (PE_parse_boot_argn("rp0", root_path
, MAXPATHLEN
) == FALSE
)) {
785 panic("%s: no valid path to image.\n", __FUNCTION__
);
788 DBG_TRACE("%s: root image url is %s\n", __FUNCTION__
, root_path
);
790 error
= imageboot_mount_image(root_path
, 0, type
);
792 panic("Failed on first stage of imageboot.");
796 * See if we are rooting from a nested image
798 if (PE_parse_boot_argn("rp1", root_path
, MAXPATHLEN
) == FALSE
) {
802 printf("%s: second level root image url is %s\n", __FUNCTION__
, root_path
);
805 * If we fail to set up second image, it's not a given that we
806 * can safely root off the first.
808 error
= imageboot_mount_image(root_path
, 1, type
);
810 panic("Failed on second stage of imageboot.");
814 FREE_ZONE(root_path
, MAXPATHLEN
, M_NAMEI
);
816 DBG_TRACE("%s: exit\n", __FUNCTION__
);