/ src / add.c
add.c
  1  /*-
  2   * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
  3   * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
  4   * All rights reserved.
  5   *
  6   * Redistribution and use in source and binary forms, with or without
  7   * modification, are permitted provided that the following conditions
  8   * are met:
  9   * 1. Redistributions of source code must retain the above copyright
 10   *    notice, this list of conditions and the following disclaimer
 11   *    in this position and unchanged.
 12   * 2. Redistributions in binary form must reproduce the above copyright
 13   *    notice, this list of conditions and the following disclaimer in the
 14   *    documentation and/or other materials provided with the distribution.
 15   *
 16   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 17   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 18   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 19   * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 20   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 21   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 22   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 23   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 25   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 26   */
 27  
 28  #include <sys/param.h>
 29  
 30  #include <err.h>
 31  #include <errno.h>
 32  #include <stdio.h>
 33  #include <stdlib.h>
 34  #include <string.h>
 35  #include <unistd.h>
 36  #include <getopt.h>
 37  #include <xstring.h>
 38  
 39  #include <pkg.h>
 40  
 41  #include "pkgcli.h"
 42  
 43  static int
 44  is_url(const char * const pattern)
 45  {
 46  	if (strncmp(pattern, "http://", 7) == 0 ||
 47  		strncmp(pattern, "https://", 8) == 0 ||
 48  		strncmp(pattern, "file://", 7) == 0)
 49  		return (EPKG_OK);
 50  
 51  	return (EPKG_FATAL);
 52  }
 53  
 54  void
 55  usage_add(void)
 56  {
 57  	fprintf(stderr, "Usage: pkg add [-IAfqM] <pkg-name> ...\n");
 58  	fprintf(stderr, "       pkg add [-IAfqM] <protocol>://<path>/<pkg-name> ...\n\n");
 59  	fprintf(stderr, "For more information see 'pkg help add'.\n");
 60  }
 61  
 62  int
 63  exec_add(int argc, char **argv)
 64  {
 65  	struct pkgdb *db = NULL;
 66  	xstring *failedpkgs = NULL;
 67  	char path[MAXPATHLEN];
 68  	char *env, *file;
 69  	int retcode;
 70  	int ch;
 71  	int i;
 72  	int failedpkgcount = 0;
 73  	int scriptnoexec = 0;
 74  	pkg_flags f = PKG_FLAG_NONE;
 75  	const char *location = NULL;
 76  
 77  	/* options descriptor */
 78  	struct option longopts[] = {
 79  		{ "no-scripts",          no_argument,            NULL,           'I' },
 80  		{ "script-no-exec",      no_argument,            &scriptnoexec,  1 },
 81  		{ "automatic",           no_argument,            NULL,           'A' },
 82  		{ "force",               no_argument,            NULL,           'f' },
 83  		{ "accept-missing",      no_argument,            NULL,           'M' },
 84  		{ "quiet",               no_argument,            NULL,           'q' },
 85  		{ "relocate",            required_argument,      NULL,            1  },
 86  		{ NULL,                  0,                      NULL,            0  }
 87  	};
 88  
 89  	while ((ch = getopt_long(argc, argv, "+IAfqM", longopts, NULL)) != -1) {
 90  		switch (ch) {
 91  		case 'I':
 92  			f |= PKG_ADD_NOSCRIPT;
 93  			break;
 94  		case 'A':
 95  			f |= PKG_ADD_AUTOMATIC;
 96  			break;
 97  		case 'f':
 98  			f |= PKG_ADD_FORCE;
 99  			force = true;
100  			break;
101  		case 'M':
102  			f |= PKG_ADD_FORCE_MISSING;
103  			break;
104  		case 'q':
105  			quiet = true;
106  			break;
107  		case 1:
108  			location = optarg;
109  			break;
110  		case 0:
111  			if (scriptnoexec == 1)
112  				f |= PKG_ADD_NOEXEC;
113  			break;
114  		default:
115  			usage_add();
116  			return (EXIT_FAILURE);
117  		}
118  	}
119  	argc -= optind;
120  	argv += optind;
121  
122  	if (argc < 1) {
123  		usage_add();
124  		return (EXIT_FAILURE);
125  	}
126  
127  	retcode = pkgdb_access(PKGDB_MODE_READ  |
128  			       PKGDB_MODE_WRITE |
129  			       PKGDB_MODE_CREATE,
130  			       PKGDB_DB_LOCAL);
131  	if (retcode == EPKG_ENOACCESS) {
132  		warnx("Insufficient privileges to add packages");
133  		return (EXIT_FAILURE);
134  	} else if (retcode != EPKG_OK)
135  		return (EXIT_FAILURE);
136  
137  	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
138  		return (EXIT_FAILURE);
139  
140  	if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) {
141  		pkgdb_close(db);
142  		warnx("Cannot get an exclusive lock on a database, it is locked by another process");
143  		return (EXIT_FAILURE);
144  	}
145  
146  	failedpkgs = xstring_new();
147  	for (i = 0; i < argc; i++) {
148  		if (is_url(argv[i]) == EPKG_OK) {
149  			const char *name = strrchr(argv[i], '/');
150  			if (name == NULL)
151  				name = argv[i];
152  			else
153  				name++;
154  
155  			if ((env = getenv("TMPDIR")) == NULL)
156  				env = "/tmp";
157  			snprintf(path, sizeof(path), "%s/%s.XXXXX", env, name);
158  			if ((retcode = pkg_fetch_file(NULL, argv[i], path, 0, 0, 0)) != EPKG_OK)
159  				break;
160  
161  			file = path;
162  		} else {
163  			file = argv[i];
164  
165  			/* Special case: treat a filename of "-" as
166  			   meaning 'read from stdin.'  It doesn't make
167  			   sense to have a filename of "-" more than
168  			   once per command line, but we aren't
169  			   testing for that at the moment */
170  
171  			if (!STREQ(file, "-") && access(file, F_OK) != 0) {
172  				int saved_errno = errno;
173  				warn("%s", file);
174  				if (saved_errno == ENOENT)
175  					warnx("Was 'pkg install %s' meant?", file);
176  				fprintf(failedpkgs->fp, "%s", argv[i]);
177  				if (i != argc - 1)
178  					fprintf(failedpkgs->fp, ", ");
179  				failedpkgcount++;
180  				continue;
181  			}
182  
183  		}
184  
185  		if ((retcode = pkg_add(db, file, f, location)) != EPKG_OK) {
186  			fprintf(failedpkgs->fp, "%s", argv[i]);
187  			if (i != argc - 1)
188  				fprintf(failedpkgs->fp, ", ");
189  			failedpkgcount++;
190  		}
191  
192  		if (is_url(argv[i]) == EPKG_OK)
193  			unlink(file);
194  
195  	}
196  	pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE);
197  	pkgdb_close(db);
198  
199  	if(failedpkgcount > 0) {
200  		fflush(failedpkgs->fp);
201  		printf("\nFailed to install the following %d package(s): %s\n", failedpkgcount, failedpkgs->buf);
202  		retcode = EPKG_FATAL;
203  	}
204  	xstring_free(failedpkgs);
205  
206  	pkg_add_triggers();
207  	if (messages != NULL) {
208  		fflush(messages->fp);
209  		printf("%s", messages->buf);
210  	}
211  
212  	return (retcode == EPKG_OK ? EXIT_SUCCESS : EXIT_FAILURE);
213  }
214