/ util / opendev.c
opendev.c
  1  /*
  2   * Copyright (c) 2000, Todd C. Miller.  All rights reserved.
  3   * Copyright (c) 1996, Jason Downs.  All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   *
 14   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
 15   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 16   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 17   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
 18   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 19   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 20   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 21   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 22   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 23   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 24   * SUCH DAMAGE.
 25   */
 26  
 27  #include <ctype.h>
 28  #include <errno.h>
 29  #include <fcntl.h>
 30  #include <limits.h>
 31  #include <paths.h>
 32  #include <stdio.h>
 33  #include <string.h>
 34  #include <pthread.h>
 35  
 36  #include "util.h"
 37  
 38  /*
 39   * opendev(3) is an inherently non-thread-safe API, since
 40   * it returns a buffer to global storage. However we can
 41   * at least make sure the storage allocation is thread safe
 42   * and does not leak memory in case of simultaneous
 43   * initialization
 44   */
 45  static pthread_once_t opendev_namebuf_once = PTHREAD_ONCE_INIT;
 46  static char *namebuf = NULL;
 47  
 48  static void opendev_namebuf_init(void);
 49  
 50  int
 51  opendev(path, oflags, dflags, realpath)
 52  	char *path;
 53  	int oflags;
 54  	int dflags;
 55  	char **realpath;
 56  {
 57  	int fd;
 58  	char *slash, *prefix;
 59  
 60  	/* Initial state */
 61  	if (realpath)
 62  		*realpath = path;
 63  	fd = -1;
 64  	errno = ENOENT;
 65  
 66  	if (pthread_once(&opendev_namebuf_once,
 67  					 opendev_namebuf_init)
 68  		|| !namebuf) {
 69  		errno = ENOMEM;
 70  		return -1;
 71  	}
 72  
 73  	if (dflags & OPENDEV_BLCK)
 74  		prefix = "";			/* block device */
 75  	else
 76  		prefix = "r";			/* character device */
 77  
 78  	if ((slash = strchr(path, '/')))
 79  		fd = open(path, oflags);
 80  	else if (dflags & OPENDEV_PART) {
 81  		if (snprintf(namebuf, PATH_MAX, "%s%s%s",
 82  		    _PATH_DEV, prefix, path) < PATH_MAX) {
 83  			char *slice;
 84  			while ((slice = strrchr(namebuf, 's')) &&
 85  			    isdigit(*(slice-1))) *slice = '\0';
 86  			fd = open(namebuf, oflags);
 87  			if (realpath)
 88  				*realpath = namebuf;
 89  		} else
 90  			errno = ENAMETOOLONG;
 91  	}
 92  	if (!slash && fd == -1 && errno == ENOENT) {
 93  		if (snprintf(namebuf, PATH_MAX, "%s%s%s",
 94  		    _PATH_DEV, prefix, path) < PATH_MAX) {
 95  			fd = open(namebuf, oflags);
 96  			if (realpath)
 97  				*realpath = namebuf;
 98  		} else
 99  			errno = ENAMETOOLONG;
100  	}
101  	return (fd);
102  }
103  
104  static void opendev_namebuf_init(void)
105  {
106  	namebuf = malloc(PATH_MAX);
107  }