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