예제 #1
0
/**
 * Check the PGP signature for the given file path.
 * If base64_sig is provided, it will be used as the signature data after
 * decoding. If base64_sig is NULL, expect a signature file next to path
 * (e.g. "%s.sig").
 *
 * The return value will be 0 if nothing abnormal happened during the signature
 * check, and -1 if an error occurred while checking signatures or if a
 * signature could not be found; pm_errno will be set. Note that "abnormal"
 * does not include a failed signature; the value in siglist should be checked
 * to determine if the signature(s) are good.
 * @param handle the context handle
 * @param path the full path to a file
 * @param base64_sig optional PGP signature data in base64 encoding
 * @param siglist a pointer to storage for signature results
 * @return 0 in normal cases, -1 if the something failed in the check process
 */
int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
		const char *base64_sig, alpm_siglist_t *siglist)
{
	int ret = -1, sigcount;
	gpgme_error_t err = 0;
	gpgme_ctx_t ctx;
	gpgme_data_t filedata, sigdata;
	gpgme_verify_result_t verify_result;
	gpgme_signature_t gpgsig;
	char *sigpath = NULL;
	unsigned char *decoded_sigdata = NULL;
	FILE *file = NULL, *sigfile = NULL;

	if(!path || _alpm_access(handle, NULL, path, R_OK) != 0) {
		RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1);
	}

	if(!siglist) {
		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
	}
	siglist->count = 0;

	if(!base64_sig) {
		sigpath = _alpm_sigpath(handle, path);
		if(_alpm_access(handle, NULL, sigpath, R_OK) != 0
				|| (sigfile = fopen(sigpath, "rb")) == NULL) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n",
					sigpath);
			handle->pm_errno = ALPM_ERR_SIG_MISSING;
			goto error;
		}
	}

	/* does the file we are verifying exist? */
	file = fopen(path, "rb");
	if(file == NULL) {
		handle->pm_errno = ALPM_ERR_NOT_A_FILE;
		goto error;
	}

	if(init_gpgme(handle)) {
		/* pm_errno was set in gpgme_init() */
		goto error;
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path);

	memset(&ctx, 0, sizeof(ctx));
	memset(&sigdata, 0, sizeof(sigdata));
	memset(&filedata, 0, sizeof(filedata));

	err = gpgme_new(&ctx);
	CHECK_ERR();

	/* create our necessary data objects to verify the signature */
	err = gpgme_data_new_from_stream(&filedata, file);
	CHECK_ERR();

	/* next create data object for the signature */
	if(base64_sig) {
		/* memory-based, we loaded it from a sync DB */
		size_t data_len;
		int decode_ret = decode_signature(base64_sig,
				&decoded_sigdata, &data_len);
		if(decode_ret) {
			handle->pm_errno = ALPM_ERR_SIG_INVALID;
			goto gpg_error;
		}
		err = gpgme_data_new_from_mem(&sigdata,
				(char *)decoded_sigdata, data_len, 0);
	} else {
		/* file-based, it is on disk */
		err = gpgme_data_new_from_stream(&sigdata, sigfile);
	}
	CHECK_ERR();

	/* here's where the magic happens */
	err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
	CHECK_ERR();
	verify_result = gpgme_op_verify_result(ctx);
	CHECK_ERR();
	if(!verify_result || !verify_result->signatures) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n");
		handle->pm_errno = ALPM_ERR_SIG_MISSING;
		goto gpg_error;
	}
	for(gpgsig = verify_result->signatures, sigcount = 0;
			gpgsig; gpgsig = gpgsig->next, sigcount++);
	_alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount);

	CALLOC(siglist->results, sigcount, sizeof(alpm_sigresult_t),
			handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
	siglist->count = sigcount;

	for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig;
			gpgsig = gpgsig->next, sigcount++) {
		alpm_list_t *summary_list, *summary;
		alpm_sigstatus_t status;
		alpm_sigvalidity_t validity;
		gpgme_key_t key;
		alpm_sigresult_t *result;

		_alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr);
		summary_list = list_sigsum(gpgsig->summary);
		for(summary = summary_list; summary; summary = summary->next) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "summary: %s\n", (const char *)summary->data);
		}
		alpm_list_free(summary_list);
		_alpm_log(handle, ALPM_LOG_DEBUG, "status: %s\n", gpgme_strerror(gpgsig->status));
		_alpm_log(handle, ALPM_LOG_DEBUG, "timestamp: %lu\n", gpgsig->timestamp);
		_alpm_log(handle, ALPM_LOG_DEBUG, "exp_timestamp: %lu\n", gpgsig->exp_timestamp);
		_alpm_log(handle, ALPM_LOG_DEBUG, "validity: %s; reason: %s\n",
				string_validity(gpgsig->validity),
				gpgme_strerror(gpgsig->validity_reason));

		result = siglist->results + sigcount;
		err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0);
		if(gpg_err_code(err) == GPG_ERR_EOF) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
			err = GPG_ERR_NO_ERROR;
			/* we dupe the fpr in this case since we have no key to point at */
			STRDUP(result->key.fingerprint, gpgsig->fpr,
					handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
		} else {
예제 #2
0
파일: sync.c 프로젝트: vadmium/pacman-arch
/** Applies delta files to create an upgraded package file.
 *
 * All intermediate files are deleted, leaving only the starting and
 * ending package files.
 *
 * @param handle the context handle
 *
 * @return 0 if all delta files were able to be applied, 1 otherwise.
 */
static int apply_deltas(alpm_handle_t *handle)
{
	alpm_list_t *i;
	int deltas_found = 0, ret = 0;
	const char *cachedir = _alpm_filecache_setup(handle);
	alpm_trans_t *trans = handle->trans;

	for(i = trans->add; i; i = i->next) {
		alpm_pkg_t *spkg = i->data;
		alpm_list_t *delta_path = spkg->delta_path;
		alpm_list_t *dlts = NULL;

		if(!delta_path) {
			continue;
		}

		if(!deltas_found) {
			/* only show this if we actually have deltas to apply, and it is before
			 * the very first one */
			EVENT(handle, ALPM_EVENT_DELTA_PATCHES_START, NULL, NULL);
			deltas_found = 1;
		}

		for(dlts = delta_path; dlts; dlts = dlts->next) {
			alpm_delta_t *d = dlts->data;
			char *delta, *from, *to;
			char command[PATH_MAX];
			size_t len = 0;

			delta = _alpm_filecache_find(handle, d->delta);
			/* the initial package might be in a different cachedir */
			if(dlts == delta_path) {
				from = _alpm_filecache_find(handle, d->from);
			} else {
				/* len = cachedir len + from len + '/' + null */
				len = strlen(cachedir) + strlen(d->from) + 2;
				MALLOC(from, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1));
				snprintf(from, len, "%s/%s", cachedir, d->from);
			}
			len = strlen(cachedir) + strlen(d->to) + 2;
			MALLOC(to, len, free(from); RET_ERR(handle, ALPM_ERR_MEMORY, 1));
			snprintf(to, len, "%s/%s", cachedir, d->to);

			/* build the patch command */
			if(endswith(to, ".gz")) {
				/* special handling for gzip : we disable timestamp with -n option */
				snprintf(command, PATH_MAX, "xdelta3 -d -q -R -c -s %s %s | gzip -n > %s", from, delta, to);
			} else {
				snprintf(command, PATH_MAX, "xdelta3 -d -q -s %s %s %s", from, delta, to);
			}

			_alpm_log(handle, ALPM_LOG_DEBUG, "command: %s\n", command);

			EVENT(handle, ALPM_EVENT_DELTA_PATCH_START, d->to, d->delta);

			int retval = system(command);
			if(retval == 0) {
				EVENT(handle, ALPM_EVENT_DELTA_PATCH_DONE, NULL, NULL);

				/* delete the delta file */
				unlink(delta);

				/* Delete the 'from' package but only if it is an intermediate
				 * package. The starting 'from' package should be kept, just
				 * as if deltas were not used. */
				if(dlts != delta_path) {
					unlink(from);
				}
			}
			FREE(from);
			FREE(to);
			FREE(delta);

			if(retval != 0) {
				/* one delta failed for this package, cancel the remaining ones */
				EVENT(handle, ALPM_EVENT_DELTA_PATCH_FAILED, NULL, NULL);
				handle->pm_errno = ALPM_ERR_DLT_PATCHFAILED;
				ret = 1;
				break;
			}
		}
	}
	if(deltas_found) {
		EVENT(handle, ALPM_EVENT_DELTA_PATCHES_DONE, NULL, NULL);
	}

	return ret;
}
예제 #3
0
파일: be_local.c 프로젝트: moben/pacman
static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)
{
	FILE *fp = NULL;
	char line[1024];
	char *pkgpath;
	alpm_db_t *db = info->origin_data.db;

	/* bitmask logic here:
	 * infolevel: 00001111
	 * inforeq:   00010100
	 * & result:  00000100
	 * == to inforeq? nope, we need to load more info. */
	if((info->infolevel & inforeq) == inforeq) {
		/* already loaded all of this info, do nothing */
		return 0;
	}

	if(info->infolevel & INFRQ_ERROR) {
		/* We've encountered an error loading this package before. Don't attempt
		 * repeated reloads, just give up. */
		return -1;
	}

	_alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
			info->name, inforeq);

	pkgpath = _alpm_local_db_pkgpath(db, info, NULL);
	if(!pkgpath || access(pkgpath, F_OK)) {
		/* directory doesn't exist or can't be opened */
		_alpm_log(db->handle, ALPM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n",
				info->name, info->version, db->treename);
		goto error;
	}
	free(pkgpath);

	/* clear out 'line', to be certain - and to make valgrind happy */
	memset(line, 0, sizeof(line));

	/* DESC */
	if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) {
		char *path = _alpm_local_db_pkgpath(db, info, "desc");
		if(!path || (fp = fopen(path, "r")) == NULL) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
			free(path);
			goto error;
		}
		free(path);
		while(!feof(fp)) {
			if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) {
				goto error;
			}
			if(_alpm_strip_newline(line) == 0) {
				/* length of stripped line was zero */
				continue;
			}
			if(strcmp(line, "%NAME%") == 0) {
				READ_NEXT();
				if(strcmp(line, info->name) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
								"mismatch on package %s\n"), db->treename, info->name);
				}
			} else if(strcmp(line, "%VERSION%") == 0) {
				READ_NEXT();
				if(strcmp(line, info->version) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
								"mismatch on package %s\n"), db->treename, info->name);
				}
			} else if(strcmp(line, "%DESC%") == 0) {
				READ_AND_STORE(info->desc);
			} else if(strcmp(line, "%GROUPS%") == 0) {
				READ_AND_STORE_ALL(info->groups);
			} else if(strcmp(line, "%URL%") == 0) {
				READ_AND_STORE(info->url);
			} else if(strcmp(line, "%LICENSE%") == 0) {
				READ_AND_STORE_ALL(info->licenses);
			} else if(strcmp(line, "%ARCH%") == 0) {
				READ_AND_STORE(info->arch);
			} else if(strcmp(line, "%BUILDDATE%") == 0) {
				READ_NEXT();
				info->builddate = _alpm_parsedate(line);
			} else if(strcmp(line, "%INSTALLDATE%") == 0) {
				READ_NEXT();
				info->installdate = _alpm_parsedate(line);
			} else if(strcmp(line, "%PACKAGER%") == 0) {
				READ_AND_STORE(info->packager);
			} else if(strcmp(line, "%REASON%") == 0) {
				READ_NEXT();
				info->reason = (alpm_pkgreason_t)atoi(line);
			} else if(strcmp(line, "%SIZE%") == 0) {
				READ_NEXT();
				info->isize = _alpm_strtoofft(line);
			} else if(strcmp(line, "%REPLACES%") == 0) {
				READ_AND_SPLITDEP(info->replaces);
			} else if(strcmp(line, "%DEPENDS%") == 0) {
				READ_AND_SPLITDEP(info->depends);
			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
				READ_AND_STORE_ALL(info->optdepends);
			} else if(strcmp(line, "%CONFLICTS%") == 0) {
				READ_AND_SPLITDEP(info->conflicts);
			} else if(strcmp(line, "%PROVIDES%") == 0) {
				READ_AND_SPLITDEP(info->provides);
			}
		}
		fclose(fp);
		fp = NULL;
		info->infolevel |= INFRQ_DESC;
	}

	/* FILES */
	if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) {
		char *path = _alpm_local_db_pkgpath(db, info, "files");
		if(!path || (fp = fopen(path, "r")) == NULL) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
			free(path);
			goto error;
		}
		free(path);
		while(fgets(line, sizeof(line), fp)) {
			_alpm_strip_newline(line);
			if(strcmp(line, "%FILES%") == 0) {
				size_t files_count = 0, files_size = 0;
				alpm_file_t *files = NULL;

				while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) {
					if(files_count >= files_size) {
						size_t old_size = files_size;
						if(files_size == 0) {
							files_size = 8;
						} else {
							files_size *= 2;
						}
						files = realloc(files, sizeof(alpm_file_t) * files_size);
						if(!files) {
							ALLOC_FAIL(sizeof(alpm_file_t) * files_size);
							goto error;
						}
						/* ensure all new memory is zeroed out, in both the initial
						 * allocation and later reallocs */
						memset(files + old_size, 0,
								sizeof(alpm_file_t) * (files_size - old_size));
					}
					STRDUP(files[files_count].name, line, goto error);
					/* TODO: lstat file, get mode/size */
					files_count++;
				}
				/* attempt to hand back any memory we don't need */
				files = realloc(files, sizeof(alpm_file_t) * files_count);
				info->files.count = files_count;
				info->files.files = files;
			} else if(strcmp(line, "%BACKUP%") == 0) {
예제 #4
0
파일: remove.c 프로젝트: JohnFrazier/pacman
/**
 * @brief Remove a package's files, optionally skipping its replacement's
 * files.
 *
 * @param handle the context handle
 * @param oldpkg package to remove
 * @param newpkg package to replace \a oldpkg (optional)
 * @param targ_count current index within the transaction (1-based)
 * @param pkg_count the number of packages affected by the transaction
 *
 * @return 0 on success, -1 if alpm lacks permission to delete some of the
 * files, >0 the number of files alpm was unable to delete
 */
static int remove_package_files(alpm_handle_t *handle,
		alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg,
		size_t targ_count, size_t pkg_count)
{
	alpm_list_t *skip_remove;
	alpm_filelist_t *filelist;
	size_t i;
	int err = 0;
	int nosave = handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE;

	if(newpkg) {
		alpm_filelist_t *newfiles;
		alpm_list_t *b;
		skip_remove = alpm_list_join(
				alpm_list_strdup(handle->trans->skip_remove),
				alpm_list_strdup(handle->noupgrade));
		/* Add files in the NEW backup array to the skip_remove array
		 * so this removal operation doesn't kill them */
		/* old package backup list */
		newfiles = alpm_pkg_get_files(newpkg);
		for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) {
			const alpm_backup_t *backup = b->data;
			/* safety check (fix the upgrade026 pactest) */
			if(!alpm_filelist_contains(newfiles, backup->name)) {
				continue;
			}
			_alpm_log(handle, ALPM_LOG_DEBUG, "adding %s to the skip_remove array\n",
					backup->name);
			skip_remove = alpm_list_add(skip_remove, strdup(backup->name));
		}
	} else {
		skip_remove = alpm_list_strdup(handle->trans->skip_remove);
	}

	filelist = alpm_pkg_get_files(oldpkg);
	for(i = 0; i < filelist->count; i++) {
		alpm_file_t *file = filelist->files + i;
		if(!can_remove_file(handle, file, skip_remove)) {
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"not removing package '%s', can't remove all files\n",
					oldpkg->name);
			FREELIST(skip_remove);
			RET_ERR(handle, ALPM_ERR_PKG_CANT_REMOVE, -1);
		}
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "removing %zd files\n", filelist->count);

	if(!newpkg) {
		/* init progress bar, but only on true remove transactions */
		PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 0,
				pkg_count, targ_count);
	}

	/* iterate through the list backwards, unlinking files */
	for(i = filelist->count; i > 0; i--) {
		alpm_file_t *file = filelist->files + i - 1;
		if(unlink_file(handle, oldpkg, newpkg, file, skip_remove, nosave) < 0) {
			err++;
		}

		if(!newpkg) {
			/* update progress bar after each file */
			int percent = ((filelist->count - i) * 100) / filelist->count;
			PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name,
					percent, pkg_count, targ_count);
		}
	}
	FREELIST(skip_remove);

	if(!newpkg) {
		/* set progress to 100% after we finish unlinking files */
		PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 100,
				pkg_count, targ_count);
	}

	return err;
}
예제 #5
0
파일: sync.c 프로젝트: vadmium/pacman-arch
/** Compute the size of the files that will be downloaded to install a
 * package.
 * @param newpkg the new package to upgrade to
 */
static int compute_download_size(alpm_pkg_t *newpkg)
{
	const char *fname;
	char *fpath, *fnamepart = NULL;
	off_t size = 0;
	alpm_handle_t *handle = newpkg->handle;
	int ret = 0;

	if(newpkg->origin != ALPM_PKG_FROM_SYNCDB) {
		newpkg->infolevel |= INFRQ_DSIZE;
		newpkg->download_size = 0;
		return 0;
	}

	ASSERT(newpkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1));
	fname = newpkg->filename;
	fpath = _alpm_filecache_find(handle, fname);

	/* downloaded file exists, so there's nothing to grab */
	if(fpath) {
		size = 0;
		goto finish;
	}

	CALLOC(fnamepart, strlen(fname) + 6, sizeof(char), return -1);
	sprintf(fnamepart, "%s.part", fname);
	fpath = _alpm_filecache_find(handle, fnamepart);
	if(fpath) {
		struct stat st;
		if(stat(fpath, &st) == 0) {
			/* subtract the size of the .part file */
			_alpm_log(handle, ALPM_LOG_DEBUG, "using (package - .part) size\n");
			size = newpkg->size - st.st_size;
			size = size < 0 ? 0 : size;
		}

		/* tell the caller that we have a partial */
		ret = 1;
	} else if(handle->deltaratio > 0.0) {
		off_t dltsize;

		dltsize = _alpm_shortest_delta_path(handle, newpkg->deltas,
				newpkg->filename, &newpkg->delta_path);

		if(newpkg->delta_path && (dltsize < newpkg->size * handle->deltaratio)) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n");
			size = dltsize;
		} else {
			_alpm_log(handle, ALPM_LOG_DEBUG, "using package size\n");
			size = newpkg->size;
			alpm_list_free(newpkg->delta_path);
			newpkg->delta_path = NULL;
		}
	} else {
		size = newpkg->size;
	}

finish:
	_alpm_log(handle, ALPM_LOG_DEBUG, "setting download size %jd for pkg %s\n",
			(intmax_t)size, newpkg->name);

	newpkg->infolevel |= INFRQ_DSIZE;
	newpkg->download_size = size;

	FREE(fpath);
	FREE(fnamepart);

	return ret;
}
예제 #6
0
파일: dload.c 프로젝트: 7799/pacman
/** Fetch a remote pkg. */
char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url)
{
	char *filepath;
	const char *cachedir;
	char *final_file = NULL, *final_pkg_url = NULL;
	struct dload_payload payload;
	int ret = 0;

	CHECK_HANDLE(handle, return NULL);
	ASSERT(url, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL));

	/* find a valid cache dir to download to */
	cachedir = _alpm_filecache_setup(handle);

	memset(&payload, 0, sizeof(struct dload_payload));

	/* attempt to find the file in our pkgcache */
	filepath = filecache_find_url(handle, url);
	if(filepath == NULL) {
		STRDUP(payload.fileurl, url, RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
		payload.allow_resume = 1;
		payload.handle = handle;
		payload.trust_remote_name = 1;

		/* download the file */
		ret = _alpm_download(&payload, cachedir, &final_file, &final_pkg_url);
		_alpm_dload_payload_reset(&payload);
		if(ret == -1) {
			_alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url);
			free(final_file);
			return NULL;
		}
		_alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url);
	}

	/* attempt to download the signature */
	if(ret == 0 && final_pkg_url && (handle->siglevel & ALPM_SIG_PACKAGE)) {
		char *sig_filepath, *sig_final_file = NULL;
		size_t len;

		len = strlen(final_pkg_url) + 5;
		MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
		snprintf(payload.fileurl, len, "%s.sig", final_pkg_url);

		sig_filepath = filecache_find_url(handle, payload.fileurl);
		if(sig_filepath == NULL) {
			payload.handle = handle;
			payload.trust_remote_name = 1;
			payload.force = 1;
			payload.errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL);

			/* set hard upper limit of 16KiB */
			payload.max_size = 16 * 1024;

			ret = _alpm_download(&payload, cachedir, &sig_final_file, NULL);
			if(ret == -1 && !payload.errors_ok) {
				_alpm_log(handle, ALPM_LOG_WARNING,
						_("failed to download %s\n"), payload.fileurl);
				/* Warn now, but don't return NULL. We will fail later during package
				 * load time. */
			} else if(ret == 0) {
				_alpm_log(handle, ALPM_LOG_DEBUG,
						"successfully downloaded %s\n", payload.fileurl);
			}
			FREE(sig_final_file);
		}
		free(sig_filepath);
		_alpm_dload_payload_reset(&payload);
	}

	/* we should be able to find the file the second time around */
	if(filepath == NULL) {
		filepath = _alpm_filecache_find(handle, final_file);
	}
	free(final_file);

	return filepath;
}
예제 #7
0
파일: remove.c 프로젝트: JohnFrazier/pacman
static void shift_pacsave(alpm_handle_t *handle, const char *file)
{
	DIR *dir = NULL;
	struct dirent *ent;
	struct stat st;
	regex_t reg;

	const char *basename;
	char *dirname;
	char oldfile[PATH_MAX];
	char newfile[PATH_MAX];
	char regstr[PATH_MAX];

	unsigned long log_max = 0;
	size_t basename_len;

	dirname = mdirname(file);
	if(!dirname) {
		return;
	}

	basename = mbasename(file);
	basename_len = strlen(basename);

	snprintf(regstr, PATH_MAX, "^%s\\.pacsave\\.([[:digit:]]+)$", basename);
	if(regcomp(&reg, regstr, REG_EXTENDED | REG_NEWLINE) != 0) {
		goto cleanup;
	}

	dir = opendir(dirname);
	if(dir == NULL) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not open directory: %s: %s\n"),
							dirname, strerror(errno));
		goto cleanup;
	}

	while((ent = readdir(dir)) != NULL) {
		if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
			continue;
		}

		if(regexec(&reg, ent->d_name, 0, 0, 0) == 0) {
			unsigned long cur_log;
			cur_log = strtoul(ent->d_name + basename_len + strlen(".pacsave."), NULL, 10);
			if(cur_log > log_max) {
				log_max = cur_log;
			}
		}
	}

	/* Shift pacsaves */
	unsigned long i;
	for(i = log_max + 1; i > 1; i--) {
		snprintf(oldfile, PATH_MAX, "%s.pacsave.%lu", file, i-1);
		snprintf(newfile, PATH_MAX, "%s.pacsave.%lu", file, i);
		rename(oldfile, newfile);
	}

	snprintf(oldfile, PATH_MAX, "%s.pacsave", file);
	if(stat(oldfile, &st) == 0) {
		snprintf(newfile, PATH_MAX, "%s.1", oldfile);
		rename(oldfile, newfile);
	}

	regfree(&reg);

cleanup:
	free(dirname);
	closedir(dir);
}
예제 #8
0
파일: add.c 프로젝트: jhuntwork/pacman
static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
		struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
{
	const char *entryname;
	mode_t entrymode;
	char filename[PATH_MAX]; /* the actual file we're extracting */
	int needbackup = 0, notouch = 0;
	const char *hash_orig = NULL;
	char *entryname_orig = NULL;
	int errors = 0;

	entryname = archive_entry_pathname(entry);
	entrymode = archive_entry_mode(entry);

	if(strcmp(entryname, ".INSTALL") == 0) {
		/* the install script goes inside the db */
		snprintf(filename, PATH_MAX, "%s%s-%s/install",
				_alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
		archive_entry_set_perm(entry, 0644);
	} else if(strcmp(entryname, ".CHANGELOG") == 0) {
		/* the changelog goes inside the db */
		snprintf(filename, PATH_MAX, "%s%s-%s/changelog",
				_alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
		archive_entry_set_perm(entry, 0644);
	} else if(strcmp(entryname, ".MTREE") == 0) {
		/* the mtree file goes inside the db */
		snprintf(filename, PATH_MAX, "%s%s-%s/mtree",
				_alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
		archive_entry_set_perm(entry, 0644);
	} else if(*entryname == '.') {
		/* for now, ignore all files starting with '.' that haven't
		 * already been handled (for future possibilities) */
		_alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname);
		archive_read_data_skip(archive);
		return 0;
	} else {
		/* build the new entryname relative to handle->root */
		snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
	}

	/* if a file is in NoExtract then we never extract it */
	if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract,"
				" skipping extraction of %s\n",
				entryname, filename);
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"note: %s is in NoExtract, skipping extraction\n", entryname);
		archive_read_data_skip(archive);
		return 0;
	}

	/* Check for file existence. This is one of the more crucial parts
	 * to get 'right'. Here are the possibilities, with the filesystem
	 * on the left and the package on the top:
	 * (F=file, N=node, S=symlink, D=dir)
	 *               |  F/N  |   D
	 *  non-existent |   1   |   2
	 *  F/N          |   3   |   4
	 *  D            |   5   |   6
	 *
	 *  1,2- extract, no magic necessary. lstat (_alpm_lstat) will fail here.
	 *  3,4- conflict checks should have caught this. either overwrite
	 *      or backup the file.
	 *  5- file replacing directory- don't allow it.
	 *  6- skip extraction, dir already exists.
	 */

	struct stat lsbuf;
	if(_alpm_lstat(filename, &lsbuf) != 0) {
		/* cases 1,2: file doesn't exist, skip all backup checks */
	} else {
		if(S_ISDIR(lsbuf.st_mode)) {
			if(S_ISDIR(entrymode)) {
				uid_t entryuid = archive_entry_uid(entry);
				gid_t entrygid = archive_entry_gid(entry);

				/* case 6: existing dir, ignore it */
				if(lsbuf.st_mode != entrymode) {
					/* if filesystem perms are different than pkg perms, warn user */
					mode_t mask = 07777;
					_alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
							"filesystem: %o  package: %o\n"), filename, lsbuf.st_mode & mask,
							entrymode & mask);
					alpm_logaction(handle, ALPM_CALLER_PREFIX,
							"warning: directory permissions differ on %s\n"
							"filesystem: %o  package: %o\n", filename, lsbuf.st_mode & mask,
							entrymode & mask);
				}

				if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) {
					_alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n"
							"filesystem: %u:%u  package: %u:%u\n"), filename,
							lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
					alpm_logaction(handle, ALPM_CALLER_PREFIX,
							"warning: directory ownership differs on %s\n"
							"filesystem: %u:%u  package: %u:%u\n", filename,
							lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
				}

				_alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
						filename);
				archive_read_data_skip(archive);
				return 0;
			} else {
				/* case 5: trying to overwrite dir with file, don't allow it */
				_alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
						filename);
				archive_read_data_skip(archive);
				return 1;
			}
		} else if(S_ISDIR(entrymode)) {
			/* case 4: trying to overwrite file with dir */
			_alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
					filename);
		} else {
			/* case 3: */
			/* if file is in NoUpgrade, don't touch it */
			if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) {
				notouch = 1;
			} else {
				alpm_backup_t *backup;
				/* go to the backup array and see if our conflict is there */
				/* check newpkg first, so that adding backup files is retroactive */
				backup = _alpm_needbackup(entryname, newpkg);
				if(backup) {
					needbackup = 1;
				}

				/* check oldpkg for a backup entry, store the hash if available */
				if(oldpkg) {
					backup = _alpm_needbackup(entryname, oldpkg);
					if(backup) {
						hash_orig = backup->hash;
						needbackup = 1;
					}
				}
			}
		}
	}

	/* we need access to the original entryname later after calls to
	 * archive_entry_set_pathname(), so we need to dupe it and free() later */
	STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1));

	if(needbackup) {
		char *checkfile;
		char *hash_local = NULL, *hash_pkg = NULL;
		size_t len;

		len = strlen(filename) + 10;
		MALLOC(checkfile, len,
				errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
		snprintf(checkfile, len, "%s.paccheck", filename);

		if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) {
			errors++;
			goto needbackup_cleanup;
		}

		hash_local = alpm_compute_md5sum(filename);
		hash_pkg = alpm_compute_md5sum(checkfile);

		/* update the md5 hash in newpkg's backup (it will be the new original) */
		alpm_list_t *i;
		for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) {
			alpm_backup_t *backup = i->data;
			char *newhash;
			if(!backup->name || strcmp(backup->name, entryname_orig) != 0) {
				continue;
			}
			STRDUP(newhash, hash_pkg, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
			FREE(backup->hash);
			backup->hash = newhash;
		}

		_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig);
		_alpm_log(handle, ALPM_LOG_DEBUG, "current:  %s\n", hash_local);
		_alpm_log(handle, ALPM_LOG_DEBUG, "new:      %s\n", hash_pkg);
		_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);

		if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
			/* local and new files are the same, updating anyway to get
			 * correct timestamps */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					entryname_orig);
			if(try_rename(handle, checkfile, filename)) {
				errors++;
			}
		} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
			/* original and new files are the same, leave the local version alone,
			 * including any user changes */
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"action: leaving existing file in place\n");
			unlink(checkfile);
		} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
			/* installed file has NOT been changed by user,
			 * update to the new version */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					entryname_orig);
			if(try_rename(handle, checkfile, filename)) {
				errors++;
			}
		} else {
			/* none of the three files matched another, unpack the new file alongside
			 * the local file */

			if(oldpkg) {
				char *newpath;
				size_t newlen = strlen(filename) + strlen(".pacnew") + 1;

				_alpm_log(handle, ALPM_LOG_DEBUG,
						"action: keeping current file and installing"
						" new one with .pacnew ending\n");

				MALLOC(newpath, newlen,
						errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
				snprintf(newpath, newlen, "%s.pacnew", filename);

				if(try_rename(handle, checkfile, newpath)) {
					errors++;
				} else {
					_alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"),
							filename, newpath);
					alpm_logaction(handle, ALPM_CALLER_PREFIX,
							"warning: %s installed as %s\n", filename, newpath);
				}

				free(newpath);
			} else {
				char *newpath;
				size_t newlen = strlen(filename) + strlen(".pacorig") + 1;

				_alpm_log(handle, ALPM_LOG_DEBUG,
						"action: saving existing file with a .pacorig ending"
						" and installing a new one\n");

				MALLOC(newpath, newlen,
						errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
				snprintf(newpath, newlen, "%s.pacorig", filename);

				/* move the existing file to the "pacorig" */
				if(try_rename(handle, filename, newpath)) {
					errors++;   /* failed rename filename  -> filename.pacorig */
					errors++;   /* failed rename checkfile -> filename */
				} else {
					/* rename the file we extracted to the real name */
					if(try_rename(handle, checkfile, filename)) {
						errors++;
					} else {
						_alpm_log(handle, ALPM_LOG_WARNING,
								_("%s saved as %s\n"), filename, newpath);
						alpm_logaction(handle, ALPM_CALLER_PREFIX,
								"warning: %s saved as %s\n", filename, newpath);
					}
				}

				free(newpath);
			}
		}

needbackup_cleanup:
		free(checkfile);
		free(hash_local);
		free(hash_pkg);
	} else {
예제 #9
0
static int sync_db_read(alpm_db_t *db, struct archive *archive,
		struct archive_entry *entry, alpm_pkg_t **likely_pkg)
{
	const char *entryname, *filename;
	alpm_pkg_t *pkg;
	struct archive_read_buffer buf;

	entryname = archive_entry_pathname(entry);
	if(entryname == NULL) {
		_alpm_log(db->handle, ALPM_LOG_DEBUG,
				"invalid archive entry provided to _alpm_sync_db_read, skipping\n");
		return -1;
	}

	_alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data from archive entry %s\n",
			entryname);

	memset(&buf, 0, sizeof(buf));
	/* 512K for a line length seems reasonable */
	buf.max_line_size = 512 * 1024;

	pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);

	if(pkg == NULL) {
		_alpm_log(db->handle, ALPM_LOG_DEBUG,
				"entry %s could not be loaded into %s sync database",
				entryname, db->treename);
		return -1;
	}

	if(filename == NULL) {
		/* A file exists outside of a subdirectory. This isn't a read error, so return
		 * success and try to continue on. */
		_alpm_log(db->handle, ALPM_LOG_WARNING, _("unknown database file: %s\n"),
				filename);
		return 0;
	}

	if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
			|| strcmp(filename, "files") == 0
			|| (strcmp(filename, "deltas") == 0 && db->handle->deltaratio > 0.0) ) {
		int ret;
		while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
			char *line = buf.line;
			if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
				/* length of stripped line was zero */
				continue;
			}

			if(strcmp(line, "%NAME%") == 0) {
				READ_NEXT();
				if(strcmp(line, pkg->name) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
								"mismatch on package %s\n"), db->treename, pkg->name);
				}
			} else if(strcmp(line, "%VERSION%") == 0) {
				READ_NEXT();
				if(strcmp(line, pkg->version) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
								"mismatch on package %s\n"), db->treename, pkg->name);
				}
			} else if(strcmp(line, "%FILENAME%") == 0) {
				READ_AND_STORE(pkg->filename);
				if(_alpm_validate_filename(db, pkg->name, pkg->filename) < 0) {
					return -1;
				}
			} else if(strcmp(line, "%BASE%") == 0) {
				READ_AND_STORE(pkg->base);
			} else if(strcmp(line, "%DESC%") == 0) {
				READ_AND_STORE(pkg->desc);
			} else if(strcmp(line, "%GROUPS%") == 0) {
				READ_AND_STORE_ALL(pkg->groups);
			} else if(strcmp(line, "%URL%") == 0) {
				READ_AND_STORE(pkg->url);
			} else if(strcmp(line, "%LICENSE%") == 0) {
				READ_AND_STORE_ALL(pkg->licenses);
			} else if(strcmp(line, "%ARCH%") == 0) {
				READ_AND_STORE(pkg->arch);
			} else if(strcmp(line, "%BUILDDATE%") == 0) {
				READ_NEXT();
				pkg->builddate = _alpm_parsedate(line);
			} else if(strcmp(line, "%PACKAGER%") == 0) {
				READ_AND_STORE(pkg->packager);
			} else if(strcmp(line, "%CSIZE%") == 0) {
				READ_NEXT();
				pkg->size = _alpm_strtoofft(line);
			} else if(strcmp(line, "%ISIZE%") == 0) {
				READ_NEXT();
				pkg->isize = _alpm_strtoofft(line);
			} else if(strcmp(line, "%MD5SUM%") == 0) {
				READ_AND_STORE(pkg->md5sum);
			} else if(strcmp(line, "%SHA256SUM%") == 0) {
				READ_AND_STORE(pkg->sha256sum);
			} else if(strcmp(line, "%PGPSIG%") == 0) {
				READ_AND_STORE(pkg->base64_sig);
			} else if(strcmp(line, "%REPLACES%") == 0) {
				READ_AND_SPLITDEP(pkg->replaces);
			} else if(strcmp(line, "%DEPENDS%") == 0) {
				READ_AND_SPLITDEP(pkg->depends);
			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
				READ_AND_SPLITDEP(pkg->optdepends);
			} else if(strcmp(line, "%MAKEDEPENDS%") == 0) {
				/* currently unused */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
				}
			} else if(strcmp(line, "%CHECKDEPENDS%") == 0) {
				/* currently unused */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
				}
			} else if(strcmp(line, "%CONFLICTS%") == 0) {
				READ_AND_SPLITDEP(pkg->conflicts);
			} else if(strcmp(line, "%PROVIDES%") == 0) {
				READ_AND_SPLITDEP(pkg->provides);
			} else if(strcmp(line, "%DELTAS%") == 0) {
				/* Different than the rest because of the _alpm_delta_parse call. */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
					pkg->deltas = alpm_list_add(pkg->deltas,
							_alpm_delta_parse(db->handle, line));
				}
			} else if(strcmp(line, "%FILES%") == 0) {
				/* TODO: this could lazy load if there is future demand */
				size_t files_count = 0, files_size = 0;
				alpm_file_t *files = NULL;

				while(1) {
					if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) {
						goto error;
					}
					line = buf.line;
					if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
						break;
					}

					if(!_alpm_greedy_grow((void **)&files, &files_size,
								(files_count ? (files_count + 1) * sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
						goto error;
					}
					STRDUP(files[files_count].name, line, goto error);
					files_count++;
				}
				/* attempt to hand back any memory we don't need */
				files = realloc(files, sizeof(alpm_file_t) * files_count);
				/* make sure the list is sorted */
				qsort(files, files_count, sizeof(alpm_file_t), _alpm_files_cmp);
				pkg->files.count = files_count;
				pkg->files.files = files;
			}
		}
예제 #10
0
파일: be_sync.c 프로젝트: moben/pacman
static int sync_db_populate(alpm_db_t *db)
{
	const char *dbpath;
	size_t est_count;
	int count = 0;
	struct stat buf;
	struct archive *archive;
	struct archive_entry *entry;
	alpm_pkg_t *pkg = NULL;

	if(db->status & DB_STATUS_INVALID) {
		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
	}
	if(db->status & DB_STATUS_MISSING) {
		RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
	}

	if((archive = archive_read_new()) == NULL) {
		RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1);
	}

	archive_read_support_compression_all(archive);
	archive_read_support_format_all(archive);

	dbpath = _alpm_db_path(db);
	if(!dbpath) {
		/* pm_errno set in _alpm_db_path() */
		return -1;
	}

	_alpm_log(db->handle, ALPM_LOG_DEBUG, "opening database archive %s\n", dbpath);

	if(archive_read_open_filename(archive, dbpath,
				ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
		_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath,
				archive_error_string(archive));
		archive_read_finish(archive);
		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
	}
	if(stat(dbpath, &buf) != 0) {
		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
	}
	est_count = estimate_package_count(&buf, archive);

	/* initialize hash at 66% full */
	db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);
	if(db->pkgcache == NULL) {
		RET_ERR(db->handle, ALPM_ERR_MEMORY, -1);
	}

	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
		mode_t mode = archive_entry_mode(entry);
		if(S_ISDIR(mode)) {
			continue;
		} else {
			/* we have desc, depends or deltas - parse it */
			if(sync_db_read(db, archive, entry, &pkg) != 0) {
				_alpm_log(db->handle, ALPM_LOG_ERROR,
						_("could not parse package description file '%s' from db '%s'\n"),
						archive_entry_pathname(entry), db->treename);
				continue;
			}
		}
	}

	count = alpm_list_count(db->pkgcache->list);

	if(count > 0) {
		db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
	}
	archive_read_finish(archive);
	_alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n",
			count, db->treename);

	return count;
}
예제 #11
0
파일: be_sync.c 프로젝트: moben/pacman
static int sync_db_validate(alpm_db_t *db)
{
	alpm_siglevel_t level;
	const char *dbpath;

	if(db->status & DB_STATUS_VALID || db->status & DB_STATUS_MISSING) {
		return 0;
	}
	if(db->status & DB_STATUS_INVALID) {
		db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
		return -1;
	}

	dbpath = _alpm_db_path(db);
	if(!dbpath) {
		/* pm_errno set in _alpm_db_path() */
		return -1;
	}

	/* we can skip any validation if the database doesn't exist */
	if(access(dbpath, R_OK) != 0 && errno == ENOENT) {
		db->status &= ~DB_STATUS_EXISTS;
		db->status |= DB_STATUS_MISSING;
		_alpm_log(db->handle, ALPM_LOG_WARNING,
				"database file for '%s' does not exist\n", db->treename);
		goto valid;
	}
	db->status |= DB_STATUS_EXISTS;
	db->status &= ~DB_STATUS_MISSING;

	/* this takes into account the default verification level if UNKNOWN
	 * was assigned to this db */
	level = alpm_db_get_siglevel(db);

	if(level & ALPM_SIG_DATABASE) {
		int retry, ret;
		do {
			retry = 0;
			alpm_siglist_t *siglist;
			ret = _alpm_check_pgp_helper(db->handle, dbpath, NULL,
					level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_DATABASE_MARGINAL_OK,
					level & ALPM_SIG_DATABASE_UNKNOWN_OK, &siglist);
			if(ret) {
				retry = _alpm_process_siglist(db->handle, db->treename, siglist,
						level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_DATABASE_MARGINAL_OK,
						level & ALPM_SIG_DATABASE_UNKNOWN_OK);
			}
			alpm_siglist_cleanup(siglist);
			free(siglist);
		} while(retry);

		if(ret) {
			db->status &= ~DB_STATUS_VALID;
			db->status |= DB_STATUS_INVALID;
			db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
			return 1;
		}
	}

valid:
	db->status |= DB_STATUS_VALID;
	db->status &= ~DB_STATUS_INVALID;
	return 0;
}
예제 #12
0
int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
{
    FILE *fp = NULL;
    char path[PATH_MAX];
    char line[1024];
    char *pkgpath = NULL;

    if(info == NULL || info->name == NULL || info->version == NULL) {
        _alpm_log(db->handle, PM_LOG_DEBUG,
                  "invalid package entry provided to _alpm_local_db_read, skipping\n");
        return -1;
    }

    if(info->origin != PKG_FROM_LOCALDB) {
        _alpm_log(db->handle, PM_LOG_DEBUG,
                  "request to read info for a non-local package '%s', skipping...\n",
                  info->name);
        return -1;
    }

    /* bitmask logic here:
     * infolevel: 00001111
     * inforeq:   00010100
     * & result:  00000100
     * == to inforeq? nope, we need to load more info. */
    if((info->infolevel & inforeq) == inforeq) {
        /* already loaded all of this info, do nothing */
        return 0;
    }
    _alpm_log(db->handle, PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
              info->name, inforeq);

    /* clear out 'line', to be certain - and to make valgrind happy */
    memset(line, 0, sizeof(line));

    pkgpath = get_pkgpath(db, info);

    if(access(pkgpath, F_OK)) {
        /* directory doesn't exist or can't be opened */
        _alpm_log(db->handle, PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n",
                  info->name, info->version, db->treename);
        goto error;
    }

    /* DESC */
    if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) {
        snprintf(path, PATH_MAX, "%sdesc", pkgpath);
        if((fp = fopen(path, "r")) == NULL) {
            _alpm_log(db->handle, PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
            goto error;
        }
        while(!feof(fp)) {
            if(fgets(line, sizeof(line), fp) == NULL) {
                break;
            }
            _alpm_strtrim(line);
            if(strcmp(line, "%NAME%") == 0) {
                if(fgets(line, sizeof(line), fp) == NULL) {
                    goto error;
                }
                if(strcmp(_alpm_strtrim(line), info->name) != 0) {
                    _alpm_log(db->handle, PM_LOG_ERROR, _("%s database is inconsistent: name "
                                                          "mismatch on package %s\n"), db->treename, info->name);
                }
            } else if(strcmp(line, "%VERSION%") == 0) {
                if(fgets(line, sizeof(line), fp) == NULL) {
                    goto error;
                }
                if(strcmp(_alpm_strtrim(line), info->version) != 0) {
                    _alpm_log(db->handle, PM_LOG_ERROR, _("%s database is inconsistent: version "
                                                          "mismatch on package %s\n"), db->treename, info->name);
                }
            } else if(strcmp(line, "%DESC%") == 0) {
                if(fgets(line, sizeof(line), fp) == NULL) {
                    goto error;
                }
                STRDUP(info->desc, _alpm_strtrim(line), goto error);
            } else if(strcmp(line, "%GROUPS%") == 0) {
                while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
                    char *linedup;
                    STRDUP(linedup, line, goto error);
                    info->groups = alpm_list_add(info->groups, linedup);
                }
            } else if(strcmp(line, "%URL%") == 0) {
예제 #13
0
int _alpm_runscriptlet(const char *root, const char *installfn,
											 const char *script, const char *ver,
											 const char *oldver, pmtrans_t *trans)
{
	char scriptfn[PATH_MAX];
	char cmdline[PATH_MAX];
	char tmpdir[PATH_MAX];
	char cwd[PATH_MAX];
	char *scriptpath;
	pid_t pid;
	int clean_tmpdir = 0;
	int restore_cwd = 0;
	int retval = 0;

	ALPM_LOG_FUNC;

	if(access(installfn, R_OK)) {
		/* not found */
		_alpm_log(PM_LOG_DEBUG, "scriptlet '%s' not found\n", installfn);
		return(0);
	}

	/* NOTE: popen will use the PARENT's /bin/sh, not the chroot's */
	if(access("/bin/sh", X_OK)) {
		/* not found */
		_alpm_log(PM_LOG_ERROR, _("No /bin/sh in parent environment, aborting scriptlet\n"));
		return(0);
	}

	/* creates a directory in $root/tmp/ for copying/extracting the scriptlet */
	snprintf(tmpdir, PATH_MAX, "%stmp/", root);
	if(access(tmpdir, F_OK) != 0) {
		_alpm_makepath_mode(tmpdir, 01777);
	}
	snprintf(tmpdir, PATH_MAX, "%stmp/alpm_XXXXXX", root);
	if(mkdtemp(tmpdir) == NULL) {
		_alpm_log(PM_LOG_ERROR, _("could not create temp directory\n"));
		return(1);
	} else {
		clean_tmpdir = 1;
	}

	/* either extract or copy the scriptlet */
	snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
	if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
		if(_alpm_unpack(installfn, tmpdir, ".INSTALL")) {
			retval = 1;
		}
	} else {
		if(_alpm_copyfile(installfn, scriptfn)) {
			_alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno));
			retval = 1;
		}
	}
	if(retval == 1) {
		goto cleanup;
	}

	/* chop off the root so we can find the tmpdir in the chroot */
	scriptpath = scriptfn + strlen(root) - 1;

	if(!grep(scriptfn, script)) {
		/* script not found in scriptlet file */
		goto cleanup;
	}

	/* save the cwd so we can restore it later */
	if(getcwd(cwd, PATH_MAX) == NULL) {
		_alpm_log(PM_LOG_ERROR, _("could not get current working directory\n"));
	} else {
		restore_cwd = 1;
	}

	/* just in case our cwd was removed in the upgrade operation */
	if(chdir(root) != 0) {
		_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), root, strerror(errno));
		goto cleanup;
	}

	_alpm_log(PM_LOG_DEBUG, "executing %s script...\n", script);

	if(oldver) {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s %s",
				scriptpath, script, ver, oldver);
	} else {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s",
				scriptpath, script, ver);
	}
	_alpm_log(PM_LOG_DEBUG, "%s\n", cmdline);

	/* fork- parent and child each have seperate code blocks below */
	pid = fork();
	if(pid == -1) {
		_alpm_log(PM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno));
		retval = 1;
		goto cleanup;
	}

	if(pid == 0) {
		FILE *pipe;
		/* this code runs for the child only (the actual chroot/exec) */
		_alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root);
		if(chroot(root) != 0) {
			_alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"),
					strerror(errno));
			exit(1);
		}
		if(chdir("/") != 0) {
			_alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"),
					strerror(errno));
			exit(1);
		}
		umask(0022);
		_alpm_log(PM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
		/* execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL); */
		pipe = popen(cmdline, "r");
		if(!pipe) {
			_alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)"),
					strerror(errno));
			exit(1);
		}
		while(!feof(pipe)) {
			char line[PATH_MAX];
			if(fgets(line, PATH_MAX, pipe) == NULL)
				break;
			alpm_logaction("%s", line);
			EVENT(trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
		}
		retval = pclose(pipe);
		exit(WEXITSTATUS(retval));
	} else {
		/* this code runs for the parent only (wait on the child) */
		pid_t retpid;
		int status;
		while((retpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
		if(retpid == -1) {
			_alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"),
			          strerror(errno));
			retval = 1;
			goto cleanup;
		} else {
			/* check the return status, make sure it is 0 (success) */
			if(WIFEXITED(status)) {
				_alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
				if(WEXITSTATUS(status) != 0) {
					_alpm_log(PM_LOG_ERROR, _("scriptlet failed to execute correctly\n"));
					retval = 1;
				}
			}
		}
	}

cleanup:
	if(clean_tmpdir && _alpm_rmrf(tmpdir)) {
		_alpm_log(PM_LOG_WARNING, _("could not remove tmpdir %s\n"), tmpdir);
	}
	if(restore_cwd) {
		chdir(cwd);
	}

	return(retval);
}
예제 #14
0
파일: trans.c 프로젝트: sandsmark/pacman
int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
		const char *script, const char *ver, const char *oldver, int is_archive)
{
	char arg0[64], arg1[3], cmdline[PATH_MAX];
	char *argv[] = { arg0, arg1, cmdline, NULL };
	char *tmpdir, *scriptfn = NULL, *scriptpath;
	int retval = 0;
	size_t len;

	if(_alpm_access(handle, NULL, filepath, R_OK) != 0) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "scriptlet '%s' not found\n", filepath);
		return 0;
	}

	if(!is_archive && !grep(filepath, script)) {
		/* script not found in scriptlet file; we can only short-circuit this early
		 * if it is an actual scriptlet file and not an archive.  */
		return 0;
	}

	strcpy(arg0, SCRIPTLET_SHELL);
	strcpy(arg1, "-c");

	/* create a directory in $root/tmp/ for copying/extracting the scriptlet */
	len = strlen(handle->root) + strlen("tmp/alpm_XXXXXX") + 1;
	MALLOC(tmpdir, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
	snprintf(tmpdir, len, "%stmp/", handle->root);
	if(access(tmpdir, F_OK) != 0) {
		_alpm_makepath_mode(tmpdir, 01777);
	}
	snprintf(tmpdir, len, "%stmp/alpm_XXXXXX", handle->root);
	if(mkdtemp(tmpdir) == NULL) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not create temp directory\n"));
		free(tmpdir);
		return 1;
	}

	/* either extract or copy the scriptlet */
	len += strlen("/.INSTALL");
	MALLOC(scriptfn, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
	snprintf(scriptfn, len, "%s/.INSTALL", tmpdir);
	if(is_archive) {
		if(_alpm_unpack_single(handle, filepath, tmpdir, ".INSTALL")) {
			retval = 1;
		}
	} else {
		if(_alpm_copyfile(filepath, scriptfn)) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno));
			retval = 1;
		}
	}
	if(retval == 1) {
		goto cleanup;
	}

	if(is_archive && !grep(scriptfn, script)) {
		/* script not found in extracted scriptlet file */
		goto cleanup;
	}

	/* chop off the root so we can find the tmpdir in the chroot */
	scriptpath = scriptfn + strlen(handle->root) - 1;

	if(oldver) {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s %s",
				scriptpath, script, ver, oldver);
	} else {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s",
				scriptpath, script, ver);
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline);

	retval = _alpm_run_chroot(handle, SCRIPTLET_SHELL, argv);

cleanup:
	if(scriptfn && unlink(scriptfn)) {
		_alpm_log(handle, ALPM_LOG_WARNING,
				_("could not remove %s\n"), scriptfn);
	}
	if(rmdir(tmpdir)) {
		_alpm_log(handle, ALPM_LOG_WARNING,
				_("could not remove tmpdir %s\n"), tmpdir);
	}

	free(scriptfn);
	free(tmpdir);
	return retval;
}
예제 #15
0
파일: be_local.c 프로젝트: AWhetter/pacman
static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq)
{
	FILE *fp = NULL;
	char line[1024];
	alpm_db_t *db = info->origin_data.db;

	/* bitmask logic here:
	 * infolevel: 00001111
	 * inforeq:   00010100
	 * & result:  00000100
	 * == to inforeq? nope, we need to load more info. */
	if((info->infolevel & inforeq) == inforeq) {
		/* already loaded all of this info, do nothing */
		return 0;
	}

	if(info->infolevel & INFRQ_ERROR) {
		/* We've encountered an error loading this package before. Don't attempt
		 * repeated reloads, just give up. */
		return -1;
	}

	_alpm_log(db->handle, ALPM_LOG_FUNCTION,
			"loading package data for %s : level=0x%x\n",
			info->name, inforeq);

	/* clear out 'line', to be certain - and to make valgrind happy */
	memset(line, 0, sizeof(line));

	/* DESC */
	if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) {
		char *path = _alpm_local_db_pkgpath(db, info, "desc");
		if(!path || (fp = fopen(path, "r")) == NULL) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
			free(path);
			goto error;
		}
		free(path);
		while(!feof(fp)) {
			if(safe_fgets(line, sizeof(line), fp) == NULL && !feof(fp)) {
				goto error;
			}
			if(_alpm_strip_newline(line, 0) == 0) {
				/* length of stripped line was zero */
				continue;
			}
			if(strcmp(line, "%NAME%") == 0) {
				READ_NEXT();
				if(strcmp(line, info->name) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
								"mismatch on package %s\n"), db->treename, info->name);
				}
			} else if(strcmp(line, "%VERSION%") == 0) {
				READ_NEXT();
				if(strcmp(line, info->version) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
								"mismatch on package %s\n"), db->treename, info->name);
				}
			} else if(strcmp(line, "%BASE%") == 0) {
				READ_AND_STORE(info->base);
			} else if(strcmp(line, "%DESC%") == 0) {
				READ_AND_STORE(info->desc);
			} else if(strcmp(line, "%GROUPS%") == 0) {
				READ_AND_STORE_ALL(info->groups);
			} else if(strcmp(line, "%URL%") == 0) {
				READ_AND_STORE(info->url);
			} else if(strcmp(line, "%LICENSE%") == 0) {
				READ_AND_STORE_ALL(info->licenses);
			} else if(strcmp(line, "%ARCH%") == 0) {
				READ_AND_STORE(info->arch);
			} else if(strcmp(line, "%BUILDDATE%") == 0) {
				READ_NEXT();
				info->builddate = _alpm_parsedate(line);
			} else if(strcmp(line, "%INSTALLDATE%") == 0) {
				READ_NEXT();
				info->installdate = _alpm_parsedate(line);
			} else if(strcmp(line, "%PACKAGER%") == 0) {
				READ_AND_STORE(info->packager);
			} else if(strcmp(line, "%REASON%") == 0) {
				READ_NEXT();
				info->reason = (alpm_pkgreason_t)atoi(line);
			} else if(strcmp(line, "%VALIDATION%") == 0) {
				alpm_list_t *i, *v = NULL;
				READ_AND_STORE_ALL(v);
				for(i = v; i; i = alpm_list_next(i))
				{
					if(strcmp(i->data, "none") == 0) {
						info->validation |= ALPM_PKG_VALIDATION_NONE;
					} else if(strcmp(i->data, "md5") == 0) {
						info->validation |= ALPM_PKG_VALIDATION_MD5SUM;
					} else if(strcmp(i->data, "sha256") == 0) {
						info->validation |= ALPM_PKG_VALIDATION_SHA256SUM;
					} else if(strcmp(i->data, "pgp") == 0) {
						info->validation |= ALPM_PKG_VALIDATION_SIGNATURE;
					} else {
						_alpm_log(db->handle, ALPM_LOG_WARNING,
								_("unknown validation type for package %s: %s\n"),
								info->name, (const char *)i->data);
					}
				}
				FREELIST(v);
			} else if(strcmp(line, "%SIZE%") == 0) {
				READ_NEXT();
				info->isize = _alpm_strtoofft(line);
			} else if(strcmp(line, "%REPLACES%") == 0) {
				READ_AND_SPLITDEP(info->replaces);
			} else if(strcmp(line, "%DEPENDS%") == 0) {
				READ_AND_SPLITDEP(info->depends);
			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
				READ_AND_SPLITDEP(info->optdepends);
			} else if(strcmp(line, "%CONFLICTS%") == 0) {
				READ_AND_SPLITDEP(info->conflicts);
			} else if(strcmp(line, "%PROVIDES%") == 0) {
				READ_AND_SPLITDEP(info->provides);
			}
		}
		fclose(fp);
		fp = NULL;
		info->infolevel |= INFRQ_DESC;
	}

	/* FILES */
	if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) {
		char *path = _alpm_local_db_pkgpath(db, info, "files");
		if(!path || (fp = fopen(path, "r")) == NULL) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
			free(path);
			goto error;
		}
		free(path);
		while(safe_fgets(line, sizeof(line), fp)) {
			_alpm_strip_newline(line, 0);
			if(strcmp(line, "%FILES%") == 0) {
				size_t files_count = 0, files_size = 0, len;
				alpm_file_t *files = NULL;

				while(safe_fgets(line, sizeof(line), fp) &&
						(len = _alpm_strip_newline(line, 0))) {
					if(!_alpm_greedy_grow((void **)&files, &files_size,
								(files_count ? (files_count + 1) * sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
						goto error;
					}
					/* since we know the length of the file string already,
					 * we can do malloc + memcpy rather than strdup */
					len += 1;
					MALLOC(files[files_count].name, len, goto error);
					memcpy(files[files_count].name, line, len);
					files_count++;
				}
				/* attempt to hand back any memory we don't need */
				if(files_count > 0) {
					files = realloc(files, sizeof(alpm_file_t) * files_count);
					/* make sure the list is sorted */
					qsort(files, files_count, sizeof(alpm_file_t), _alpm_files_cmp);
				} else {
					FREE(files);
				}
				info->files.count = files_count;
				info->files.files = files;
			} else if(strcmp(line, "%BACKUP%") == 0) {
예제 #16
0
파일: deps.c 프로젝트: vadmium/pacman-arch
/* Re-order a list of target packages with respect to their dependencies.
 *
 * Example (reverse == 0):
 *   A depends on C
 *   B depends on A
 *   Target order is A,B,C,D
 *
 *   Should be re-ordered to C,A,B,D
 *
 * if reverse is > 0, the dependency order will be reversed.
 *
 * This function returns the new alpm_list_t* target list.
 *
 */
alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle,
		alpm_list_t *targets, int reverse)
{
	alpm_list_t *newtargs = NULL;
	alpm_list_t *vertices = NULL;
	alpm_list_t *vptr;
	alpm_graph_t *vertex;

	if(targets == NULL) {
		return NULL;
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "started sorting dependencies\n");

	vertices = dep_graph_init(targets);

	vptr = vertices;
	vertex = vertices->data;
	while(vptr) {
		/* mark that we touched the vertex */
		vertex->state = -1;
		int found = 0;
		while(vertex->childptr && !found) {
			alpm_graph_t *nextchild = vertex->childptr->data;
			vertex->childptr = vertex->childptr->next;
			if(nextchild->state == 0) {
				found = 1;
				nextchild->parent = vertex;
				vertex = nextchild;
			}
			else if(nextchild->state == -1) {
				alpm_pkg_t *vertexpkg = vertex->data;
				alpm_pkg_t *childpkg = nextchild->data;

				_alpm_log(handle, ALPM_LOG_WARNING, _("dependency cycle detected:\n"));
				if(reverse) {
					_alpm_log(handle, ALPM_LOG_WARNING,
							_("%s will be removed after its %s dependency\n"),
							vertexpkg->name, childpkg->name);
				} else {
					_alpm_log(handle, ALPM_LOG_WARNING,
							_("%s will be installed before its %s dependency\n"),
							vertexpkg->name, childpkg->name);
				}
			}
		}
		if(!found) {
			newtargs = alpm_list_add(newtargs, vertex->data);
			/* mark that we've left this vertex */
			vertex->state = 1;
			vertex = vertex->parent;
			if(!vertex) {
				vptr = vptr->next;
				while(vptr) {
					vertex = vptr->data;
					if(vertex->state == 0) break;
					vptr = vptr->next;
				}
			}
		}
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "sorting dependencies finished\n");

	if(reverse) {
		/* reverse the order */
		alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
		/* free the old one */
		alpm_list_free(newtargs);
		newtargs = tmptargs;
	}

	alpm_list_free_inner(vertices, _alpm_graph_free);
	alpm_list_free(vertices);

	return newtargs;
}
예제 #17
0
파일: dload.c 프로젝트: 7799/pacman
static int curl_download_internal(struct dload_payload *payload,
		const char *localpath, char **final_file, char **final_url)
{
	int ret = -1;
	FILE *localf = NULL;
	char *effective_url;
	char hostname[HOSTNAME_SIZE];
	char error_buffer[CURL_ERROR_SIZE] = {0};
	struct stat st;
	long timecond, remote_time = -1;
	double remote_size, bytes_dl;
	struct sigaction orig_sig_pipe, orig_sig_int;
	/* shortcut to our handle within the payload */
	alpm_handle_t *handle = payload->handle;
	CURL *curl = get_libcurl_handle(handle);
	handle->pm_errno = 0;

	/* make sure these are NULL */
	FREE(payload->tempfile_name);
	FREE(payload->destfile_name);
	FREE(payload->content_disp_name);

	payload->tempfile_openmode = "wb";
	if(!payload->remote_name) {
		STRDUP(payload->remote_name, get_filename(payload->fileurl),
				RET_ERR(handle, ALPM_ERR_MEMORY, -1));
	}
	if(curl_gethost(payload->fileurl, hostname, sizeof(hostname)) != 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), payload->fileurl);
		RET_ERR(handle, ALPM_ERR_SERVER_BAD_URL, -1);
	}

	if(payload->remote_name && strlen(payload->remote_name) > 0 &&
			strcmp(payload->remote_name, ".sig") != 0) {
		payload->destfile_name = get_fullpath(localpath, payload->remote_name, "");
		payload->tempfile_name = get_fullpath(localpath, payload->remote_name, ".part");
		if(!payload->destfile_name || !payload->tempfile_name) {
			goto cleanup;
		}
	} else {
		/* URL doesn't contain a filename, so make a tempfile. We can't support
		 * resuming this kind of download; partial transfers will be destroyed */
		payload->unlink_on_fail = 1;

		localf = create_tempfile(payload, localpath);
		if(localf == NULL) {
			goto cleanup;
		}
	}

	curl_set_handle_opts(payload, curl, error_buffer);

	if(localf == NULL) {
		localf = fopen(payload->tempfile_name, payload->tempfile_openmode);
		if(localf == NULL) {
			handle->pm_errno = ALPM_ERR_RETRIEVE;
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("could not open file %s: %s\n"),
					payload->tempfile_name, strerror(errno));
			goto cleanup;
		}
	}

	_alpm_log(handle, ALPM_LOG_DEBUG,
			"opened tempfile for download: %s (%s)\n", payload->tempfile_name,
			payload->tempfile_openmode);

	curl_easy_setopt(curl, CURLOPT_WRITEDATA, localf);

	/* Ignore any SIGPIPE signals. With libcurl, these shouldn't be happening,
	 * but better safe than sorry. Store the old signal handler first. */
	mask_signal(SIGPIPE, SIG_IGN, &orig_sig_pipe);
	mask_signal(SIGINT, &inthandler, &orig_sig_int);

	/* perform transfer */
	payload->curlerr = curl_easy_perform(curl);
	_alpm_log(handle, ALPM_LOG_DEBUG, "curl returned error %d from transfer\n",
			payload->curlerr);

	/* disconnect relationships from the curl handle for things that might go out
	 * of scope, but could still be touched on connection teardown. This really
	 * only applies to FTP transfers. */
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char *)NULL);

	/* was it a success? */
	switch(payload->curlerr) {
		case CURLE_OK:
			/* get http/ftp response code */
			_alpm_log(handle, ALPM_LOG_DEBUG, "response code: %ld\n", payload->respcode);
			if(payload->respcode >= 400) {
				payload->unlink_on_fail = 1;
				/* non-translated message is same as libcurl */
				snprintf(error_buffer, sizeof(error_buffer),
						"The requested URL returned error: %ld", payload->respcode);
				_alpm_log(handle, ALPM_LOG_ERROR,
						_("failed retrieving file '%s' from %s : %s\n"),
						payload->remote_name, hostname, error_buffer);
				goto cleanup;
			}
			break;
		case CURLE_ABORTED_BY_CALLBACK:
			/* handle the interrupt accordingly */
			if(dload_interrupted == ABORT_OVER_MAXFILESIZE) {
				payload->curlerr = CURLE_FILESIZE_EXCEEDED;
				handle->pm_errno = ALPM_ERR_LIBCURL;
				/* use the 'size exceeded' message from libcurl */
				_alpm_log(handle, ALPM_LOG_ERROR,
						_("failed retrieving file '%s' from %s : %s\n"),
						payload->remote_name, hostname,
						curl_easy_strerror(CURLE_FILESIZE_EXCEEDED));
			}
			goto cleanup;
		default:
			/* delete zero length downloads */
			if(fstat(fileno(localf), &st) == 0 && st.st_size == 0) {
				payload->unlink_on_fail = 1;
			}
			if(!payload->errors_ok) {
				handle->pm_errno = ALPM_ERR_LIBCURL;
				_alpm_log(handle, ALPM_LOG_ERROR,
						_("failed retrieving file '%s' from %s : %s\n"),
						payload->remote_name, hostname, error_buffer);
			} else {
				_alpm_log(handle, ALPM_LOG_DEBUG,
						"failed retrieving file '%s' from %s : %s\n",
						payload->remote_name, hostname, error_buffer);
			}
			goto cleanup;
	}

	/* retrieve info about the state of the transfer */
	curl_easy_getinfo(curl, CURLINFO_FILETIME, &remote_time);
	curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &remote_size);
	curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &bytes_dl);
	curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &timecond);
	curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);

	if(final_url != NULL) {
		*final_url = effective_url;
	}

	/* time condition was met and we didn't download anything. we need to
	 * clean up the 0 byte .part file that's left behind. */
	if(timecond == 1 && DOUBLE_EQ(bytes_dl, 0)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "file met time condition\n");
		ret = 1;
		unlink(payload->tempfile_name);
		goto cleanup;
	}

	/* remote_size isn't necessarily the full size of the file, just what the
	 * server reported as remaining to download. compare it to what curl reported
	 * as actually being transferred during curl_easy_perform() */
	if(!DOUBLE_EQ(remote_size, -1) && !DOUBLE_EQ(bytes_dl, -1) &&
			!DOUBLE_EQ(bytes_dl, remote_size)) {
		handle->pm_errno = ALPM_ERR_RETRIEVE;
		_alpm_log(handle, ALPM_LOG_ERROR, _("%s appears to be truncated: %jd/%jd bytes\n"),
				payload->remote_name, (intmax_t)bytes_dl, (intmax_t)remote_size);
		goto cleanup;
	}

	if(payload->trust_remote_name) {
		if(payload->content_disp_name) {
			/* content-disposition header has a better name for our file */
			free(payload->destfile_name);
			payload->destfile_name = get_fullpath(localpath, payload->content_disp_name, "");
		} else {
			const char *effective_filename = strrchr(effective_url, '/');
			if(effective_filename && strlen(effective_filename) > 2) {
				effective_filename++;

				/* if destfile was never set, we wrote to a tempfile. even if destfile is
				 * set, we may have followed some redirects and the effective url may
				 * have a better suggestion as to what to name our file. in either case,
				 * refactor destfile to this newly derived name. */
				if(!payload->destfile_name || strcmp(effective_filename,
							strrchr(payload->destfile_name, '/') + 1) != 0) {
					free(payload->destfile_name);
					payload->destfile_name = get_fullpath(localpath, effective_filename, "");
				}
			}
		}
	}

	ret = 0;

cleanup:
	if(localf != NULL) {
		fclose(localf);
		utimes_long(payload->tempfile_name, remote_time);
	}

	if(ret == 0) {
		const char *realname = payload->tempfile_name;
		if(payload->destfile_name) {
			realname = payload->destfile_name;
			if(rename(payload->tempfile_name, payload->destfile_name)) {
				_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
						payload->tempfile_name, payload->destfile_name, strerror(errno));
				ret = -1;
			}
		}
		if(ret != -1 && final_file) {
			STRDUP(*final_file, strrchr(realname, '/') + 1,
					RET_ERR(handle, ALPM_ERR_MEMORY, -1));
		}
	}

	if((ret == -1 || dload_interrupted) && payload->unlink_on_fail &&
			payload->tempfile_name) {
		unlink(payload->tempfile_name);
	}

	/* restore the old signal handlers */
	unmask_signal(SIGINT, &orig_sig_int);
	unmask_signal(SIGPIPE, &orig_sig_pipe);
	/* if we were interrupted, trip the old handler */
	if(dload_interrupted) {
		raise(SIGINT);
	}

	return ret;
}
예제 #18
0
파일: deps.c 프로젝트: vadmium/pacman-arch
/** Checks dependencies and returns missing ones in a list.
 * Dependencies can include versions with depmod operators.
 * @param handle the context handle
 * @param pkglist the list of local packages
 * @param remove an alpm_list_t* of packages to be removed
 * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade)
 * @param reversedeps handles the backward dependencies
 * @return an alpm_list_t* of alpm_depmissing_t pointers.
 */
alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
		alpm_list_t *pkglist, alpm_list_t *rem, alpm_list_t *upgrade,
		int reversedeps)
{
	alpm_list_t *i, *j;
	alpm_list_t *dblist = NULL, *modified = NULL;
	alpm_list_t *baddeps = NULL;
	int nodepversion;

	CHECK_HANDLE(handle, return NULL);

	for(i = pkglist; i; i = i->next) {
		alpm_pkg_t *pkg = i->data;
		if(alpm_pkg_find(rem, pkg->name) || alpm_pkg_find(upgrade, pkg->name)) {
			modified = alpm_list_add(modified, pkg);
		} else {
			dblist = alpm_list_add(dblist, pkg);
		}
	}

	nodepversion = no_dep_version(handle);

	/* look for unsatisfied dependencies of the upgrade list */
	for(i = upgrade; i; i = i->next) {
		alpm_pkg_t *tp = i->data;
		_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: package %s-%s\n",
				tp->name, tp->version);

		for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
			alpm_depend_t *depend = j->data;
			depend = filtered_depend(depend, nodepversion);
			/* 1. we check the upgrade list */
			/* 2. we check database for untouched satisfying packages */
			if(!find_dep_satisfier(upgrade, depend) &&
					!find_dep_satisfier(dblist, depend)) {
				/* Unsatisfied dependency in the upgrade list */
				alpm_depmissing_t *miss;
				char *missdepstring = alpm_dep_compute_string(depend);
				_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
						missdepstring, tp->name);
				free(missdepstring);
				miss = depmiss_new(tp->name, depend, NULL);
				baddeps = alpm_list_add(baddeps, miss);
			}
			release_filtered_depend(depend, nodepversion);
		}
	}

	if(reversedeps) {
		/* reversedeps handles the backwards dependencies, ie,
		 * the packages listed in the requiredby field. */
		for(i = dblist; i; i = i->next) {
			alpm_pkg_t *lp = i->data;
			for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
				alpm_depend_t *depend = j->data;
				depend = filtered_depend(depend, nodepversion);
				alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend);
				/* we won't break this depend, if it is already broken, we ignore it */
				/* 1. check upgrade list for satisfiers */
				/* 2. check dblist for satisfiers */
				if(causingpkg &&
				   !find_dep_satisfier(upgrade, depend) &&
				   !find_dep_satisfier(dblist, depend)) {
					alpm_depmissing_t *miss;
					char *missdepstring = alpm_dep_compute_string(depend);
					_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
							missdepstring, lp->name);
					free(missdepstring);
					miss = depmiss_new(lp->name, depend, causingpkg->name);
					baddeps = alpm_list_add(baddeps, miss);
				}
				release_filtered_depend(depend, nodepversion);
			}
		}
	}

	alpm_list_free(modified);
	alpm_list_free(dblist);

	return baddeps;
}
예제 #19
0
파일: remove.c 프로젝트: JohnFrazier/pacman
/**
 * @brief Transaction preparation for remove actions.
 *
 * This functions takes a pointer to a alpm_list_t which will be
 * filled with a list of alpm_depmissing_t* objects representing
 * the packages blocking the transaction.
 *
 * @param handle the context handle
 * @param data a pointer to an alpm_list_t* to fill
 *
 * @return 0 on success, -1 on error
 */
int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data)
{
	alpm_list_t *lp;
	alpm_trans_t *trans = handle->trans;
	alpm_db_t *db = handle->db_local;

	if((trans->flags & ALPM_TRANS_FLAG_RECURSE)
			&& !(trans->flags & ALPM_TRANS_FLAG_CASCADE)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n");
		if(_alpm_recursedeps(db, trans->remove,
				trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) {
			return -1;
		}
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		EVENT(handle, ALPM_EVENT_CHECKDEPS_START, NULL, NULL);

		_alpm_log(handle, ALPM_LOG_DEBUG, "looking for unsatisfied dependencies\n");
		lp = alpm_checkdeps(handle, _alpm_db_get_pkgcache(db), trans->remove, NULL, 1);
		if(lp != NULL) {

			if(trans->flags & ALPM_TRANS_FLAG_CASCADE) {
				if(remove_prepare_cascade(handle, lp)) {
					return -1;
				}
			} else if(trans->flags & ALPM_TRANS_FLAG_UNNEEDED) {
				/* Remove needed packages (which would break dependencies)
				 * from target list */
				remove_prepare_keep_needed(handle, lp);
			} else {
				if(data) {
					*data = lp;
				} else {
					alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
					alpm_list_free(lp);
				}
				RET_ERR(handle, ALPM_ERR_UNSATISFIED_DEPS, -1);
			}
		}
	}

	/* re-order w.r.t. dependencies */
	_alpm_log(handle, ALPM_LOG_DEBUG, "sorting by dependencies\n");
	lp = _alpm_sortbydeps(handle, trans->remove, 1);
	/* free the old alltargs */
	alpm_list_free(trans->remove);
	trans->remove = lp;

	/* -Rcs == -Rc then -Rs */
	if((trans->flags & ALPM_TRANS_FLAG_CASCADE)
			&& (trans->flags & ALPM_TRANS_FLAG_RECURSE)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "finding removable dependencies\n");
		if(_alpm_recursedeps(db, trans->remove,
					trans->flags & ALPM_TRANS_FLAG_RECURSEALL)) {
			return -1;
		}
	}

	/* Note packages being removed that are optdepends for installed packages */
	remove_notify_needed_optdepends(handle, trans->remove);

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		EVENT(handle, ALPM_EVENT_CHECKDEPS_DONE, NULL, NULL);
	}

	return 0;
}
예제 #20
0
/** Update a package database
 *
 * An update of the package database \a db will be attempted. Unless
 * \a force is true, the update will only be performed if the remote
 * database was modified since the last update.
 *
 * This operation requires a database lock, and will return an applicable error
 * if the lock could not be obtained.
 *
 * Example:
 * @code
 * alpm_list_t *syncs = alpm_get_syncdbs();
 * for(i = syncs; i; i = alpm_list_next(i)) {
 *     alpm_db_t *db = alpm_list_getdata(i);
 *     result = alpm_db_update(0, db);
 *
 *     if(result < 0) {
 *	       printf("Unable to update database: %s\n", alpm_strerrorlast());
 *     } else if(result == 1) {
 *         printf("Database already up to date\n");
 *     } else {
 *         printf("Database updated\n");
 *     }
 * }
 * @endcode
 *
 * @ingroup alpm_databases
 * @note After a successful update, the \link alpm_db_get_pkgcache()
 * package cache \endlink will be invalidated
 * @param force if true, then forces the update, otherwise update only in case
 * the database isn't up to date
 * @param db pointer to the package database to update
 * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
 * to date
 */
int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
{
	char *syncpath;
	alpm_list_t *i;
	int ret = -1;
	mode_t oldmask;
	alpm_handle_t *handle;
	alpm_siglevel_t level;

	/* Sanity checks */
	ASSERT(db != NULL, return -1);
	handle = db->handle;
	handle->pm_errno = 0;
	ASSERT(db != handle->db_local, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
	ASSERT(db->servers != NULL, RET_ERR(handle, ALPM_ERR_SERVER_NONE, -1));

	syncpath = get_sync_dir(handle);
	if(!syncpath) {
		return -1;
	}

	/* make sure we have a sane umask */
	oldmask = umask(0022);

	level = alpm_db_get_siglevel(db);

	/* attempt to grab a lock */
	if(_alpm_handle_lock(handle)) {
		free(syncpath);
		umask(oldmask);
		RET_ERR(handle, ALPM_ERR_HANDLE_LOCK, -1);
	}

	for(i = db->servers; i; i = i->next) {
		const char *server = i->data;
		struct dload_payload payload;
		size_t len;
		int sig_ret = 0;

		memset(&payload, 0, sizeof(struct dload_payload));

		/* set hard upper limit of 25MiB */
		payload.max_size = 25 * 1024 * 1024;

		/* print server + filename into a buffer */
		len = strlen(server) + strlen(db->treename) + 5;
		/* TODO fix leak syncpath and umask unset */
		MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
		snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename);
		payload.handle = handle;
		payload.force = force;
		payload.unlink_on_fail = 1;

		ret = _alpm_download(&payload, syncpath, NULL);
		_alpm_dload_payload_reset(&payload);

		if(ret == 0 && (level & ALPM_SIG_DATABASE)) {
			/* an existing sig file is no good at this point */
			char *sigpath = _alpm_sigpath(handle, _alpm_db_path(db));
			if(!sigpath) {
				ret = -1;
				break;
			}
			unlink(sigpath);
			free(sigpath);

			/* if we downloaded a DB, we want the .sig from the same server */
			/* print server + filename into a buffer (leave space for .sig) */
			len = strlen(server) + strlen(db->treename) + 9;
			/* TODO fix leak syncpath and umask unset */
			MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
			snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename);
			payload.handle = handle;
			payload.force = 1;
			payload.errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL);

			/* set hard upper limit of 16KiB */
			payload.max_size = 16 * 1024;

			sig_ret = _alpm_download(&payload, syncpath, NULL);
			/* errors_ok suppresses error messages, but not the return code */
			sig_ret = payload.errors_ok ? 0 : sig_ret;
			_alpm_dload_payload_reset(&payload);
		}

		if(ret != -1 && sig_ret != -1) {
			break;
		}
	}

	if(ret == 1) {
		/* files match, do nothing */
		handle->pm_errno = 0;
		goto cleanup;
	} else if(ret == -1) {
		/* pm_errno was set by the download code */
		_alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync db: %s\n",
				alpm_strerror(handle->pm_errno));
		goto cleanup;
	}

	/* Cache needs to be rebuilt */
	_alpm_db_free_pkgcache(db);

	/* clear all status flags regarding validity/existence */
	db->status &= ~DB_STATUS_VALID;
	db->status &= ~DB_STATUS_INVALID;
	db->status &= ~DB_STATUS_EXISTS;
	db->status &= ~DB_STATUS_MISSING;

	if(sync_db_validate(db)) {
		/* pm_errno should be set */
		ret = -1;
	}

cleanup:

	if(_alpm_handle_unlock(handle)) {
		_alpm_log(handle, ALPM_LOG_WARNING, _("could not remove lock file %s\n"),
				handle->lockfile);
	}
	free(syncpath);
	umask(oldmask);
	return ret;
}
예제 #21
0
파일: remove.c 프로젝트: JohnFrazier/pacman
/**
 * @brief Unlink a package file, backing it up if necessary.
 *
 * @param handle the context handle
 * @param oldpkg the package being removed
 * @param newpkg the package replacing \a oldpkg
 * @param fileobj file to remove
 * @param skip_remove list of files that shouldn't be removed
 * @param nosave whether files should be backed up
 *
 * @return 0 on success, -1 if there was an error unlinking the file, 1 if the
 * file was skipped or did not exist
 */
static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg,
		alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove,
		int nosave)
{
	struct stat buf;
	char file[PATH_MAX];

	snprintf(file, PATH_MAX, "%s%s", handle->root, fileobj->name);

	/* check the remove skip list before removing the file.
	 * see the big comment block in db_find_fileconflicts() for an
	 * explanation. */
	if(alpm_list_find(skip_remove, fileobj->name, _alpm_fnmatch)) {
		_alpm_log(handle, ALPM_LOG_DEBUG,
				"%s is in skip_remove, skipping removal\n", file);
		return 1;
	}

	if(_alpm_lstat(file, &buf)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file);
		return 1;
	}

	if(S_ISDIR(buf.st_mode)) {
		ssize_t files = _alpm_files_in_directory(handle, file, 0);
		/* if we have files, no need to remove the directory */
		if(files > 0) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (contains files)\n",
					file);
		} else if(files < 0) {
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"keeping directory %s (could not count files)\n", file);
		} else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg),
					fileobj->name)) {
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"keeping directory %s (in new package)\n", file);
		} else if(dir_is_mountpoint(handle, file, &buf)) {
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"keeping directory %s (mountpoint)\n", file);
		} else {
			/* one last check- does any other package own this file? */
			alpm_list_t *local, *local_pkgs;
			int found = 0;
			local_pkgs = _alpm_db_get_pkgcache(handle->db_local);
			for(local = local_pkgs; local && !found; local = local->next) {
				alpm_pkg_t *local_pkg = local->data;
				alpm_filelist_t *filelist;

				/* we duplicated the package when we put it in the removal list, so we
				 * so we can't use direct pointer comparison here. */
				if(oldpkg->name_hash == local_pkg->name_hash
						&& strcmp(oldpkg->name, local_pkg->name) == 0) {
					continue;
				}
				filelist = alpm_pkg_get_files(local_pkg);
				if(alpm_filelist_contains(filelist, fileobj->name)) {
					_alpm_log(handle, ALPM_LOG_DEBUG,
							"keeping directory %s (owned by %s)\n", file, local_pkg->name);
					found = 1;
				}
			}
			if(!found) {
				if(rmdir(file)) {
					_alpm_log(handle, ALPM_LOG_DEBUG,
							"directory removal of %s failed: %s\n", file, strerror(errno));
					return -1;
				} else {
					_alpm_log(handle, ALPM_LOG_DEBUG,
							"removed directory %s (no remaining owners)\n", file);
				}
			}
		}
	} else {
		/* if the file needs backup and has been modified, back it up to .pacsave */
		alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg);
		if(backup) {
			if(nosave) {
				_alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file);
			} else {
				char *filehash = alpm_compute_md5sum(file);
				int cmp = filehash ? strcmp(filehash, backup->hash) : 0;
				FREE(filehash);
				if(cmp != 0) {
					char *newpath;
					size_t len = strlen(file) + 8 + 1;
					MALLOC(newpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
					shift_pacsave(handle, file);
					snprintf(newpath, len, "%s.pacsave", file);
					if(rename(file, newpath)) {
						_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
								file, newpath, strerror(errno));
						alpm_logaction(handle, ALPM_CALLER_PREFIX,
								"error: could not rename %s to %s (%s)\n",
								file, newpath, strerror(errno));
						free(newpath);
						return -1;
					}
					_alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), file, newpath);
					alpm_logaction(handle, ALPM_CALLER_PREFIX,
							"warning: %s saved as %s\n", file, newpath);
					free(newpath);
					return 0;
				}
			}
		}

		_alpm_log(handle, ALPM_LOG_DEBUG, "unlinking %s\n", file);

		if(unlink(file) == -1) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("cannot remove %s (%s)\n"),
					file, strerror(errno));
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"error: cannot remove %s (%s)\n", file, strerror(errno));
			return -1;
		}
	}
	return 0;
}
예제 #22
0
static int sync_db_populate(alpm_db_t *db)
{
	const char *dbpath;
	size_t est_count;
	int count, fd;
	struct stat buf;
	struct archive *archive;
	struct archive_entry *entry;
	alpm_pkg_t *pkg = NULL;

	if(db->status & DB_STATUS_INVALID) {
		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
	}
	if(db->status & DB_STATUS_MISSING) {
		RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
	}
	dbpath = _alpm_db_path(db);
	if(!dbpath) {
		/* pm_errno set in _alpm_db_path() */
		return -1;
	}

	fd = _alpm_open_archive(db->handle, dbpath, &buf,
			&archive, ALPM_ERR_DB_OPEN);
	if(fd < 0) {
		return -1;
	}
	est_count = estimate_package_count(&buf, archive);

	db->pkgcache = _alpm_pkghash_create(est_count);
	if(db->pkgcache == NULL) {
		db->handle->pm_errno = ALPM_ERR_MEMORY;
		count = -1;
		goto cleanup;
	}

	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
		mode_t mode = archive_entry_mode(entry);
		if(S_ISDIR(mode)) {
			continue;
		} else {
			/* we have desc, depends or deltas - parse it */
			if(sync_db_read(db, archive, entry, &pkg) != 0) {
				_alpm_log(db->handle, ALPM_LOG_ERROR,
						_("could not parse package description file '%s' from db '%s'\n"),
						archive_entry_pathname(entry), db->treename);
				continue;
			}
		}
	}

	count = alpm_list_count(db->pkgcache->list);
	if(count > 0) {
		db->pkgcache->list = alpm_list_msort(db->pkgcache->list,
				(size_t)count, _alpm_pkg_cmp);
	}
	_alpm_log(db->handle, ALPM_LOG_DEBUG,
			"added %d packages to package cache for db '%s'\n",
			count, db->treename);

cleanup:
	archive_read_finish(archive);
	if(fd >= 0) {
		CLOSE(fd);
	}
	return count;
}
예제 #23
0
파일: sync.c 프로젝트: vadmium/pacman-arch
static alpm_list_t *check_replacers(alpm_handle_t *handle, alpm_pkg_t *lpkg,
		alpm_db_t *sdb)
{
	/* 2. search for replacers in sdb */
	alpm_list_t *replacers = NULL;
	alpm_list_t *k;
	_alpm_log(handle, ALPM_LOG_DEBUG,
			"searching for replacements for %s in %s\n",
			lpkg->name, sdb->treename);
	for(k = _alpm_db_get_pkgcache(sdb); k; k = k->next) {
		int found = 0;
		alpm_pkg_t *spkg = k->data;
		alpm_list_t *l;
		for(l = alpm_pkg_get_replaces(spkg); l; l = l->next) {
			alpm_depend_t *replace = l->data;
			/* we only want to consider literal matches at this point. */
			if(_alpm_depcmp_literal(lpkg, replace)) {
				found = 1;
				break;
			}
		}
		if(found) {
			int doreplace = 0;
			alpm_pkg_t *tpkg;
			/* check IgnorePkg/IgnoreGroup */
			if(_alpm_pkg_should_ignore(handle, spkg)
					|| _alpm_pkg_should_ignore(handle, lpkg)) {
				_alpm_log(handle, ALPM_LOG_WARNING,
						_("ignoring package replacement (%s-%s => %s-%s)\n"),
						lpkg->name, lpkg->version, spkg->name, spkg->version);
				continue;
			}

			QUESTION(handle, ALPM_QUESTION_REPLACE_PKG, lpkg, spkg,
					sdb->treename, &doreplace);
			if(!doreplace) {
				continue;
			}

			/* If spkg is already in the target list, we append lpkg to spkg's
			 * removes list */
			tpkg = alpm_pkg_find(handle->trans->add, spkg->name);
			if(tpkg) {
				/* sanity check, multiple repos can contain spkg->name */
				if(tpkg->origin_data.db != sdb) {
					_alpm_log(handle, ALPM_LOG_WARNING, _("cannot replace %s by %s\n"),
							lpkg->name, spkg->name);
					continue;
				}
				_alpm_log(handle, ALPM_LOG_DEBUG, "appending %s to the removes list of %s\n",
						lpkg->name, tpkg->name);
				tpkg->removes = alpm_list_add(tpkg->removes, lpkg);
				/* check the to-be-replaced package's reason field */
				if(alpm_pkg_get_reason(lpkg) == ALPM_PKG_REASON_EXPLICIT) {
					tpkg->reason = ALPM_PKG_REASON_EXPLICIT;
				}
			} else {
				/* add spkg to the target list */
				/* copy over reason */
				spkg->reason = alpm_pkg_get_reason(lpkg);
				spkg->removes = alpm_list_add(NULL, lpkg);
				_alpm_log(handle, ALPM_LOG_DEBUG,
						"adding package %s-%s to the transaction targets\n",
						spkg->name, spkg->version);
				replacers = alpm_list_add(replacers, spkg);
			}
		}
	}
	return replacers;
}
예제 #24
0
static int sync_db_read(alpm_db_t *db, struct archive *archive,
		struct archive_entry *entry, alpm_pkg_t **likely_pkg)
{
	const char *entryname, *filename;
	alpm_pkg_t *pkg;
	struct archive_read_buffer buf;

	entryname = archive_entry_pathname(entry);
	if(entryname == NULL) {
		_alpm_log(db->handle, ALPM_LOG_DEBUG,
				"invalid archive entry provided to _alpm_sync_db_read, skipping\n");
		return -1;
	}

	_alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data from archive entry %s\n",
			entryname);

	memset(&buf, 0, sizeof(buf));
	/* 512K for a line length seems reasonable */
	buf.max_line_size = 512 * 1024;

	pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);

	if(pkg == NULL) {
		_alpm_log(db->handle, ALPM_LOG_DEBUG,
				"entry %s could not be loaded into %s sync database",
				entryname, db->treename);
		return -1;
	}

	if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
			|| strcmp(filename, "deltas") == 0) {
		int ret;
		while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
			char *line = buf.line;
			if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
				/* length of stripped line was zero */
				continue;
			}

			if(strcmp(line, "%NAME%") == 0) {
				READ_NEXT();
				if(strcmp(line, pkg->name) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
								"mismatch on package %s\n"), db->treename, pkg->name);
				}
			} else if(strcmp(line, "%VERSION%") == 0) {
				READ_NEXT();
				if(strcmp(line, pkg->version) != 0) {
					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
								"mismatch on package %s\n"), db->treename, pkg->name);
				}
			} else if(strcmp(line, "%FILENAME%") == 0) {
				READ_AND_STORE(pkg->filename);
			} else if(strcmp(line, "%DESC%") == 0) {
				READ_AND_STORE(pkg->desc);
			} else if(strcmp(line, "%GROUPS%") == 0) {
				READ_AND_STORE_ALL(pkg->groups);
			} else if(strcmp(line, "%URL%") == 0) {
				READ_AND_STORE(pkg->url);
			} else if(strcmp(line, "%LICENSE%") == 0) {
				READ_AND_STORE_ALL(pkg->licenses);
			} else if(strcmp(line, "%ARCH%") == 0) {
				READ_AND_STORE(pkg->arch);
			} else if(strcmp(line, "%BUILDDATE%") == 0) {
				READ_NEXT();
				pkg->builddate = _alpm_parsedate(line);
			} else if(strcmp(line, "%PACKAGER%") == 0) {
				READ_AND_STORE(pkg->packager);
			} else if(strcmp(line, "%CSIZE%") == 0) {
				READ_NEXT();
				pkg->size = _alpm_strtoofft(line);
			} else if(strcmp(line, "%ISIZE%") == 0) {
				READ_NEXT();
				pkg->isize = _alpm_strtoofft(line);
			} else if(strcmp(line, "%MD5SUM%") == 0) {
				READ_AND_STORE(pkg->md5sum);
			} else if(strcmp(line, "%SHA256SUM%") == 0) {
				READ_AND_STORE(pkg->sha256sum);
			} else if(strcmp(line, "%PGPSIG%") == 0) {
				READ_AND_STORE(pkg->base64_sig);
			} else if(strcmp(line, "%REPLACES%") == 0) {
				READ_AND_SPLITDEP(pkg->replaces);
			} else if(strcmp(line, "%DEPENDS%") == 0) {
				READ_AND_SPLITDEP(pkg->depends);
			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
				READ_AND_SPLITDEP(pkg->optdepends);
			} else if(strcmp(line, "%MAKEDEPENDS%") == 0) {
				/* currently unused */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
				}
			} else if(strcmp(line, "%CHECKDEPENDS%") == 0) {
				/* currently unused */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
				}
			} else if(strcmp(line, "%CONFLICTS%") == 0) {
				READ_AND_SPLITDEP(pkg->conflicts);
			} else if(strcmp(line, "%PROVIDES%") == 0) {
				READ_AND_SPLITDEP(pkg->provides);
			} else if(strcmp(line, "%DELTAS%") == 0) {
				/* Different than the rest because of the _alpm_delta_parse call. */
				while(1) {
					READ_NEXT();
					if(strlen(line) == 0) break;
					pkg->deltas = alpm_list_add(pkg->deltas,
							_alpm_delta_parse(db->handle, line));
				}
			}
		}
		if(ret != ARCHIVE_EOF) {
			goto error;
		}
		*likely_pkg = pkg;
	} else if(strcmp(filename, "files") == 0) {
		/* currently do nothing with this file */
	} else {
		/* unknown database file */
		_alpm_log(db->handle, ALPM_LOG_DEBUG, "unknown database file: %s\n", filename);
	}

	return 0;

error:
	_alpm_log(db->handle, ALPM_LOG_DEBUG, "error parsing database file: %s\n", filename);
	return -1;
}
예제 #25
0
파일: sync.c 프로젝트: vadmium/pacman-arch
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
{
	alpm_list_t *i, *j;
	alpm_list_t *deps = NULL;
	alpm_list_t *unresolvable = NULL;
	size_t from_sync = 0;
	int ret = 0;
	alpm_trans_t *trans = handle->trans;

	if(data) {
		*data = NULL;
	}

	for(i = trans->add; i; i = i->next) {
		alpm_pkg_t *spkg = i->data;
		from_sync += (spkg->origin == ALPM_PKG_FROM_SYNCDB);
	}

	/* ensure all sync database are valid if we will be using them */
	for(i = handle->dbs_sync; i; i = i->next) {
		const alpm_db_t *db = i->data;
		if(db->status & DB_STATUS_INVALID) {
			RET_ERR(handle, ALPM_ERR_DB_INVALID, -1);
		}
		/* missing databases are not allowed if we have sync targets */
		if(from_sync && db->status & DB_STATUS_MISSING) {
			RET_ERR(handle, ALPM_ERR_DB_NOT_FOUND, -1);
		}
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		alpm_list_t *resolved = NULL;
		alpm_list_t *remove = NULL;
		alpm_list_t *localpkgs;

		/* Build up list by repeatedly resolving each transaction package */
		/* Resolve targets dependencies */
		EVENT(handle, ALPM_EVENT_RESOLVEDEPS_START, NULL, NULL);
		_alpm_log(handle, ALPM_LOG_DEBUG, "resolving target's dependencies\n");

		/* build remove list for resolvedeps */
		for(i = trans->add; i; i = i->next) {
			alpm_pkg_t *spkg = i->data;
			for(j = spkg->removes; j; j = j->next) {
				remove = alpm_list_add(remove, j->data);
			}
		}

		/* Compute the fake local database for resolvedeps (partial fix for the
		 * phonon/qt issue) */
		localpkgs = alpm_list_diff(_alpm_db_get_pkgcache(handle->db_local),
				trans->add, _alpm_pkg_cmp);

		/* Resolve packages in the transaction one at a time, in addition
		   building up a list of packages which could not be resolved. */
		for(i = trans->add; i; i = i->next) {
			alpm_pkg_t *pkg = i->data;
			if(_alpm_resolvedeps(handle, localpkgs, pkg, trans->add,
						&resolved, remove, data) == -1) {
				unresolvable = alpm_list_add(unresolvable, pkg);
			}
			/* Else, [resolved] now additionally contains [pkg] and all of its
			   dependencies not already on the list */
		}
		alpm_list_free(localpkgs);
		alpm_list_free(remove);

		/* If there were unresolvable top-level packages, prompt the user to
		   see if they'd like to ignore them rather than failing the sync */
		if(unresolvable != NULL) {
			int remove_unresolvable = 0;
			alpm_errno_t saved_err = handle->pm_errno;
			QUESTION(handle, ALPM_QUESTION_REMOVE_PKGS, unresolvable,
					NULL, NULL, &remove_unresolvable);
			if(remove_unresolvable) {
				/* User wants to remove the unresolvable packages from the
				   transaction. The packages will be removed from the actual
				   transaction when the transaction packages are replaced with a
				   dependency-reordered list below */
				handle->pm_errno = 0;
				if(data) {
					alpm_list_free_inner(*data, (alpm_list_fn_free)_alpm_depmiss_free);
					alpm_list_free(*data);
					*data = NULL;
				}
			} else {
				/* pm_errno was set by resolvedeps, callback may have overwrote it */
				handle->pm_errno = saved_err;
				alpm_list_free(resolved);
				ret = -1;
				goto cleanup;
			}
		}

		/* Set DEPEND reason for pulled packages */
		for(i = resolved; i; i = i->next) {
			alpm_pkg_t *pkg = i->data;
			if(!alpm_pkg_find(trans->add, pkg->name)) {
				pkg->reason = ALPM_PKG_REASON_DEPEND;
			}
		}

		/* Unresolvable packages will be removed from the target list; set these
		 * aside in the transaction as a list we won't operate on. If we free them
		 * before the end of the transaction, we may kill pointers the frontend
		 * holds to package objects. */
		trans->unresolvable = unresolvable;

		/* re-order w.r.t. dependencies */
		alpm_list_free(trans->add);
		trans->add = _alpm_sortbydeps(handle, resolved, 0);
		alpm_list_free(resolved);

		EVENT(handle, ALPM_EVENT_RESOLVEDEPS_DONE, NULL, NULL);
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NOCONFLICTS)) {
		/* check for inter-conflicts and whatnot */
		EVENT(handle, ALPM_EVENT_INTERCONFLICTS_START, NULL, NULL);

		_alpm_log(handle, ALPM_LOG_DEBUG, "looking for conflicts\n");

		/* 1. check for conflicts in the target list */
		_alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs targets\n");
		deps = _alpm_innerconflicts(handle, trans->add);

		for(i = deps; i; i = i->next) {
			alpm_conflict_t *conflict = i->data;
			alpm_pkg_t *rsync, *sync, *sync1, *sync2;

			/* have we already removed one of the conflicting targets? */
			sync1 = alpm_pkg_find(trans->add, conflict->package1);
			sync2 = alpm_pkg_find(trans->add, conflict->package2);
			if(!sync1 || !sync2) {
				continue;
			}

			_alpm_log(handle, ALPM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n",
					conflict->package1, conflict->package2);

			/* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */
			alpm_depend_t *dep1 = _alpm_splitdep(conflict->package1);
			alpm_depend_t *dep2 = _alpm_splitdep(conflict->package2);
			if(_alpm_depcmp(sync1, dep2)) {
				rsync = sync2;
				sync = sync1;
			} else if(_alpm_depcmp(sync2, dep1)) {
				rsync = sync1;
				sync = sync2;
			} else {
				_alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
				handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS;
				ret = -1;
				if(data) {
					alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict);
					if(newconflict) {
						*data = alpm_list_add(*data, newconflict);
					}
				}
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
				alpm_list_free(deps);
				_alpm_dep_free(dep1);
				_alpm_dep_free(dep2);
				goto cleanup;
			}
			_alpm_dep_free(dep1);
			_alpm_dep_free(dep2);

			/* Prints warning */
			_alpm_log(handle, ALPM_LOG_WARNING,
					_("removing '%s' from target list because it conflicts with '%s'\n"),
					rsync->name, sync->name);
			trans->add = alpm_list_remove(trans->add, rsync, _alpm_pkg_cmp, NULL);
			/* rsync is not a transaction target anymore */
			trans->unresolvable = alpm_list_add(trans->unresolvable, rsync);
			continue;
		}

		alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
		alpm_list_free(deps);
		deps = NULL;

		/* 2. we check for target vs db conflicts (and resolve)*/
		_alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs db and db vs targets\n");
		deps = _alpm_outerconflicts(handle->db_local, trans->add);

		for(i = deps; i; i = i->next) {
			alpm_conflict_t *conflict = i->data;

			/* if conflict->package2 (the local package) is not elected for removal,
			   we ask the user */
			int found = 0;
			for(j = trans->add; j && !found; j = j->next) {
				alpm_pkg_t *spkg = j->data;
				if(alpm_pkg_find(spkg->removes, conflict->package2)) {
					found = 1;
				}
			}
			if(found) {
				continue;
			}

			_alpm_log(handle, ALPM_LOG_DEBUG, "package '%s' conflicts with '%s'\n",
					conflict->package1, conflict->package2);

			alpm_pkg_t *sync = alpm_pkg_find(trans->add, conflict->package1);
			alpm_pkg_t *local = _alpm_db_get_pkgfromcache(handle->db_local, conflict->package2);
			int doremove = 0;
			QUESTION(handle, ALPM_QUESTION_CONFLICT_PKG, conflict->package1,
							conflict->package2, conflict->reason->name, &doremove);
			if(doremove) {
				/* append to the removes list */
				_alpm_log(handle, ALPM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2);
				sync->removes = alpm_list_add(sync->removes, local);
			} else { /* abort */
				_alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
				handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS;
				ret = -1;
				if(data) {
					alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict);
					if(newconflict) {
						*data = alpm_list_add(*data, newconflict);
					}
				}
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
				alpm_list_free(deps);
				goto cleanup;
			}
		}
		EVENT(handle, ALPM_EVENT_INTERCONFLICTS_DONE, NULL, NULL);
		alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
		alpm_list_free(deps);
	}

	/* Build trans->remove list */
	for(i = trans->add; i; i = i->next) {
		alpm_pkg_t *spkg = i->data;
		for(j = spkg->removes; j; j = j->next) {
			alpm_pkg_t *rpkg = j->data;
			if(!alpm_pkg_find(trans->remove, rpkg->name)) {
				alpm_pkg_t *copy;
				_alpm_log(handle, ALPM_LOG_DEBUG, "adding '%s' to remove list\n", rpkg->name);
				if(_alpm_pkg_dup(rpkg, &copy) == -1) {
					return -1;
				}
				trans->remove = alpm_list_add(trans->remove, copy);
			}
		}
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n");
		deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local),
				trans->remove, trans->add, 1);
		if(deps) {
			handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS;
			ret = -1;
			if(data) {
				*data = deps;
			} else {
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
				alpm_list_free(deps);
			}
			goto cleanup;
		}
	}
	for(i = trans->add; i; i = i->next) {
		/* update download size field */
		alpm_pkg_t *spkg = i->data;
		if(compute_download_size(spkg) < 0) {
			ret = -1;
			goto cleanup;
		}
	}

cleanup:
	return ret;
}
예제 #26
0
파일: util.c 프로젝트: sandsmark/pacman
/** Unpack a list of files in an archive.
 * @param handle the context handle
 * @param path the archive to unpack
 * @param prefix where to extract the files
 * @param list a list of files within the archive to unpack or NULL for all
 * @param breakfirst break after the first entry found
 * @return 0 on success, 1 on failure
 */
int _alpm_unpack(alpm_handle_t *handle, const char *path, const char *prefix,
		alpm_list_t *list, int breakfirst)
{
	int ret = 0;
	mode_t oldmask;
	struct archive *archive;
	struct archive_entry *entry;
	struct stat buf;
	int fd, cwdfd;

	fd = _alpm_open_archive(handle, path, &buf, &archive, ALPM_ERR_PKG_OPEN);
	if(fd < 0) {
		return 1;
	}

	oldmask = umask(0022);

	/* save the cwd so we can restore it later */
	OPEN(cwdfd, ".", O_RDONLY);
	if(cwdfd < 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
	}

	/* just in case our cwd was removed in the upgrade operation */
	if(chdir(prefix) != 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
				prefix, strerror(errno));
		ret = 1;
		goto cleanup;
	}

	while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
		const char *entryname;
		mode_t mode;

		entryname = archive_entry_pathname(entry);

		/* If specific files were requested, skip entries that don't match. */
		if(list) {
			char *entry_prefix = strdup(entryname);
			char *p = strstr(entry_prefix,"/");
			if(p) {
				*(p+1) = '\0';
			}
			char *found = alpm_list_find_str(list, entry_prefix);
			free(entry_prefix);
			if(!found) {
				if(archive_read_data_skip(archive) != ARCHIVE_OK) {
					ret = 1;
					goto cleanup;
				}
				continue;
			} else {
				_alpm_log(handle, ALPM_LOG_DEBUG, "extracting: %s\n", entryname);
			}
		}

		mode = archive_entry_mode(entry);
		if(S_ISREG(mode)) {
			archive_entry_set_perm(entry, 0644);
		} else if(S_ISDIR(mode)) {
			archive_entry_set_perm(entry, 0755);
		}

		/* Extract the archive entry. */
		int readret = archive_read_extract(archive, entry, 0);
		if(readret == ARCHIVE_WARN) {
			/* operation succeeded but a non-critical error was encountered */
			_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
					entryname, archive_error_string(archive));
		} else if(readret != ARCHIVE_OK) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
					entryname, archive_error_string(archive));
			ret = 1;
			goto cleanup;
		}

		if(breakfirst) {
			break;
		}
	}

cleanup:
	umask(oldmask);
	archive_read_finish(archive);
	CLOSE(fd);
	if(cwdfd >= 0) {
		if(fchdir(cwdfd) != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("could not restore working directory (%s)\n"), strerror(errno));
		}
		CLOSE(cwdfd);
	}

	return ret;
}
예제 #27
0
파일: be_local.c 프로젝트: moben/pacman
static int local_db_populate(alpm_db_t *db)
{
	size_t est_count;
	int count = 0;
	struct stat buf;
	struct dirent *ent = NULL;
	const char *dbpath;
	DIR *dbdir;

	if(db->status & DB_STATUS_INVALID) {
		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
	}
	/* note: DB_STATUS_MISSING is not fatal for local database */

	dbpath = _alpm_db_path(db);
	if(dbpath == NULL) {
		/* pm_errno set in _alpm_db_path() */
		return -1;
	}

	dbdir = opendir(dbpath);
	if(dbdir == NULL) {
		if(errno == ENOENT) {
			/* no database existing yet is not an error */
			db->status &= ~DB_STATUS_EXISTS;
			db->status |= DB_STATUS_MISSING;
			return 0;
		}
		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
	}
	if(fstat(dirfd(dbdir), &buf) != 0) {
		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
	}
	db->status |= DB_STATUS_EXISTS;
	db->status &= ~DB_STATUS_MISSING;
	if(buf.st_nlink >= 2) {
		est_count = buf.st_nlink;
	} else {
		/* Some filesystems don't subscribe to the two-implicit links school of
		 * thought, e.g. BTRFS, HFS+. See
		 * http://kerneltrap.org/mailarchive/linux-btrfs/2010/1/23/6723483/thread
		 */
		est_count = 0;
		while(readdir(dbdir) != NULL) {
			est_count++;
		}
		rewinddir(dbdir);
	}
	if(est_count >= 2) {
		/* subtract the two extra pointers to get # of children */
		est_count -= 2;
	}

	/* initialize hash at 50% full */
	db->pkgcache = _alpm_pkghash_create(est_count * 2);
	if(db->pkgcache == NULL){
		closedir(dbdir);
		RET_ERR(db->handle, ALPM_ERR_MEMORY, -1);
	}

	while((ent = readdir(dbdir)) != NULL) {
		const char *name = ent->d_name;

		alpm_pkg_t *pkg;

		if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
			continue;
		}
		if(!is_dir(dbpath, ent)) {
			continue;
		}

		pkg = _alpm_pkg_new();
		if(pkg == NULL) {
			closedir(dbdir);
			RET_ERR(db->handle, ALPM_ERR_MEMORY, -1);
		}
		/* split the db entry name */
		if(_alpm_splitname(name, &(pkg->name), &(pkg->version),
					&(pkg->name_hash)) != 0) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
					name);
			_alpm_pkg_free(pkg);
			continue;
		}

		/* duplicated database entries are not allowed */
		if(_alpm_pkghash_find(db->pkgcache, pkg->name)) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
			_alpm_pkg_free(pkg);
			continue;
		}

		pkg->origin = PKG_FROM_LOCALDB;
		pkg->origin_data.db = db;
		pkg->ops = &local_pkg_ops;
		pkg->handle = db->handle;

		/* explicitly read with only 'BASE' data, accessors will handle the rest */
		if(local_db_read(pkg, INFRQ_BASE) == -1) {
			_alpm_log(db->handle, ALPM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
			_alpm_pkg_free(pkg);
			continue;
		}

		/* add to the collection */
		_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
				pkg->name, db->treename);
		db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg);
		count++;
	}

	closedir(dbdir);
	if(count > 0) {
		db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
	}
	_alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n",
			count, db->treename);

	return count;
}
예제 #28
0
파일: util.c 프로젝트: sandsmark/pacman
/** Execute a command with arguments in a chroot.
 * @param handle the context handle
 * @param cmd command to execute
 * @param argv arguments to pass to cmd
 * @return 0 on success, 1 on error
 */
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
{
	pid_t pid;
	int pipefd[2], cwdfd;
	int retval = 0;

	/* save the cwd so we can restore it later */
	OPEN(cwdfd, ".", O_RDONLY);
	if(cwdfd < 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
	}

	/* just in case our cwd was removed in the upgrade operation */
	if(chdir(handle->root) != 0) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
				handle->root, strerror(errno));
		goto cleanup;
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n",
			cmd, handle->root);

	/* Flush open fds before fork() to avoid cloning buffers */
	fflush(NULL);

	if(pipe(pipefd) == -1) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
		retval = 1;
		goto cleanup;
	}

	/* fork- parent and child each have seperate code blocks below */
	pid = fork();
	if(pid == -1) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno));
		retval = 1;
		goto cleanup;
	}

	if(pid == 0) {
		/* this code runs for the child only (the actual chroot/exec) */
		CLOSE(1);
		CLOSE(2);
		while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
		while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
		CLOSE(pipefd[0]);
		CLOSE(pipefd[1]);

		/* use fprintf instead of _alpm_log to send output through the parent */
		if(chroot(handle->root) != 0) {
			fprintf(stderr, _("could not change the root directory (%s)\n"), strerror(errno));
			exit(1);
		}
		if(chdir("/") != 0) {
			fprintf(stderr, _("could not change directory to %s (%s)\n"),
					"/", strerror(errno));
			exit(1);
		}
		umask(0022);
		execv(cmd, argv);
		/* execv only returns if there was an error */
		fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));
		exit(1);
	} else {
		/* this code runs for the parent only (wait on the child) */
		int status;
		FILE *pipe_file;

		CLOSE(pipefd[1]);
		pipe_file = fdopen(pipefd[0], "r");
		if(pipe_file == NULL) {
			CLOSE(pipefd[0]);
			retval = 1;
		} else {
			while(!feof(pipe_file)) {
				char line[PATH_MAX];
				if(fgets(line, PATH_MAX, pipe_file) == NULL)
					break;
				alpm_logaction(handle, "%s", line);
				EVENT(handle, ALPM_EVENT_SCRIPTLET_INFO, line, NULL);
			}
			fclose(pipe_file);
		}

		while(waitpid(pid, &status, 0) == -1) {
			if(errno != EINTR) {
				_alpm_log(handle, ALPM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno));
				retval = 1;
				goto cleanup;
			}
		}

		/* report error from above after the child has exited */
		if(retval != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not open pipe (%s)\n"), strerror(errno));
			goto cleanup;
		}
		/* check the return status, make sure it is 0 (success) */
		if(WIFEXITED(status)) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "call to waitpid succeeded\n");
			if(WEXITSTATUS(status) != 0) {
				_alpm_log(handle, ALPM_LOG_ERROR, _("command failed to execute correctly\n"));
				retval = 1;
			}
		}
	}

cleanup:
	if(cwdfd >= 0) {
		if(fchdir(cwdfd) != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("could not restore working directory (%s)\n"), strerror(errno));
		}
		CLOSE(cwdfd);
	}

	return retval;
}
예제 #29
0
파일: add.c 프로젝트: Alexpux/MSYS2-pacman
static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
		struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
{
	const char *entryname = archive_entry_pathname(entry);
	mode_t entrymode = archive_entry_mode(entry);
	alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg);
	char filename[PATH_MAX]; /* the actual file we're extracting */
	int needbackup = 0, notouch = 0;
	const char *hash_orig = NULL;
	int isnewfile = 0, errors = 0;
	struct stat lsbuf;
	size_t filename_len;

	if(*entryname == '.') {
		return extract_db_file(handle, archive, entry, newpkg, entryname);
	}

	if (!alpm_filelist_contains(&newpkg->files, entryname)) {
		_alpm_log(handle, ALPM_LOG_WARNING,
				_("file not found in file list for package %s. skipping extraction of %s\n"),
				newpkg->name, entryname);
		return 0;
	}

	/* build the new entryname relative to handle->root */
	filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
	if(filename_len >= PATH_MAX) {
		_alpm_log(handle, ALPM_LOG_ERROR,
				_("unable to extract %s%s: path too long"), handle->root, entryname);
		return 1;
	}

	/* if a file is in NoExtract then we never extract it */
	if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract,"
				" skipping extraction of %s\n",
				entryname, filename);
		archive_read_data_skip(archive);
		return 0;
	}

	/* Check for file existence. This is one of the more crucial parts
	 * to get 'right'. Here are the possibilities, with the filesystem
	 * on the left and the package on the top:
	 * (F=file, N=node, S=symlink, D=dir)
	 *               |  F/N  |   D
	 *  non-existent |   1   |   2
	 *  F/N          |   3   |   4
	 *  D            |   5   |   6
	 *
	 *  1,2- extract, no magic necessary. lstat (llstat) will fail here.
	 *  3,4- conflict checks should have caught this. either overwrite
	 *      or backup the file.
	 *  5- file replacing directory- don't allow it.
	 *  6- skip extraction, dir already exists.
	 */

	isnewfile = llstat(filename, &lsbuf) != 0;
	if(isnewfile) {
		/* cases 1,2: file doesn't exist, skip all backup checks */
	} else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) {
#if 0
		uid_t entryuid = archive_entry_uid(entry);
		gid_t entrygid = archive_entry_gid(entry);
#endif

		/* case 6: existing dir, ignore it */
		if(lsbuf.st_mode != entrymode) {
			/* if filesystem perms are different than pkg perms, warn user */
			mode_t mask = 07777;
			_alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
					"filesystem: %o  package: %o\n"), filename, lsbuf.st_mode & mask,
					entrymode & mask);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: directory permissions differ on %s\n"
					"filesystem: %o  package: %o\n", filename, lsbuf.st_mode & mask,
					entrymode & mask);
		}
#ifndef __MSYS__

#if 0
		/* Disable this warning until our user management in packages has improved.
		   Currently many packages have to create users in post_install and chown the
		   directories. These all resulted in "false-positive" warnings. */

		if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) {
			_alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n"
					"filesystem: %u:%u  package: %u:%u\n"), filename,
					lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: directory ownership differs on %s\n"
					"filesystem: %u:%u  package: %u:%u\n", filename,
					lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
		}
#endif

#endif
		_alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
				filename);
		archive_read_data_skip(archive);
		return 0;
	} else if(S_ISDIR(lsbuf.st_mode)) {
		/* case 5: trying to overwrite dir with file, don't allow it */
		_alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
				filename);
		archive_read_data_skip(archive);
		return 1;
	} else if(S_ISDIR(entrymode)) {
		/* case 4: trying to overwrite file with dir */
		_alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
				filename);
	} else {
		/* case 3: trying to overwrite file with file */
		/* if file is in NoUpgrade, don't touch it */
		if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) {
			notouch = 1;
		} else {
			alpm_backup_t *oldbackup;
			if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) {
				hash_orig = oldbackup->hash;
				needbackup = 1;
			} else if(backup) {
				/* allow adding backup files retroactively */
				needbackup = 1;
			}
		}
	}

	if(notouch || needbackup) {
		if(filename_len + strlen(".pacnew") >= PATH_MAX) {
			_alpm_log(handle, ALPM_LOG_ERROR,
					_("unable to extract %s.pacnew: path too long"), filename);
			return 1;
		}
		strcpy(filename + filename_len, ".pacnew");
		isnewfile = (llstat(filename, &lsbuf) != 0 && errno == ENOENT);
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
	if(perform_extraction(handle, archive, entry, filename)) {
		errors++;
		return errors;
	}

	if(backup) {
		FREE(backup->hash);
		backup->hash = alpm_compute_md5sum(filename);
	}

	if(notouch) {
		alpm_event_pacnew_created_t event = {
			.type = ALPM_EVENT_PACNEW_CREATED,
			.from_noupgrade = 1,
			.oldpkg = oldpkg,
			.newpkg = newpkg,
			.file = filename
		};
		/* "remove" the .pacnew suffix */
		filename[filename_len] = '\0';
		EVENT(handle, &event);
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"warning: %s installed as %s.pacnew\n", filename, filename);
	} else if(needbackup) {
		char *hash_local = NULL, *hash_pkg = NULL;
		char origfile[PATH_MAX] = "";

		strncat(origfile, filename, filename_len);

		hash_local = alpm_compute_md5sum(origfile);
		hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename);

		_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile);
		_alpm_log(handle, ALPM_LOG_DEBUG, "current:  %s\n", hash_local);
		_alpm_log(handle, ALPM_LOG_DEBUG, "new:      %s\n", hash_pkg);
		_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);

		if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
			/* local and new files are the same, updating anyway to get
			 * correct timestamps */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					origfile);
			if(try_rename(handle, filename, origfile)) {
				errors++;
			}
		} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
			/* original and new files are the same, leave the local version alone,
			 * including any user changes */
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"action: leaving existing file in place\n");
			if(isnewfile) {
				unlink(filename);
			}
		} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
			/* installed file has NOT been changed by user,
			 * update to the new version */
			_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
					origfile);
			if(try_rename(handle, filename, origfile)) {
				errors++;
			}
		} else {
			/* none of the three files matched another,  leave the unpacked
			 * file alongside the local file */
			alpm_event_pacnew_created_t event = {
				.type = ALPM_EVENT_PACNEW_CREATED,
				.from_noupgrade = 0,
				.oldpkg = oldpkg,
				.newpkg = newpkg,
				.file = origfile
			};
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"action: keeping current file and installing"
					" new one with .pacnew ending\n");
			EVENT(handle, &event);
			alpm_logaction(handle, ALPM_CALLER_PREFIX,
					"warning: %s installed as %s\n", origfile, filename);
		}

		free(hash_local);
		if(!backup) {
			free(hash_pkg);
		}
	}
	return errors;
}

static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
		size_t pkg_current, size_t pkg_count)
{
	int i, ret = 0, errors = 0;
	int is_upgrade = 0;
	alpm_pkg_t *oldpkg = NULL;
	alpm_db_t *db = handle->db_local;
	alpm_trans_t *trans = handle->trans;
	alpm_progress_t progress = ALPM_PROGRESS_ADD_START;
	alpm_event_package_operation_t event;
	const char *log_msg = "adding";
	const char *pkgfile;

	ASSERT(trans != NULL, return -1);

	/* see if this is an upgrade. if so, remove the old package first */
	if((oldpkg = newpkg->oldpkg)) {
		int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg);
		if(cmp < 0) {
			log_msg = "downgrading";
			progress = ALPM_PROGRESS_DOWNGRADE_START;
			event.operation = ALPM_PACKAGE_DOWNGRADE;
		} else if(cmp == 0) {
			log_msg = "reinstalling";
			progress = ALPM_PROGRESS_REINSTALL_START;
			event.operation = ALPM_PACKAGE_REINSTALL;
		} else {
			log_msg = "upgrading";
			progress = ALPM_PROGRESS_UPGRADE_START;
			event.operation = ALPM_PACKAGE_UPGRADE;
		}
		is_upgrade = 1;

		/* copy over the install reason */
		newpkg->reason = alpm_pkg_get_reason(oldpkg);
	} else {
		event.operation = ALPM_PACKAGE_INSTALL;
	}

	event.type = ALPM_EVENT_PACKAGE_OPERATION_START;
	event.oldpkg = oldpkg;
	event.newpkg = newpkg;
	EVENT(handle, &event);

	pkgfile = newpkg->origin_data.file;

	_alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n",
			log_msg, newpkg->name, newpkg->version);
		/* pre_install/pre_upgrade scriptlet */
	if(alpm_pkg_has_scriptlet(newpkg) &&
			!(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
		const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";

		_alpm_runscriptlet(handle, pkgfile, scriptlet_name,
				newpkg->version, oldpkg ? oldpkg->version : NULL, 1);
	}

	/* we override any pre-set reason if we have alldeps or allexplicit set */
	if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) {
		newpkg->reason = ALPM_PKG_REASON_DEPEND;
	} else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) {
		newpkg->reason = ALPM_PKG_REASON_EXPLICIT;
	}

	if(oldpkg) {
		/* set up fake remove transaction */
		if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) {
			handle->pm_errno = ALPM_ERR_TRANS_ABORT;
			ret = -1;
			goto cleanup;
		}
	}

	/* prepare directory for database entries so permission are correct after
	   changelog/install script installation */
	if(_alpm_local_db_prepare(db, newpkg)) {
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"error: could not create database entry %s-%s\n",
				newpkg->name, newpkg->version);
		handle->pm_errno = ALPM_ERR_DB_WRITE;
		ret = -1;
		goto cleanup;
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
		struct archive *archive;
		struct archive_entry *entry;
		struct stat buf;
		int fd, cwdfd;

		_alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");

		fd = _alpm_open_archive(db->handle, pkgfile, &buf,
				&archive, ALPM_ERR_PKG_OPEN);
		if(fd < 0) {
			ret = -1;
			goto cleanup;
		}

		/* save the cwd so we can restore it later */
		OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC);
		if(cwdfd < 0) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
		}

		/* libarchive requires this for extracting hard links */
		if(chdir(handle->root) != 0) {
			_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
					handle->root, strerror(errno));
			_alpm_archive_read_free(archive);
			close(fd);
			ret = -1;
			goto cleanup;
		}

		/* call PROGRESS once with 0 percent, as we sort-of skip that here */
		PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current);

		for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
			int percent;

			if(newpkg->size != 0) {
				/* Using compressed size for calculations here, as newpkg->isize is not
				 * exact when it comes to comparing to the ACTUAL uncompressed size
				 * (missing metadata sizes) */
				int64_t pos = _alpm_archive_compressed_ftell(archive);
				percent = (pos * 100) / newpkg->size;
				if(percent >= 100) {
					percent = 100;
				}
			} else {
				percent = 0;
			}

			PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current);

			/* extract the next file from the archive */
			errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
		}
		_alpm_archive_read_free(archive);
		close(fd);

		/* restore the old cwd if we have it */
		if(cwdfd >= 0) {
			if(fchdir(cwdfd) != 0) {
				_alpm_log(handle, ALPM_LOG_ERROR,
						_("could not restore working directory (%s)\n"), strerror(errno));
			}
			close(cwdfd);
		}

		if(errors) {
			ret = -1;
			if(is_upgrade) {
				_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
						newpkg->name);
				alpm_logaction(handle, ALPM_CALLER_PREFIX,
						"error: problem occurred while upgrading %s\n",
						newpkg->name);
			} else {
				_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"),
						newpkg->name);
				alpm_logaction(handle, ALPM_CALLER_PREFIX,
						"error: problem occurred while installing %s\n",
						newpkg->name);
			}
		}
	}

	/* make an install date (in UTC) */
	newpkg->installdate = time(NULL);

	_alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n");
	_alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);

	if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"),
				newpkg->name, newpkg->version);
		alpm_logaction(handle, ALPM_CALLER_PREFIX,
				"error: could not update database entry %s-%s\n",
				newpkg->name, newpkg->version);
		handle->pm_errno = ALPM_ERR_DB_WRITE;
		ret = -1;
		goto cleanup;
	}

	if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
		_alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
				newpkg->name);
	}

	PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current);

	switch(event.operation) {
		case ALPM_PACKAGE_INSTALL:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n",
					newpkg->name, newpkg->version);
			break;
		case ALPM_PACKAGE_DOWNGRADE:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n",
					newpkg->name, oldpkg->version, newpkg->version);
			break;
		case ALPM_PACKAGE_REINSTALL:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n",
					newpkg->name, newpkg->version);
			break;
		case ALPM_PACKAGE_UPGRADE:
			alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n",
					newpkg->name, oldpkg->version, newpkg->version);
			break;
		default:
			/* we should never reach here */
			break;
	}

	/* run the post-install script if it exists */
	if(alpm_pkg_has_scriptlet(newpkg)
			&& !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
		char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
		const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";

		_alpm_runscriptlet(handle, scriptlet, scriptlet_name,
				newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
		free(scriptlet);
	}

	event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE;
	EVENT(handle, &event);

cleanup:
	return ret;
}
예제 #30
0
/**
 * Search for a GPG key in a remote location.
 * This requires GPGME to call the gpg binary and have a keyserver previously
 * defined in a gpg.conf configuration file.
 * @param handle the context handle
 * @param fpr the fingerprint key ID to look up
 * @param pgpkey storage location for the given key if found
 * @return 1 on success, 0 on key not found, -1 on error
 */
static int key_search(alpm_handle_t *handle, const char *fpr,
		alpm_pgpkey_t *pgpkey)
{
	gpgme_error_t err;
	gpgme_ctx_t ctx;
	gpgme_keylist_mode_t mode;
	gpgme_key_t key;
	int ret = -1;
	size_t fpr_len;
	char *full_fpr;

	/* gpg2 goes full retard here. For key searches ONLY, we need to prefix the
	 * key fingerprint with 0x, or the lookup will fail. */
	fpr_len = strlen(fpr);
	MALLOC(full_fpr, fpr_len + 3, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
	sprintf(full_fpr, "0x%s", fpr);

	memset(&ctx, 0, sizeof(ctx));
	err = gpgme_new(&ctx);
	CHECK_ERR();

	mode = gpgme_get_keylist_mode(ctx);
	/* using LOCAL and EXTERN together doesn't work for GPG 1.X. Ugh. */
	mode &= ~GPGME_KEYLIST_MODE_LOCAL;
	mode |= GPGME_KEYLIST_MODE_EXTERN;
	err = gpgme_set_keylist_mode(ctx, mode);
	CHECK_ERR();

	_alpm_log(handle, ALPM_LOG_DEBUG, "looking up key %s remotely\n", fpr);

	err = gpgme_get_key(ctx, full_fpr, &key, 0);
	if(gpg_err_code(err) == GPG_ERR_EOF) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
		/* Try an alternate lookup using the 8 character fingerprint value, since
		 * busted-ass keyservers can't support lookups using subkeys with the full
		 * value as of now. This is why 2012 is not the year of PGP encryption. */
		if(fpr_len > 8) {
			const char *short_fpr = memcpy(&full_fpr[fpr_len - 8], "0x", 2);
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"looking up key %s remotely\n", short_fpr);
			err = gpgme_get_key(ctx, short_fpr, &key, 0);
			if(gpg_err_code(err) == GPG_ERR_EOF) {
				_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
				ret = 0;
			}
		} else {
			ret = 0;
		}
	}

	if(gpg_err_code(err) != GPG_ERR_NO_ERROR) {
		goto error;
	}

	/* should only get here if key actually exists */
	pgpkey->data = key;
	if(key->subkeys->fpr) {
		pgpkey->fingerprint = key->subkeys->fpr;
	} else if(key->subkeys->keyid) {
		pgpkey->fingerprint = key->subkeys->keyid;
	}
	pgpkey->uid = key->uids->uid;
	pgpkey->name = key->uids->name;
	pgpkey->email = key->uids->email;
	pgpkey->created = key->subkeys->timestamp;
	pgpkey->expires = key->subkeys->expires;
	pgpkey->length = key->subkeys->length;
	pgpkey->revoked = key->subkeys->revoked;

	switch (key->subkeys->pubkey_algo) {
		case GPGME_PK_RSA:
		case GPGME_PK_RSA_E:
		case GPGME_PK_RSA_S:
			pgpkey->pubkey_algo = 'R';
			break;

		case GPGME_PK_DSA:
			pgpkey->pubkey_algo = 'D';
			break;

		case GPGME_PK_ELG_E:
		case GPGME_PK_ELG:
		case GPGME_PK_ECDSA:
		case GPGME_PK_ECDH:
			pgpkey->pubkey_algo = 'E';
			break;
	}

	ret = 1;

error:
	if(ret != 1) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(err));
	}
	free(full_fpr);
	gpgme_release(ctx);
	return ret;
}