xref: /illumos-gate/usr/src/lib/libc/port/rt/pos4obj.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5734b6a94Sdarrenm  * Common Development and Distribution License (the "License").
6734b6a94Sdarrenm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21e8031f0aSraf 
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*7257d1b4Sraf #include "lint.h"
28f841f6adSraf #include "mtlib.h"
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <sys/stat.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <limits.h>
367c478bd9Sstevel@tonic-gate #include <pthread.h>
377c478bd9Sstevel@tonic-gate #include <thread.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <dirent.h>
407c478bd9Sstevel@tonic-gate #include <stdio.h>
4134709573Sraf #include <dlfcn.h>
428cd45542Sraf #include <atomic.h>
437c478bd9Sstevel@tonic-gate #include <md5.h>
447c478bd9Sstevel@tonic-gate #include "pos4obj.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	HASHSTRLEN	32
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static	char	*__pos4obj_name(const char *, const char *);
497c478bd9Sstevel@tonic-gate static	void	__pos4obj_md5toa(unsigned char *, unsigned char *);
507c478bd9Sstevel@tonic-gate static	void	__pos4obj_clean(char *);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static	char	objroot[] = "/tmp/";
537c478bd9Sstevel@tonic-gate static	long int	name_max = 0;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate int
__open_nc(const char * path,int oflag,mode_t mode)567c478bd9Sstevel@tonic-gate __open_nc(const char *path, int oflag, mode_t mode)
577c478bd9Sstevel@tonic-gate {
58a574db85Sraf 	int		cancel_state;
59a574db85Sraf 	int		val;
607c478bd9Sstevel@tonic-gate 	struct stat64	statbuf;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	/*
637c478bd9Sstevel@tonic-gate 	 * Ensure path is not a symlink to somewhere else. This provides
647c478bd9Sstevel@tonic-gate 	 * a modest amount of protection against easy security attacks.
657c478bd9Sstevel@tonic-gate 	 */
667c478bd9Sstevel@tonic-gate 	if (lstat64(path, &statbuf) == 0) {
677c478bd9Sstevel@tonic-gate 		if (S_ISLNK(statbuf.st_mode)) {
687c478bd9Sstevel@tonic-gate 			errno = EINVAL;
697c478bd9Sstevel@tonic-gate 			return (-1);
707c478bd9Sstevel@tonic-gate 		}
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 
73a574db85Sraf 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
747c478bd9Sstevel@tonic-gate 	val = open64(path, oflag, mode);
75a574db85Sraf 	(void) pthread_setcancelstate(cancel_state, NULL);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	return (val);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate int
__close_nc(int fildes)817c478bd9Sstevel@tonic-gate __close_nc(int fildes)
827c478bd9Sstevel@tonic-gate {
83a574db85Sraf 	int	cancel_state;
84a574db85Sraf 	int	val;
857c478bd9Sstevel@tonic-gate 
86a574db85Sraf 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
877c478bd9Sstevel@tonic-gate 	val = close(fildes);
88a574db85Sraf 	(void) pthread_setcancelstate(cancel_state, NULL);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	return (val);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
9334709573Sraf /*
9434709573Sraf  * This is to avoid loading libmd.so.1 unless we absolutely have to.
9534709573Sraf  */
9634709573Sraf typedef void (*md5_calc_t)(unsigned char *, unsigned char *, unsigned int);
9734709573Sraf static md5_calc_t real_md5_calc = NULL;
98f841f6adSraf static mutex_t md5_lock = DEFAULTMUTEX;
9934709573Sraf 
10034709573Sraf static void
load_md5_calc(void)10134709573Sraf load_md5_calc(void)
10234709573Sraf {
103f90fe29eSraf 	void *md5_handle = dlopen("libmd.so.1", RTLD_LAZY);
1048cd45542Sraf 	md5_calc_t md5_calc = (md5_handle == NULL)? NULL :
1058cd45542Sraf 	    (md5_calc_t)dlsym(md5_handle, "md5_calc");
106f90fe29eSraf 
107f841f6adSraf 	lmutex_lock(&md5_lock);
10834709573Sraf 	if (real_md5_calc == NULL) {
1098cd45542Sraf 		if (md5_calc == NULL)
11034709573Sraf 			real_md5_calc = (md5_calc_t)(-1);
11134709573Sraf 		else {
1128cd45542Sraf 			real_md5_calc = md5_calc;
1138cd45542Sraf 			md5_handle = NULL;	/* don't dlclose it */
11434709573Sraf 		}
1158cd45542Sraf 		membar_producer();
11634709573Sraf 	}
117f841f6adSraf 	lmutex_unlock(&md5_lock);
118f90fe29eSraf 
119f90fe29eSraf 	if (md5_handle)
120f90fe29eSraf 		(void) dlclose(md5_handle);
12134709573Sraf }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static char *
__pos4obj_name(const char * path,const char * type)1247c478bd9Sstevel@tonic-gate __pos4obj_name(const char *path, const char *type)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	int	shortpath = 1;
1277c478bd9Sstevel@tonic-gate 	int	olderrno;
1287c478bd9Sstevel@tonic-gate 	size_t	len;
1297c478bd9Sstevel@tonic-gate 	char	*dfile;
1307c478bd9Sstevel@tonic-gate 	unsigned char	hashbuf[HASHSTRLEN + 1];
131734b6a94Sdarrenm 	unsigned char	md5_digest[MD5_DIGEST_LENGTH];
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/*
1347c478bd9Sstevel@tonic-gate 	 * If the path is path_max - strlen(type) characters or less,
1357c478bd9Sstevel@tonic-gate 	 * the name of the file to use will be the path prefixed by
1367c478bd9Sstevel@tonic-gate 	 * the type.
1377c478bd9Sstevel@tonic-gate 	 *
1387c478bd9Sstevel@tonic-gate 	 * In the special case where the path is longer than
1397c478bd9Sstevel@tonic-gate 	 * path_max - strlen(type) characters, we create a string based on the
1407c478bd9Sstevel@tonic-gate 	 * MD5 hash of the path. We prefix that string with a '.' to
1417c478bd9Sstevel@tonic-gate 	 * make it obscure, and create a directory in objroot with
1427c478bd9Sstevel@tonic-gate 	 * that name. In that directory, we create a directory named
1437c478bd9Sstevel@tonic-gate 	 * after the type of object requested.  Inside the type
1447c478bd9Sstevel@tonic-gate 	 * directory, the filename will be the path of the object. This
1457c478bd9Sstevel@tonic-gate 	 * prevents collisions in all namespaces.
1467c478bd9Sstevel@tonic-gate 	 *
1477c478bd9Sstevel@tonic-gate 	 * Example:
1487c478bd9Sstevel@tonic-gate 	 * Let objroot = "/tmp/", path = "/<longpath>", and type = ".MQD"
1497c478bd9Sstevel@tonic-gate 	 * Let the MD5 hash of "<longpath>" = "<hash>"
1507c478bd9Sstevel@tonic-gate 	 *
1517c478bd9Sstevel@tonic-gate 	 * The desired file is /tmp/.<hash>/.MQD/<longpath>
1527c478bd9Sstevel@tonic-gate 	 */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Do not include the leading '/' in the path length.
1567c478bd9Sstevel@tonic-gate 	 * Assumes __pos4obj_check(path) has already been called.
1577c478bd9Sstevel@tonic-gate 	 */
1587c478bd9Sstevel@tonic-gate 	if ((strlen(path) - 1) > (name_max - strlen(type)))
1597c478bd9Sstevel@tonic-gate 		shortpath = 0;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if (shortpath) {
1627c478bd9Sstevel@tonic-gate 		/*
1637c478bd9Sstevel@tonic-gate 		 * strlen(path) includes leading slash as space for NUL.
1647c478bd9Sstevel@tonic-gate 		 */
1657c478bd9Sstevel@tonic-gate 		len = strlen(objroot) + strlen(type) + strlen(path);
1667c478bd9Sstevel@tonic-gate 	} else {
1677c478bd9Sstevel@tonic-gate 		/*
1687c478bd9Sstevel@tonic-gate 		 * Long path name. Add 3 for extra '/', '.' and '\0'
1697c478bd9Sstevel@tonic-gate 		 */
1707c478bd9Sstevel@tonic-gate 		len = strlen(objroot) + HASHSTRLEN + strlen(type) +
1717c478bd9Sstevel@tonic-gate 		    strlen(path) + 3;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if ((dfile = malloc(len)) == NULL)
1757c478bd9Sstevel@tonic-gate 		return (NULL);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	(void) memset(dfile, 0, len);
1787c478bd9Sstevel@tonic-gate 	(void) strcpy(dfile, objroot);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (shortpath) {
1817c478bd9Sstevel@tonic-gate 		(void) strcat(dfile, type);
1827c478bd9Sstevel@tonic-gate 		(void) strcat(dfile, path + 1);
1837c478bd9Sstevel@tonic-gate 		return (dfile);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
18634709573Sraf 	/*
18734709573Sraf 	 * If we can successfully load it, call md5_calc().
18834709573Sraf 	 * Otherwise, (this "can't happen") return NULL.
18934709573Sraf 	 */
19034709573Sraf 	if (real_md5_calc == NULL)
19134709573Sraf 		load_md5_calc();
19234709573Sraf 	if (real_md5_calc == (md5_calc_t)(-1)) {
19334709573Sraf 		free(dfile);
19434709573Sraf 		return (NULL);
19534709573Sraf 	}
19634709573Sraf 
19734709573Sraf 	real_md5_calc(md5_digest, (unsigned char *)path + 1, strlen(path + 1));
1987c478bd9Sstevel@tonic-gate 	__pos4obj_md5toa(hashbuf, md5_digest);
1997c478bd9Sstevel@tonic-gate 	(void) strcat(dfile, ".");
2007c478bd9Sstevel@tonic-gate 	(void) strcat(dfile, (const char *)hashbuf);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/*
2037c478bd9Sstevel@tonic-gate 	 * Errno must be preserved across the following calls to
2047c478bd9Sstevel@tonic-gate 	 * mkdir.  This needs to be done to prevent incorrect error
205f841f6adSraf 	 * reporting in certain cases. When we attempt to open a
2067c478bd9Sstevel@tonic-gate 	 * non-existent object without the O_CREAT flag, it will
2077c478bd9Sstevel@tonic-gate 	 * always create a lock file first.  The lock file is created
2087c478bd9Sstevel@tonic-gate 	 * and then the open is attempted, but fails with ENOENT. The
2097c478bd9Sstevel@tonic-gate 	 * lock file is then destroyed. In the following code path, we
2107c478bd9Sstevel@tonic-gate 	 * are finding the absolute path to the lock file after
2117c478bd9Sstevel@tonic-gate 	 * already having attempted the open (which set errno to
2127c478bd9Sstevel@tonic-gate 	 * ENOENT). The following calls to mkdir will return -1 and
2137c478bd9Sstevel@tonic-gate 	 * set errno to EEXIST, since the hash and type directories
2147c478bd9Sstevel@tonic-gate 	 * were created when the lock file was created. The correct
2157c478bd9Sstevel@tonic-gate 	 * errno is the ENOENT from the attempted open of the desired
2167c478bd9Sstevel@tonic-gate 	 * object.
2177c478bd9Sstevel@tonic-gate 	 */
2187c478bd9Sstevel@tonic-gate 	olderrno = errno;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/*
2217c478bd9Sstevel@tonic-gate 	 * Create hash directory. Use 777 permissions so everyone can use it.
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	if (mkdir(dfile, S_IRWXU|S_IRWXG|S_IRWXO) == 0) {
2247c478bd9Sstevel@tonic-gate 		if (chmod(dfile, S_IRWXU|S_IRWXG|S_IRWXO) == -1) {
2257c478bd9Sstevel@tonic-gate 			free(dfile);
2267c478bd9Sstevel@tonic-gate 			return (NULL);
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 	} else {
2297c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
2307c478bd9Sstevel@tonic-gate 			free(dfile);
2317c478bd9Sstevel@tonic-gate 			return (NULL);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	(void) strcat(dfile, "/");
2367c478bd9Sstevel@tonic-gate 	(void) strcat(dfile, type);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * Create directory for requested type. Use 777 perms so everyone
2407c478bd9Sstevel@tonic-gate 	 * can use it.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	if (mkdir(dfile, S_IRWXU|S_IRWXG|S_IRWXO) == 0) {
2437c478bd9Sstevel@tonic-gate 		if (chmod(dfile, S_IRWXU|S_IRWXG|S_IRWXO) == -1) {
2447c478bd9Sstevel@tonic-gate 			free(dfile);
2457c478bd9Sstevel@tonic-gate 			return (NULL);
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 	} else {
2487c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
2497c478bd9Sstevel@tonic-gate 			free(dfile);
2507c478bd9Sstevel@tonic-gate 			return (NULL);
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	errno = olderrno;
2557c478bd9Sstevel@tonic-gate 	(void) strcat(dfile, path);
2567c478bd9Sstevel@tonic-gate 	return (dfile);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate /*
2607c478bd9Sstevel@tonic-gate  * Takes a 128-bit MD5 digest and transforms to a sequence of 32 ASCII
2617c478bd9Sstevel@tonic-gate  * characters. Output is the hexadecimal representation of the digest.
2627c478bd9Sstevel@tonic-gate  *
2637c478bd9Sstevel@tonic-gate  * The output buffer must be at least HASHSTRLEN + 1 characters
2647c478bd9Sstevel@tonic-gate  * long.  HASHSTRLEN is the size of the MD5 digest (128 bits)
2657c478bd9Sstevel@tonic-gate  * divided by the number of bits used per char of output (4). The
2667c478bd9Sstevel@tonic-gate  * extra character at the end is for the NUL terminating character.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static void
__pos4obj_md5toa(unsigned char * dest,unsigned char * src)2707c478bd9Sstevel@tonic-gate __pos4obj_md5toa(unsigned char *dest, unsigned char *src)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	int i;
2737c478bd9Sstevel@tonic-gate 	uint32_t *p;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast may result in improper alignment */
2767c478bd9Sstevel@tonic-gate 	p = (uint32_t *)src;
2777c478bd9Sstevel@tonic-gate 
278734b6a94Sdarrenm 	for (i = 0; i < (MD5_DIGEST_LENGTH / 4); i++)
2797c478bd9Sstevel@tonic-gate 		(void) snprintf((char *)dest + (i * 8), 9, "%.8x", *p++);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	dest[HASHSTRLEN] = '\0';
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * This open function assume that there is no simultaneous
2867c478bd9Sstevel@tonic-gate  * open/unlink operation is going on. The caller is supposed
2877c478bd9Sstevel@tonic-gate  * to ensure that both open in O_CREAT mode happen atomically.
2887c478bd9Sstevel@tonic-gate  * It returns the crflag as 1 if file is created else 0.
2897c478bd9Sstevel@tonic-gate  */
2907c478bd9Sstevel@tonic-gate int
__pos4obj_open(const char * name,char * type,int oflag,mode_t mode,int * crflag)2917c478bd9Sstevel@tonic-gate __pos4obj_open(const char *name, char *type, int oflag,
2927c478bd9Sstevel@tonic-gate 		mode_t mode, int *crflag)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	int fd;
2957c478bd9Sstevel@tonic-gate 	char *dfile;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	errno = 0;
2987c478bd9Sstevel@tonic-gate 	*crflag = 0;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	if ((dfile = __pos4obj_name(name, type)) == NULL) {
3017c478bd9Sstevel@tonic-gate 		return (-1);
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (!(oflag & O_CREAT)) {
3057c478bd9Sstevel@tonic-gate 		if ((fd = __open_nc(dfile, oflag, mode)) == -1)
3067c478bd9Sstevel@tonic-gate 			__pos4obj_clean(dfile);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		free(dfile);
3097c478bd9Sstevel@tonic-gate 		return (fd);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/*
3137c478bd9Sstevel@tonic-gate 	 * We need to make sure that crflag is set iff we actually create
3147c478bd9Sstevel@tonic-gate 	 * the file.  We do this by or'ing in O_EXCL, and attempting an
3157c478bd9Sstevel@tonic-gate 	 * open.  If that fails with an EEXIST, and O_EXCL wasn't specified
3167c478bd9Sstevel@tonic-gate 	 * by the caller, then the file seems to exist;  we'll try an
3177c478bd9Sstevel@tonic-gate 	 * open with O_CREAT cleared.  If that succeeds, then the file
3187c478bd9Sstevel@tonic-gate 	 * did indeed exist.  If that fails with an ENOENT, however, the
3197c478bd9Sstevel@tonic-gate 	 * file was removed between the opens;  we need to take another
3207c478bd9Sstevel@tonic-gate 	 * lap.
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	for (;;) {
3237c478bd9Sstevel@tonic-gate 		if ((fd = __open_nc(dfile, (oflag | O_EXCL), mode)) == -1) {
3247c478bd9Sstevel@tonic-gate 			if (errno == EEXIST && !(oflag & O_EXCL)) {
3257c478bd9Sstevel@tonic-gate 				fd = __open_nc(dfile, oflag & ~O_CREAT, mode);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 				if (fd == -1 && errno == ENOENT)
3287c478bd9Sstevel@tonic-gate 					continue;
3297c478bd9Sstevel@tonic-gate 				break;
3307c478bd9Sstevel@tonic-gate 			}
3317c478bd9Sstevel@tonic-gate 		} else {
3327c478bd9Sstevel@tonic-gate 			*crflag = 1;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 		break;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	free(dfile);
3387c478bd9Sstevel@tonic-gate 	return (fd);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate int
__pos4obj_unlink(const char * name,const char * type)3437c478bd9Sstevel@tonic-gate __pos4obj_unlink(const char *name, const char *type)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	int	err;
3467c478bd9Sstevel@tonic-gate 	char	*dfile;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if ((dfile = __pos4obj_name(name, type)) == NULL) {
3497c478bd9Sstevel@tonic-gate 		return (-1);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	err = unlink(dfile);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	__pos4obj_clean(dfile);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	free(dfile);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	return (err);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate  * This function opens the lock file for each named object
3637c478bd9Sstevel@tonic-gate  * the presence of this file in the file system is the lock
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate int
__pos4obj_lock(const char * name,const char * ltype)3667c478bd9Sstevel@tonic-gate __pos4obj_lock(const char *name, const char *ltype)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	char	*dfile;
3697c478bd9Sstevel@tonic-gate 	int	fd;
3707c478bd9Sstevel@tonic-gate 	int	limit = 64;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if ((dfile = __pos4obj_name(name, ltype)) == NULL) {
3737c478bd9Sstevel@tonic-gate 		return (-1);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	while (limit-- > 0) {
3777c478bd9Sstevel@tonic-gate 		if ((fd = __open_nc(dfile, O_RDWR | O_CREAT | O_EXCL, 0666))
3787c478bd9Sstevel@tonic-gate 		    < 0) {
3797c478bd9Sstevel@tonic-gate 			if (errno != EEXIST)
3807c478bd9Sstevel@tonic-gate 				break;
3817c478bd9Sstevel@tonic-gate 			(void) sleep(1);
3827c478bd9Sstevel@tonic-gate 			continue;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		(void) __close_nc(fd);
3867c478bd9Sstevel@tonic-gate 		free(dfile);
3877c478bd9Sstevel@tonic-gate 		return (1);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	free(dfile);
3917c478bd9Sstevel@tonic-gate 	return (-1);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Unlocks the file by unlinking it from the filesystem
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate int
__pos4obj_unlock(const char * path,const char * type)3987c478bd9Sstevel@tonic-gate __pos4obj_unlock(const char *path, const char *type)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	return (__pos4obj_unlink(path, type));
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * Removes unused hash and type directories that may exist in specified path.
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate static void
__pos4obj_clean(char * path)4077c478bd9Sstevel@tonic-gate __pos4obj_clean(char *path)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	char	*p;
4107c478bd9Sstevel@tonic-gate 	int	olderrno;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/*
4137c478bd9Sstevel@tonic-gate 	 * path is either
4147c478bd9Sstevel@tonic-gate 	 * 1) /<objroot>/<type><path>  or
4157c478bd9Sstevel@tonic-gate 	 * 2) /<objroot>/.<hash>/<type>/<path>
4167c478bd9Sstevel@tonic-gate 	 *
4177c478bd9Sstevel@tonic-gate 	 * In case 1, there is nothing to clean.
4187c478bd9Sstevel@tonic-gate 	 *
4197c478bd9Sstevel@tonic-gate 	 * Detect case 2 by looking for a '/' after /objroot/ and
4207c478bd9Sstevel@tonic-gate 	 * remove the two trailing directories, if empty.
4217c478bd9Sstevel@tonic-gate 	 */
4227c478bd9Sstevel@tonic-gate 	if (strchr(path + strlen(objroot), '/') == NULL)
4237c478bd9Sstevel@tonic-gate 		return;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * Preserve errno across calls to rmdir. See block comment in
4277c478bd9Sstevel@tonic-gate 	 * __pos4obj_name() for explanation.
4287c478bd9Sstevel@tonic-gate 	 */
4297c478bd9Sstevel@tonic-gate 	olderrno = errno;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((p = strrchr(path, '/')) == NULL)
4327c478bd9Sstevel@tonic-gate 		return;
4337c478bd9Sstevel@tonic-gate 	*p = '\0';
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	(void) rmdir(path);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if ((p = strrchr(path, '/')) == NULL)
4387c478bd9Sstevel@tonic-gate 		return;
4397c478bd9Sstevel@tonic-gate 	*p = '\0';
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	(void) rmdir(path);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	errno = olderrno;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate  * Check that path starts with a /, does not contain a / within it
4497c478bd9Sstevel@tonic-gate  * and is not longer than PATH_MAX or NAME_MAX
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate int
__pos4obj_check(const char * path)4527c478bd9Sstevel@tonic-gate __pos4obj_check(const char *path)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	long int	i;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * This assumes that __pos4obj_check() is called before
4587c478bd9Sstevel@tonic-gate 	 * any of the other functions in this file
4597c478bd9Sstevel@tonic-gate 	 */
4607c478bd9Sstevel@tonic-gate 	if (name_max == 0 || name_max == -1) {
4617c478bd9Sstevel@tonic-gate 		name_max = pathconf(objroot, _PC_NAME_MAX);
4627c478bd9Sstevel@tonic-gate 		if (name_max == -1)
4637c478bd9Sstevel@tonic-gate 			return (-1);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (*path++ != '/') {
4677c478bd9Sstevel@tonic-gate 		errno = EINVAL;
4687c478bd9Sstevel@tonic-gate 		return (-1);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	for (i = 0; *path != '\0'; i++) {
4727c478bd9Sstevel@tonic-gate 		if (*path++ == '/') {
4737c478bd9Sstevel@tonic-gate 			errno = EINVAL;
4747c478bd9Sstevel@tonic-gate 			return (-1);
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (i > PATH_MAX || i > name_max) {
4797c478bd9Sstevel@tonic-gate 		errno = ENAMETOOLONG;
4807c478bd9Sstevel@tonic-gate 		return (-1);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	return (0);
4847c478bd9Sstevel@tonic-gate }
485