/ src / shlib.c
shlib.c
  1  /*-
  2   * Copyright (c) 2012-2014 Matthew Seaman <matthew@FreeBSD.org>
  3   * 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   *    in this position and unchanged.
 11   * 2. Redistributions in binary form must reproduce the above copyright
 12   *    notice, this list of conditions and the following disclaimer in the
 13   *    documentation and/or other materials provided with the distribution.
 14   *
 15   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 16   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 17   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 18   * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 19   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 20   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 21   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 22   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 23   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 24   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 25   */
 26  
 27  #include <sys/param.h>
 28  
 29  #include <err.h>
 30  #include <getopt.h>
 31  #include <stdio.h>
 32  #include <pkg.h>
 33  #include <libgen.h>
 34  #include <stdlib.h>
 35  #include <string.h>
 36  #include <unistd.h>
 37  #include <ctype.h>
 38  
 39  #include "pkgcli.h"
 40  
 41  void
 42  usage_shlib(void)
 43  {
 44  	fprintf(stderr, "Usage: pkg shlib [-q] [-P|R] <library>\n\n");
 45  	fprintf(stderr, "For more information see 'pkg help shlib'.\n");
 46  }
 47  
 48  char *
 49  sanitize(char *buf, const char *src, size_t size)
 50  {
 51  	const char *sep;
 52  	char *dst = buf;
 53  
 54  	/* skip path */
 55  	if ((sep = strrchr(src, '/')) != NULL)
 56  		src = sep + 1;
 57  	/* copy src to dst */
 58  	while (size > 1) {
 59  		if (isspace((unsigned char)*src)) {
 60  			/* whitespace is not allowed */
 61  			return (NULL);
 62  		}
 63  		*dst++ = *src++;
 64  		if (*src == '\0')
 65  			break;
 66  		size--;
 67  	}
 68  	if (*src != '\0') {
 69  		/* src is longer than buf */
 70  		return (NULL);
 71  	}
 72  	*dst = '\0';
 73  
 74  	return (buf);
 75  }
 76  
 77  static int
 78  pkgs_providing_lib(struct pkgdb *db, const char *libname)
 79  {
 80  	struct pkgdb_it	*it = NULL;
 81  	struct pkg	*pkg = NULL;
 82  	int		 ret = EPKG_OK;
 83  	int		 count = 0;
 84  
 85  	if ((it = pkgdb_query_shlib_provide(db, libname)) == NULL) {
 86  		return (EPKG_FATAL);
 87  	}
 88  
 89  	while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC)) == EPKG_OK) {
 90  		if (count == 0 && !quiet)
 91  			printf("%s is provided by the following packages:\n",
 92  			       libname);
 93  		count++;
 94  		pkg_printf("%n-%v\n", pkg, pkg);
 95  	}
 96  
 97  	if (ret == EPKG_END) {
 98  		if (count == 0 && !quiet)
 99  			printf("No packages provide %s.\n", libname);
100  		ret = EPKG_OK;
101  	}
102  
103  	pkg_free(pkg);
104  	pkgdb_it_free(it);
105  
106  	return (ret);
107  }
108  
109  static int
110  pkgs_requiring_lib(struct pkgdb *db, const char *libname)
111  {
112  	struct pkgdb_it	*it = NULL;
113  	struct pkg	*pkg = NULL;
114  	int		 ret = EPKG_OK;
115  	int		 count = 0;
116  
117  	if ((it = pkgdb_query_shlib_require(db, libname)) == NULL) {
118  		return (EPKG_FATAL);
119  	}
120  
121  	while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC)) == EPKG_OK) {
122  		if (count == 0 && !quiet)
123  			printf("%s is linked to by the following packages:\n",
124  			       libname);
125  		count++;
126  		pkg_printf("%n-%v\n", pkg, pkg);
127  	}
128  
129  	if (ret == EPKG_END) {
130  		if (count == 0 && !quiet)
131  			printf("No packages require %s.\n", libname);
132  		ret = EPKG_OK;
133  	}
134  
135  	pkg_free(pkg);
136  	pkgdb_it_free(it);
137  
138  	return (ret);
139  }
140  
141  int
142  exec_shlib(int argc, char **argv)
143  {
144  	struct pkgdb	*db = NULL;
145  	char		 libname[MAXPATHLEN];
146  	int		 retcode = EPKG_OK;
147  	int		 ch;
148  	bool		 provides_only = false;
149  	bool		 requires_only = false;
150  
151  	struct option longopts[] = {
152  		{ "provides",	no_argument,	NULL,	'P' },
153  		{ "requires",	no_argument,	NULL,	'R' },
154  		{ "quiet" ,	no_argument,	NULL,	'q' },
155  		{ NULL,		0,		NULL,	0 },
156  	};
157  
158  	while ((ch = getopt_long(argc, argv, "+qPR", longopts, NULL)) != -1) {
159  		switch (ch) {
160  		case 'P':
161  			provides_only = true;
162  			break;
163  		case 'R':
164  			requires_only = true;
165  			break;
166  		case 'q':
167  			quiet = true;
168  			break;
169  		default:
170  			usage_shlib();
171  			return (EXIT_FAILURE);
172  		}
173  	}
174  	argc -= optind;
175  	argv += optind;
176  
177  	if (argc < 1 || (provides_only && requires_only)) {
178  		usage_shlib();
179  		return (EXIT_FAILURE);
180  	}
181  
182  	if (argc >= 2) {
183  		warnx("multiple libraries per run not allowed");
184  		return (EXIT_FAILURE);
185  	}
186  
187  	if (sanitize(libname, argv[0], sizeof(libname)) == NULL) {
188  		usage_shlib();
189  		return (EXIT_FAILURE);
190  	}
191  
192  	retcode = pkgdb_open(&db, PKGDB_DEFAULT_READONLY);
193  	if (retcode != EPKG_OK)
194  		return (EXIT_FAILURE);
195  
196  	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
197  		pkgdb_close(db);
198  		warnx("Cannot get a read lock on a database, it is locked by another process");
199  		return (EXIT_FAILURE);
200  	}
201  
202  	if (retcode == EPKG_OK && !requires_only)
203  		retcode = pkgs_providing_lib(db, libname);
204  
205  	if (retcode == EPKG_OK && !provides_only)
206  		retcode = pkgs_requiring_lib(db, libname);
207  
208  	if (retcode != EPKG_OK)
209  		retcode = (EXIT_FAILURE);
210  
211  	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
212  	pkgdb_close(db);
213  	return (retcode);
214  }