Home | History | Annotate | Download | only in syscall
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <sys/copyops.h>
     30 #include <sys/errno.h>
     31 #include <sys/kmem.h>
     32 #include <sys/param.h>
     33 #include <sys/pathname.h>
     34 #include <sys/sysmacros.h>
     35 #include <sys/systm.h>
     36 #include <sys/types.h>
     37 #include <sys/vnode.h>
     38 
     39 int
     40 getcwd(char *buf, size_t buflen)
     41 {
     42 	int err;
     43 	char *kbuf;
     44 	size_t kbuflen;
     45 
     46 	/*
     47 	 * The user should be able to specify any size buffer, but we don't want
     48 	 * to arbitrarily allocate huge kernel buffers just because the user
     49 	 * requests it.  So we'll start with MAXPATHLEN (which should hold any
     50 	 * normal path), and only increase it if we fail with ERANGE.
     51 	 */
     52 	kbuflen = MIN(buflen, MAXPATHLEN);
     53 
     54 	for (;;) {
     55 		kbuf = kmem_alloc(kbuflen, KM_SLEEP);
     56 
     57 		if (((err = dogetcwd(kbuf, kbuflen)) == 0) &&
     58 		    (copyout(kbuf, buf, strlen(kbuf) + 1) != 0))
     59 			err = EFAULT;
     60 
     61 		kmem_free(kbuf, kbuflen);
     62 
     63 		if (err == ENAMETOOLONG) {
     64 			/*
     65 			 * If the user's buffer really was too small, give up.
     66 			 * For some reason, getcwd() uses ERANGE for this case.
     67 			 */
     68 			if (kbuflen == buflen) {
     69 				err = ERANGE;
     70 				break;
     71 			}
     72 			kbuflen = MIN(kbuflen * 2, buflen);
     73 		} else {
     74 			break;
     75 		}
     76 	}
     77 
     78 	return ((err != 0) ? set_errno(err) : 0);
     79 }
     80