2 * Copyright (c) 2012 Baptiste Daroussin <bapt@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/elf_common.h>
32 #include <sys/endian.h>
36 #include <archive_entry.h>
50 #include "elf_tables.h"
52 #define _LOCALBASE "/usr/local"
53 #define _PKGS_URL "http://pkgbeta.FreeBSD.org"
56 elf_corres_to_string(struct _elf_corres *m, int e)
60 for (i = 0; m[i].string != NULL; i++)
68 pkg_get_myabi(char *dest, size_t sz)
86 if (elf_version(EV_CURRENT) == EV_NONE) {
87 warnx("ELF library initialization failed: %s",
92 if ((fd = open("/bin/sh", O_RDONLY)) < 0) {
97 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
99 warnx("elf_begin() failed: %s.", elf_errmsg(-1));
103 if (gelf_getehdr(elf, &elfhdr) == NULL) {
105 warn("getehdr() failed: %s.", elf_errmsg(-1));
109 while ((scn = elf_nextscn(elf, scn)) != NULL) {
110 if (gelf_getshdr(scn, &shdr) != &shdr) {
112 warn("getshdr() failed: %s.", elf_errmsg(-1));
116 if (shdr.sh_type == SHT_NOTE)
122 warn("failed to get the note section");
126 data = elf_getdata(scn, NULL);
129 memcpy(¬e, src, sizeof(Elf_Note));
130 src += sizeof(Elf_Note);
131 if (note.n_type == NT_VERSION)
133 src += note.n_namesz + note.n_descsz;
136 src += note.n_namesz;
137 if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
138 version = be32dec(src);
140 version = le32dec(src);
142 for (i = 0; osname[i] != '\0'; i++)
143 osname[i] = (char)tolower(osname[i]);
145 snprintf(dest, sz, "%s:%d:%s:%s",
146 osname, version / 100000,
147 elf_corres_to_string(mach_corres, (int)elfhdr.e_machine),
148 elf_corres_to_string(wordsize_corres,
149 (int)elfhdr.e_ident[EI_CLASS]));
153 switch (elfhdr.e_machine) {
155 snprintf(dest + strlen(dest), sz - strlen(dest),
156 ":%s:%s:%s", elf_corres_to_string(endian_corres,
157 (int)elfhdr.e_ident[EI_DATA]),
158 (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ?
160 (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ?
165 * this is taken from binutils sources:
167 * mapping is figured out from binutils:
168 * gas/config/tc-mips.c
170 switch (elfhdr.e_flags & EF_MIPS_ABI) {
178 if (elfhdr.e_ident[EI_DATA] ==
181 else if (elfhdr.e_ident[EI_DATA] ==
186 snprintf(dest + strlen(dest), sz - strlen(dest),
187 ":%s:%s", elf_corres_to_string(endian_corres,
188 (int)elfhdr.e_ident[EI_DATA]), abi);
201 extract_pkg_static(int fd, char *p, int sz)
204 struct archive_entry *ae;
209 a = archive_read_new();
211 warn("archive_read_new");
214 archive_read_support_compression_all(a);
215 archive_read_support_format_tar(a);
217 if (lseek(fd, 0, 0) == -1) {
222 if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
223 warnx("archive_read_open_fd: %s", archive_error_string(a));
228 while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
229 end = strrchr(archive_entry_pathname(ae), '/');
233 if (strcmp(end, "/pkg-static") == 0) {
234 r = archive_read_extract(a, ae,
235 ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
236 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
237 ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
238 strlcpy(p, archive_entry_pathname(ae), sz);
246 warnx("fail to extract pkg-static");
249 archive_read_finish(a);
255 install_pkg_static(char *path, char *pkgpath)
260 switch ((pid = fork())) {
264 execl(path, "pkg-static", "add", pkgpath, (char *)NULL);
270 while (waitpid(pid, &pstat, 0) == -1)
274 if (WEXITSTATUS(pstat))
275 return (WEXITSTATUS(pstat));
276 else if (WIFSIGNALED(pstat))
277 return (128 & (WTERMSIG(pstat)));
285 char url[MAXPATHLEN];
287 char tmppkg[MAXPATHLEN];
289 char pkgstatic[MAXPATHLEN];
301 printf("Bootstrapping pkg please wait\n");
303 if (pkg_get_myabi(abi, MAXPATHLEN) != 0) {
304 warnx("failed to determine the system ABI");
308 if (getenv("PACKAGESITE") != NULL)
309 snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", getenv("PACKAGESITE"));
311 snprintf(url, MAXPATHLEN, "%s/%s/latest/Latest/pkg.txz",
312 getenv("PACKAGEROOT") ? getenv("PACKAGEROOT") : _PKGS_URL,
313 getenv("ABI") ? getenv("ABI") : abi);
315 snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
316 getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
318 if ((fd = mkstemp(tmppkg)) == -1) {
325 remote = fetchXGetURL(url, &st, "");
328 } while (remote == NULL && retry-- > 0);
333 while (done < st.size) {
334 if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
337 if (write(fd, buf, r) != r) {
344 if (now > last || done == st.size)
351 if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
352 ret = install_pkg_static(pkgstatic, tmppkg);
357 warnx("Error fetching %s: %s", url, fetchLastErrString);
368 static const char confirmation_message[] =
369 "The package management tool is not yet installed on your system.\n"
370 "The mechanism for doing this is not secure on FreeBSD 9.1. To securely install\n"
371 "pkg(8), use ports from a portsnap checkout:\n"
372 " # portsnap fetch extract\n"
373 " # make -C /usr/ports/ports-mgmt/pkg install clean\n"
374 "Do you still want to fetch and install it now? [y/N]: ";
377 pkg_query_yes_no(void)
383 if (c == 'y' || c == 'Y')
388 while (c != '\n' && c != EOF)
395 main(__unused int argc, char *argv[])
397 char pkgpath[MAXPATHLEN];
399 snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
400 getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
402 if (access(pkgpath, X_OK) == -1) {
404 * Do not ask for confirmation if either of stdin or stdout is
405 * not tty. Check the environment to see if user has answer
406 * tucked in there already.
408 if (getenv("ASSUME_ALWAYS_YES") == NULL) {
409 printf("%s", confirmation_message);
410 if (!isatty(fileno(stdin)))
413 if (pkg_query_yes_no() == 0)
416 if (bootstrap_pkg() != 0)
420 execv(pkgpath, argv);
423 return (EXIT_FAILURE);