summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJudd Vinet <judd@archlinux.org>2002-03-18 10:36:01 +0100
committerJudd Vinet <judd@archlinux.org>2002-03-18 10:36:01 +0100
commit931506031bbf51051200b67f096fe02620e6fbf5 (patch)
tree376688aa41d15928b61525315bf178d9acc656ed
parent8cf35f551fd9cf8dc92c9a7c86fd4485f9cec74a (diff)
downloadpacman-931506031bbf51051200b67f096fe02620e6fbf5.tar.gz
pacman-931506031bbf51051200b67f096fe02620e6fbf5.tar.xz
Imported from pacman-1.2.tar.gz
-rw-r--r--ChangeLog5
-rw-r--r--Makefile9
-rw-r--r--README18
-rwxr-xr-xmakepkg14
-rwxr-xr-xmakepkg.8.in110
-rwxr-xr-xmakeworld4
-rw-r--r--pacman.8.in4
-rw-r--r--pacman.c306
-rw-r--r--pacman.h8
-rwxr-xr-xpacsync281
-rw-r--r--pacsync.8.in53
-rw-r--r--pacsync.conf8
12 files changed, 692 insertions, 128 deletions
diff --git a/ChangeLog b/ChangeLog
index 6a9a6b89..41a3edd0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
VERSION DESCRIPTION
------------------------------------------------------------------
+ -
+1.1 - Fixed some string-handling bugs
+ - Added better handling of configuration files and the like.
+ If "file" is about to be removed, but it is designated to
+ be backed up, then it will be copied to "file.save"
- Changed db_find_conflicts() to ignore directories
1.0 - Initial Release
diff --git a/Makefile b/Makefile
index 5184a572..3e1d0b0d 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ BINDIR = /usr/bin
MANDIR = /usr/man
ETCDIR = /etc
-VERSION = 1.1
+VERSION = 1.2
LIBTAR_VERSION = 1.2.4
CXX = gcc
@@ -45,7 +45,7 @@ pacman: $(OBJECTS)
pacman.o: pacman.c pacman.h
$(CXX) $(CXXFLAGS) -c pacman.c
-man: pacman.8
+man: pacman.8 pacsync.8 makepkg.8
%: %.in
sed -e "s/#VERSION#/$(VERSION)/" $< > $@
@@ -62,11 +62,14 @@ libtar:
install: all
install -D -m0755 pacman $(DESTDIR)$(BINDIR)/pacman
install -D -m0644 pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8
+ install -D -m0644 pacsync.8 $(DESTDIR)$(MANDIR)/man8/pacsync.8
+ install -D -m0644 makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8
install -D -m0755 makepkg $(DESTDIR)$(BINDIR)/makepkg
install -D -m0755 makeworld $(DESTDIR)$(BINDIR)/makeworld
+ install -D -m0755 pacsync $(DESTDIR)$(BINDIR)/pacsync
@echo ""
@echo "*** If this is a first-time install, you should copy makepkg.conf"
- @echo "*** to /etc now."
+ @echo "*** and pacsync.conf to /etc now."
@echo ""
clean:
diff --git a/README b/README
index 26cab790..b39ecedb 100644
--- a/README
+++ b/README
@@ -13,7 +13,17 @@ DESCRIPTION:
upgrade packages in the system, and it will allow you to query the
package database for installed packages, files and owners.
- Plans exist for dependency checking and remote file fetching, as well.
+ Although the package manager itself is quite simple, the pacman tarball
+ also comes with scripts that help automate building and installing
+ packages. These are used extensively in the Arch Build System (ABS),
+ used in Arch Linux <http://www.archlinux.org>. See ABS.txt for more
+ information.
+
+ As of version 1.2, pacsync is included as well. This performs an apt-like
+ function, keeping your system's packages in sync with the packages on
+ a remote server.
+
+ Plans exist for dependency checking as I approach version 2.0.
See TODO for more info.
@@ -32,15 +42,15 @@ Note: Since pacman is compiled statically, you will need the static libraries
BUGS:
-----
-If you find bugs (which is quite likely at version 1.0), please submit
-them to <jvinet@zeroflux.org> with specific information, such as your
+If you find bugs (which is quite likely), please submit them to
+<jvinet@zeroflux.org> with specific information, such as your
commandline, the nature of the bug, and even the package database, if
it helps.
COPYRIGHT:
----------
-pacman is Copyright (c) 2002 Judd vinet <jvinet@zeroflux.org> and is
+pacman is Copyright (c) 2002 Judd Vinet <jvinet@zeroflux.org> and is
licensed through the GNU General Public License (see COPYING).
pacman uses "libtar", a library for reading/writing tar-files. This
diff --git a/makepkg b/makepkg
index c286d7fc..18d5df97 100755
--- a/makepkg
+++ b/makepkg
@@ -1,7 +1,7 @@
#!/bin/bash
me=`basename $0`
-myver='1.1'
+myver='1.2'
startdir=`pwd`
[ -f /etc/makepkg.conf ] && . /etc/makepkg.conf
@@ -30,9 +30,9 @@ for netfile in ${source[@]}; do
if [ -f ../$file ]; then
echo "==> Found $file in build dir" >&2
cp ../$file .
- elif [ -f /var/cache/pkg/$file ]; then
+ elif [ -f /var/cache/pacman/src/$file ]; then
echo "==> Using local copy of $file" >&2
- cp /var/cache/pkg/$file .
+ cp /var/cache/pacman/src/$file .
else
echo "==> Downloading $file" >&2
wget --passive-ftp --no-directories --tries=3 --waitretry=3 $netfile 2>&1
@@ -41,7 +41,7 @@ for netfile in ${source[@]}; do
echo "==> Aborting..." >&2
exit 1
fi
- mkdir -p /var/cache/pkg && cp $file /var/cache/pkg
+ mkdir -p /var/cache/pacman/src && cp $file /var/cache/pacman/src
fi
case $file in
*.tar.gz|*.tar.Z|*.tgz)
@@ -76,6 +76,12 @@ echo "pkgver = $pkgver-$pkgrel" >>.PKGINFO
for bakfile in "${backup[@]}"; do
echo "backup = $bakfile" >>.PKGINFO
done
+if [ "$install" != "" ]; then
+ cat $startdir/$install | egrep '^[^$]' | sed 's/^/install = /g' >>.PKGINFO
+fi
+if [ "$remove" != "" ]; then
+ cat $startdir/$remove | egrep '^[^$]' | sed 's/^/remove = /g' >>.PKGINFO
+fi
# remove info/doc files
cd $startdir
diff --git a/makepkg.8.in b/makepkg.8.in
new file mode 100755
index 00000000..a7430770
--- /dev/null
+++ b/makepkg.8.in
@@ -0,0 +1,110 @@
+.TH makepkg 8 "Mar 17, 2002" "makepkg #VERSION#" ""
+.SH NAME
+makepkg \- package build utility
+.SH SYNOPSIS
+\fBmakepkg\fP
+.SH DESCRIPTION
+\fBmakepkg\fP will build packages for you. All it needs is
+a build-capable linux platform, wget, and some build scripts. The advantage
+to a script-based build is that you only really do the work once. Once you
+have the build script for a package, you just need to run makepkg and it
+will do the rest: download source files, configure the buildtime settings,
+build the package, install the package into a temporary root, make
+customizations, and package the whole thing up for pacman to use.
+
+\fBmakeworld\fP can be used to rebuild an entire package group, or the
+entire build tree.
+.SH BUILD PROCESS (or How To Build Your Own Packages)
+Start in an isolated directory (ie, it's not used for anything other
+than building this package). The build script should be called PKGBUILD
+and it should bear resemblance to the example below.
+
+.TP
+.TP
+.SH PKGBUILD Example:
+.RS
+.nf
+pkgname=modutils
+pkgver=2.4.13
+pkgrel=1
+backup=(etc/modules.conf)
+source=(ftp://ftp.server.com/$pkgname-$pkgver.tar.gz modules.conf)
+
+build() {
+ cd $startdir/src/$pkgname-$pkgver
+ ./configure --prefix=/usr
+ make || return 1
+ make prefix=$startdir/pkg/usr install
+ # copy our custom modules.conf into the package root
+ mkdir -p $startdir/pkg/etc
+ cp ../modules.conf $startdir/pkg/etc
+}
+.fi
+.RE
+
+As you can see, the setup is fairly simple. The first three lines define
+the package name and version info. They also define the final package name,
+which will be of the form $pkgname-$pkgver-$pkgrel.pkg.tar.gz
+
+The sources are then decompressed (if necessary) into a directory called ./src.
+Then the \fIbuild\fP function is called. This is where all package configuration,
+building, and installing should be done. Any customization will likely take
+place here.
+
+After a package is built, the \fIbuild\fP function must install the package
+files into a special package root, which can be referenced by \fB$startdir/pkg\fP
+in the \fIbuild\fP function. The typical way to do this is one of the following:
+.RS
+.nf
+
+make DESTDIR=$startdir/pkg install
+
+or
+
+make prefix=$startdir/pkg/usr install
+
+.fi
+.RE
+Notice that the "/usr" portion should be present with "prefix", but not "DESTDIR."
+
+Once the package is successfully installed into the package root, \fImakepkg\fP
+will remove some directories (as per Arch Linux package guidelines; if you use
+this elsewhere, feel free to change it) like /usr/doc and /usr/info. It will
+then strip debugging info from libraries and binaries and compress
+
+.SH PKGBUILD Directives
+.TP
+.B backup
+A space-delimited array of filenames (without a preceiding slash). The
+\fIbackup\fP line will be propagated to the package meta-info file for
+pacman. This will designate all files listed there to be backed up if this
+package is ever removed from a system.
+
+.TP
+.B source
+The \fIsource\fP line is an array of source files required to build the
+package. Source files must reside in the same directory as the PKGBUILD
+file, unless they have a fully-qualified URL. Then if the source file
+does not already exist in /var/cache/pacman/src, the file is downloaded
+by wget.
+
+.TP
+.B install
+There is also an \fIinstall\fP directive that is not used in the example
+above. If \fIinstall\fP is set to the name of a file in the package build
+directory (but \fBnot\fP listed in the source line), then it will be
+copied to the package meta-info file and designated as a post-install script.
+This will be run by pacman whenever it installs the package.
+
+.SH CONFIGURATION
+Configuration options are stored in /etc/makepkg.conf. This file is parsed
+as a bash script, so you can export any special compiler flags you wish
+to use. This is helpful for building for different architectures, or with
+different optimizations.
+
+\fBNOTE:\fP This does not guarantee that all package Makefiles will use
+your exported variables. Some of them are flaky...
+.SH AUTHOR
+.nf
+Judd Vinet <jvinet@zeroflux.org>
+.fi
diff --git a/makeworld b/makeworld
index 883e5ad5..e517321a 100755
--- a/makeworld
+++ b/makeworld
@@ -1,11 +1,15 @@
#!/bin/bash
toplevel=`pwd`
+version="1.2"
if [ $# -lt 2 ]; then
+ echo "makepkg version $version"
echo "usage: $0 <destdir> <category> [category] ..."
echo " where <category> is base, opt, etc."
echo " eg: makeworld /packages base opt extra"
+ echo
+ echo " this should be run from the toplevel directory of ABS (usually /usr/abs)"
exit 1
fi
diff --git a/pacman.8.in b/pacman.8.in
index a7e720ed..86783836 100644
--- a/pacman.8.in
+++ b/pacman.8.in
@@ -1,8 +1,8 @@
-.TH pacman 8 "Feb 10, 2002" "pacman #VERSION#" ""
+.TH pacman 8 "Mar 17, 2002" "pacman #VERSION#" ""
.SH NAME
pacman \- package manager utility
.SH SYNOPSIS
-\fBpacman <operation> [options] <package>\fP
+\fBpacman <operation> [options] <package> [package] ...\fP
.SH DESCRIPTION
\fBpacman\fP is a \fIpackage management\fP utility. Package
information is maintained in a basic text format for easy
diff --git a/pacman.c b/pacman.c
index 0a686925..5f01e5ff 100644
--- a/pacman.c
+++ b/pacman.c
@@ -95,15 +95,21 @@ unsigned short pmo_q_info = 0;
unsigned short pmo_q_list = 0;
char* pmo_q_owns = NULL;
-pkginfo_t** packages = NULL;
-unsigned int pkgcount = 0;
+/* list of installed packages */
+pkginfo_t** pm_packages = NULL;
+unsigned int pm_pkgcount = 0;
+/* list of targets specified on command line */
+fileset_t pm_targets = NULL;
+unsigned int pm_targct = 0;
+
+/* path to post-install script, if any */
+char* pm_install = NULL;
int main(int argc, char* argv[])
{
pm_opfunc_t op_func;
- char* funcvar = NULL;
- int ret = 0;
+ int i, ret = 0;
/* default root */
pmo_root = (char*)malloc(2);
@@ -118,16 +124,16 @@ int main(int argc, char* argv[])
/* the handler function */
if(!strcmp(argv[1], "-A") || !strcmp(argv[1], "--add")) {
op_func = pacman_add;
- funcvar = parseargs(PM_ADD, argc, argv);
+ ret = parseargs(PM_ADD, argc, argv);
} else if(!strcmp(argv[1], "-R") || !strcmp(argv[1], "--remove")) {
op_func = pacman_remove;
- funcvar = parseargs(PM_REMOVE, argc, argv);
+ ret = parseargs(PM_REMOVE, argc, argv);
} else if(!strcmp(argv[1], "-Q") || !strcmp(argv[1], "--query")) {
op_func = pacman_query;
- funcvar = parseargs(PM_QUERY, argc, argv);
+ ret = parseargs(PM_QUERY, argc, argv);
} else if(!strcmp(argv[1], "-U") || !strcmp(argv[1], "--upgrade")) {
op_func = pacman_upgrade;
- funcvar = parseargs(PM_UPGRADE, argc, argv);
+ ret = parseargs(PM_UPGRADE, argc, argv);
} else if(!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
usage(PM_MAIN, (char*)basename(argv[0]));
return(1);
@@ -135,16 +141,21 @@ int main(int argc, char* argv[])
version();
return(1);
} else {
- printf("error: invalid operation\n\n");
+ fprintf(stderr, "error: invalid operation\n\n");
usage(PM_MAIN, (char*)basename(argv[0]));
return(1);
}
- if(funcvar == NULL && op_func != pacman_query) {
+ if(ret || (pm_targct < 1 && op_func != pacman_query)) {
return(1);
}
vprint("Installation Root: %s\n", pmo_root);
- vprint("Package Name: %s\n", funcvar);
+ if(pm_targct) {
+ vprint("Targets:\n");
+ for(i = 0; i < pm_targct; i++) {
+ vprint(" %s\n", pm_targets[i]);
+ }
+ }
/* check for db existence */
if(pmo_root != NULL) {
@@ -161,27 +172,40 @@ int main(int argc, char* argv[])
ret = db_open(dbpath);
if(ret == 1) {
- printf("error: Could not open package database file!\n");
- printf(" Check to see that %s exists.\n", dbpath);
- printf(" If not, you may simply create it by \"touch\"-ing it.\n");
+ fprintf(stderr, "error: Could not open package database file!\n");
+ fprintf(stderr, " Check to see that %s exists.\n", dbpath);
+ fprintf(stderr, " If not, you may simply create it by \"touch\"-ing it.\n");
return(1);
}
if(ret == 2) {
- printf("error: Database is corrupt! You may need to use the backup database.\n");
- printf(" I hope you like tweaking... ;-)\n");
+ fprintf(stderr, "error: Database is corrupt! You may need to use the backup database.\n");
+ fprintf(stderr, " I hope you like tweaking... ;-)\n");
return(1);
}
/* start the requested operation */
if(!pmo_nofunc) {
- ret = op_func(funcvar);
- if(ret) {
- printf("There were errors\n");
+ for(i = 0; i < pm_targct; i++) {
+ if(op_func(pm_targets[i])) {
+ ret = 1;
+ }
+ }
+ if(op_func == pacman_query && pm_targct == 0) {
+ ret = op_func(NULL);
}
}
+
+ if(op_func == pacman_remove) {
+ /* the remove function no longer updates the db itself. we do it here
+ * instead, in an effort to save some expensive file rewrites. note that we
+ * can't do this for pacman_add() yet, as he's gotta call db_find_conflicts
+ * for each package.
+ */
+ ret = db_update(NULL, 0);
+ }
fclose(dbfp);
- return(0);
+ return(ret);
}
int pacman_add(char* pkgfile)
@@ -206,13 +230,13 @@ int pacman_add(char* pkgfile)
vprint("Looking for DB conflicts...\n");
if((i = db_find_conflicts(files, filecount)) == 1) {
if(pmo_force) {
- printf("\nInstalling package anyway...\n");
- printf(" You might have duplicate entries in your package\n");
- printf(" database now. You may want to edit it and remove\n");
- printf(" one of the copies.\n\n");
+ fprintf(stderr, "\nInstalling package anyway...\n");
+ fprintf(stderr, " You might have duplicate entries in your package\n");
+ fprintf(stderr, " database now. You may want to edit it and remove\n");
+ fprintf(stderr, " one of the copies.\n\n");
} else {
- printf("Aborting...\n");
- printf(" (use -f to override)\n\n");
+ fprintf(stderr, "Aborting...\n");
+ fprintf(stderr, " (use -f to override)\n\n");
return(1);
}
} else if(i == 2) {
@@ -225,7 +249,11 @@ int pacman_add(char* pkgfile)
if(pmo_upgrade) {
vprint("Removing old package first...\n");
if(pacman_remove(pkgname)) {
- printf("\nUpgrade aborted.\n");
+ fprintf(stderr, "\nUpgrade aborted.\n");
+ return(1);
+ }
+ if(db_update(NULL, 0)) {
+ fprintf(stderr, "\nError updating database. Upgrade aborted.\n");
return(1);
}
}
@@ -257,11 +285,11 @@ int pacman_add(char* pkgfile)
strcpy(newpath, expath);
strcat(newpath, ".save");
rename(expath, newpath);
- printf("%s renamed to %s\n", expath, newpath);
+ fprintf(stderr, "%s renamed to %s\n", expath, newpath);
}
if(tar_extract_file(tar, expath)) {
errmsg = strerror(errno);
- printf("could not extract %s: %s\n", th_get_pathname(tar), errmsg);
+ fprintf(stderr, "could not extract %s: %s\n", th_get_pathname(tar), errmsg);
errors = 1;
}
free(expath);
@@ -269,16 +297,29 @@ int pacman_add(char* pkgfile)
tar_close(tar);
vprint("Done.\n");
if(errors) {
- printf("There were errors. No database update was performed.\n");
+ fprintf(stderr, "There were errors. No database update was performed.\n");
+ return(1);
} else {
vprint("Updating database...\n");
if(db_update(files, filecount)) {
- printf("error: Could not update database! The database may not\n");
- printf(" be in a sane state!\n");
+ fprintf(stderr, "error: Could not update database! The database may not\n");
+ fprintf(stderr, " be in a sane state!\n");
return(1);
}
vprint("Done.\n");
}
+
+ /* run the script in pm_install */
+ if(pm_install != NULL) {
+ vprint("Executing post-install script...\n");
+ expath = (char*)malloc(256);
+ snprintf(expath, 255, "/bin/bash %s", pm_install);
+ system(expath);
+ free(expath);
+ unlink(pm_install);
+ free(pm_install);
+ }
+
return(0);
}
@@ -286,7 +327,7 @@ int pacman_remove(char* pkgfile)
{
int found = 0, done = 0;
int i;
- char line[255];
+ char line[PATH_MAX+1];
fileset_t files = NULL;
unsigned int filecount = 0, nb = 0;
struct stat buf;
@@ -304,17 +345,17 @@ int pacman_remove(char* pkgfile)
strcpy(line, trim(line));
if(!strcmp(line, pkgfile)) {
/* read the version */
- fgets(line, 255, dbfp);
+ fgets(line, 63, dbfp);
found = 1;
}
}
if(!found) {
- printf("Cannot remove %s: Package was not found.\n", pkgfile);
+ fprintf(stderr, "Cannot remove %s: Package was not found.\n", pkgfile);
return(1);
}
while(!done) {
- fgets(line, 255, dbfp);
+ fgets(line, PATH_MAX, dbfp);
strcpy(line, trim(line));
if(strlen(line)) {
/* add the path to the list */
@@ -347,13 +388,13 @@ int pacman_remove(char* pkgfile)
/* perror("cannot remove directory"); */
}
} else {
- /* if the file ends in .conf, back it up */
+ /* if the file is flagged, back it up to .save */
if(!pmo_nosave && nb) {
newpath = (char*)realloc(newpath, strlen(file)+6);
strcpy(newpath, file);
strcat(newpath, ".save");
rename(file, newpath);
- printf("%s renamed to %s\n", file, newpath);
+ fprintf(stderr, "%s renamed to %s\n", file, newpath);
} else {
vprint(" unlinking %s\n", file);
if(unlink(file)) {
@@ -365,31 +406,31 @@ int pacman_remove(char* pkgfile)
/* now splice this name out of the packages list */
found = 0;
- for(i = 0; i < pkgcount-1; i++) {
+ for(i = 0; i < pm_pkgcount-1; i++) {
if(found) {
- packages[i] = packages[i+1];
+ pm_packages[i] = pm_packages[i+1];
} else {
- if(!strcmp(packages[i]->name, pkgfile)) {
+ if(!strcmp(pm_packages[i]->name, pkgfile)) {
found = 1;
- if(i < pkgcount-1) {
- packages[i] = packages[i+1];
+ if(i < pm_pkgcount-1) {
+ pm_packages[i] = pm_packages[i+1];
}
}
}
}
/* drop the last item */
- packages = (pkginfo_t**)realloc(packages, (--pkgcount)*sizeof(pkginfo_t*));
+ pm_packages = (pkginfo_t**)realloc(pm_packages, (--pm_pkgcount)*sizeof(pkginfo_t*));
- /* and commit the db */
- return(db_update(NULL, 0));
+ /* the db will be commited back up in main() */
+ return(0);
}
int pacman_query(char* pkgfile)
{
char *str = NULL;
- char name[255];
- char ver[255];
- char line[255];
+ char name[256];
+ char ver[64];
+ char line[PATH_MAX+1];
int found = 0;
int done = 0;
int i;
@@ -422,22 +463,25 @@ int pacman_query(char* pkgfile)
while(!found && !feof(dbfp)) {
fgets(name, 255, dbfp);
strcpy(name, trim(name));
- fgets(ver, 255, dbfp);
+ fgets(ver, 63, dbfp);
strcpy(ver, trim(ver));
strcpy(line, " ");
while(strlen(line) && !feof(dbfp)) {
- fgets(line, 255, dbfp);
+ fgets(line, PATH_MAX, dbfp);
strcpy(line, trim(line));
str = line;
+ if(line[0] == '*') {
+ str++;
+ }
str += strlen(pmo_root);
- if(!strcmp(line, pmo_q_owns)) {
+ if(!strcmp(str, pmo_q_owns)) {
printf("%s %s\n", name, ver);
return(0);
}
}
}
- printf("No package owns this file.\n");
- return(0);
+ fprintf(stderr, "No package owns this file.\n");
+ return(2);
}
/* find packages in the db */
@@ -449,7 +493,7 @@ int pacman_query(char* pkgfile)
strcpy(name, trim(name));
if(pkgfile == NULL || (pkgfile != NULL && !strcmp(name, pkgfile))) {
/* read the version */
- fgets(ver, 255, dbfp);
+ fgets(ver, 63, dbfp);
strcpy(ver, trim(ver));
found = 1;
if(pkgfile != NULL) {
@@ -459,13 +503,14 @@ int pacman_query(char* pkgfile)
}
if(feof(dbfp)) {
if(pkgfile != NULL && !found) {
- printf("Package was not found in database.\n");
+ fprintf(stderr, "Package \"%s\" was not found in database.\n", pkgfile);
+ return(2);
}
break;
}
found = 0;
while(!found) {
- fgets(line, 255, dbfp);
+ fgets(line, PATH_MAX, dbfp);
strcpy(line, trim(line));
if(strlen(line)) {
if(pmo_q_list) {
@@ -494,9 +539,8 @@ int pacman_upgrade(char* pkgfile)
{
/* this is basically just a remove,add process. pacman_add() will */
/* handle it */
- pmo_upgrade = 1;
- pacman_add(pkgfile);
- return(0);
+ pmo_upgrade = 1;
+ return pacman_add(pkgfile);
}
/*
@@ -559,10 +603,10 @@ int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output)
}
tar_close(tar);
+ free(descfile);
+
if(pkgname == NULL || pkgver == NULL) {
- printf("The current version of Pacman requires a .PKGINFO file\n");
- printf("present in the .tar.gz archive. This package does not\n");
- printf("have one.\n");
+ fprintf(stderr, "Error: Missing .PKGINFO file in %s\n", pkgfile);
return(0);
}
@@ -575,26 +619,38 @@ int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output)
*/
int db_open(char* path)
{
- char line[255];
+ char line[PATH_MAX+1];
+ int i;
pkginfo_t* info;
+
+ /* if pm_packages already contains data, free it first */
+ if(pm_pkgcount) {
+ for(i = 0; i < pm_pkgcount; i++) {
+ free(pm_packages[i]);
+ }
+ free(pm_packages);
+ pm_packages = NULL;
+ pm_pkgcount = 0;
+ }
+
dbfp = fopen(path, "r");
if(dbfp == NULL) {
return(1);
}
while(!feof(dbfp)) {
info = (pkginfo_t*)malloc(sizeof(pkginfo_t));
- fgets(line, 64, dbfp);
+ fgets(line, sizeof(info->name)-1, dbfp);
if(feof(dbfp)) {
break;
}
strcpy(info->name, trim(line));
- fgets(line, 32, dbfp);
+ fgets(line, sizeof(info->version)-1, dbfp);
strcpy(info->version, trim(line));
/* add to the collective */
- packages = (pkginfo_t**)realloc(packages, (++pkgcount) * sizeof(pkginfo_t*));
- packages[pkgcount-1] = info;
+ pm_packages = (pkginfo_t**)realloc(pm_packages, (++pm_pkgcount) * sizeof(pkginfo_t*));
+ pm_packages[pm_pkgcount-1] = info;
for(;;) {
- fgets(line, 255, dbfp);
+ fgets(line, PATH_MAX, dbfp);
if(feof(dbfp)) {
return(2);
}
@@ -617,12 +673,12 @@ int db_open(char* path)
*/
int db_update(fileset_t files, unsigned int filecount)
{
- FILE* olddb;
+ FILE* olddb = NULL;
char* newpath = NULL;
char* str = NULL;
- char name[64];
- char ver[32];
- char line[255];
+ char name[256];
+ char ver[64];
+ char line[PATH_MAX+1];
int i = 0, found = 0, done = 0;
/* build the backup pathname */
@@ -643,21 +699,21 @@ int db_update(fileset_t files, unsigned int filecount)
rewind(olddb);
while(!feof(olddb)) {
- if(!fgets(name, 64, olddb)) {
+ if(!fgets(name, 255, olddb)) {
break;
}
strcpy(name, trim(name));
- fgets(ver, 32, olddb);
+ fgets(ver, 63, olddb);
found = 0;
- for(i = 0; i < pkgcount && !found; i++) {
- if(!strcmp(packages[i]->name, name)) {
+ for(i = 0; i < pm_pkgcount && !found; i++) {
+ if(!strcmp(pm_packages[i]->name, name)) {
/* it's there... copy the entries over */
found = 1;
fputs(name, dbfp);
fputc('\n', dbfp);
fputs(ver, dbfp);
for(done = 0; !done;) {
- fgets(line, 255, olddb);
+ fgets(line, PATH_MAX, olddb);
if(found) {
fputs(line, dbfp);
}
@@ -670,7 +726,7 @@ int db_update(fileset_t files, unsigned int filecount)
if(!found) {
/* skip through filelist for this package */
for(done = 0; !done;) {
- fgets(line, 255, olddb);
+ fgets(line, PATH_MAX, olddb);
if(strlen(trim(line)) == 0 || feof(olddb)) {
done = 1;
}
@@ -713,8 +769,8 @@ int db_update(fileset_t files, unsigned int filecount)
int db_find_conflicts(fileset_t files, unsigned int filecount)
{
int i;
- char line[255];
- char name[255];
+ char line[PATH_MAX+1];
+ char name[256];
char* dbstr = NULL;
char* filestr = NULL;
struct stat buf;
@@ -726,13 +782,13 @@ int db_find_conflicts(fileset_t files, unsigned int filecount)
fgets(name, 255, dbfp);
strcpy(name, trim(name));
if(!pmo_upgrade && !strcmp(name, pkgname)) {
- printf("error: This package is already installed.\n");
- printf(" Maybe you should be using --upgrade.\n");
+ fprintf(stderr, "error: This package is already installed.\n");
+ fprintf(stderr, " Maybe you should be using --upgrade.\n");
return(2);
}
- fgets(line, 255, dbfp);
+ fgets(line, 64, dbfp);
while(!feof(dbfp)) {
- fgets(line, 255, dbfp);
+ fgets(line, PATH_MAX, dbfp);
strcpy(line, trim(line));
dbstr = line;
if(dbstr[0] == '*') {
@@ -742,6 +798,7 @@ int db_find_conflicts(fileset_t files, unsigned int filecount)
break;
}
if(index(dbstr, '/') == dbstr && (!pmo_upgrade || strcmp(name,pkgname))) {
+ /* we're looking at a file in the db that belongs to a different package */
for(i = 0; i < filecount; i++) {
filestr = files[i];
if(filestr[0] == '*') {
@@ -752,7 +809,7 @@ int db_find_conflicts(fileset_t files, unsigned int filecount)
/* this filename has a trailing '/', so it's a directory -- skip it. */
continue;
}
- printf("conflict: %s already exists in package \"%s\"\n", dbstr, name);
+ fprintf(stderr, "conflict: %s already exists in package \"%s\"\n", dbstr, name);
conflicts = 1;
}
}
@@ -768,7 +825,7 @@ int db_find_conflicts(fileset_t files, unsigned int filecount)
filestr++;
}
if(!stat(filestr, &buf) && !S_ISDIR(buf.st_mode)) {
- printf("conflict: %s already exists in filesystem\n", filestr);
+ fprintf(stderr, "conflict: %s already exists in filesystem\n", filestr);
conflicts = 1;
}
}
@@ -785,8 +842,9 @@ int db_find_conflicts(fileset_t files, unsigned int filecount)
int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
unsigned int* bakct)
{
- FILE* fp;
- char line[255];
+ FILE* fp = NULL;
+ FILE* inst = NULL;
+ char line[PATH_MAX+1];
char* ptr = NULL;
char* key = NULL;
int linenum = 0;
@@ -799,7 +857,7 @@ int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
}
while(!feof(fp)) {
- fgets(line, 255, fp);
+ fgets(line, PATH_MAX, fp);
if(output) {
printf("%s", line);
}
@@ -814,7 +872,7 @@ int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
ptr = line;
key = strsep(&ptr, "=");
if(key == NULL || ptr == NULL) {
- printf("Syntax error in description file line %d\n", linenum);
+ fprintf(stderr, "Syntax error in description file line %d\n", linenum);
} else {
key = trim(key);
key = strtoupper(key);
@@ -827,12 +885,25 @@ int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
strcpy(pkgver, ptr);
} else if(!strcmp(key, "PKGDESC")) {
/* Not used yet */
+ } else if(!strcmp(key, "INSTALL")) {
+ if(inst == NULL) {
+ pm_install = (char*)malloc(strlen("/tmp/pacman_XXXXXX")+1);
+ strcpy(pm_install, "/tmp/pacman_XXXXXX");
+ mkstemp(pm_install);
+ inst = fopen(pm_install, "w");
+ if(inst == NULL) {
+ perror("fopen");
+ return(1);
+ }
+ }
+ fputs(ptr, inst);
+ fputc('\n', inst);
} else if(!strcmp(key, "BACKUP")) {
backup = (fileset_t)realloc(backup, (++count) * sizeof(char*));
backup[count-1] = (char*)malloc(strlen(ptr)+1);
strcpy(backup[count-1], ptr);
} else {
- printf("Syntax error in description file line %d\n", linenum);
+ fprintf(stderr, "Syntax error in description file line %d\n", linenum);
}
}
line[0] = '\0';
@@ -840,6 +911,11 @@ int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
fclose(fp);
unlink(descfile);
+ if(inst != NULL) {
+ fputs("exit 0\n", inst);
+ fclose(inst);
+ }
+
if(count > 0) {
(*bakptr) = backup;
(*bakct) = count;
@@ -853,19 +929,21 @@ int parse_descfile(char* descfile, unsigned short output, fileset_t *bakptr,
* argc: argc
* argv: argv
*
- * Returns: the functional variable for that operation
- * (eg, the package file name for PM_ADD)
+ * Returns: 0 on success, 1 on error
*/
-char* parseargs(int op, int argc, char** argv)
+int parseargs(int op, int argc, char** argv)
{
- char* pkg = NULL;
int i;
for(i = 2; i < argc; i++) {
+ if(strlen(argv[i]) > PATH_MAX) {
+ fprintf(stderr, "error: argument %d is too long.\n", i);
+ return(1);
+ }
if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
pmo_nofunc = 1;
usage(op, (char*)basename(argv[0]));
- return(NULL);
+ return(1);
} else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
pmo_verbose = 1;
} else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--force")) {
@@ -873,14 +951,14 @@ char* parseargs(int op, int argc, char** argv)
} else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--root")) {
i++;
if(i >= argc) {
- printf("error: missing argument for %s\n", argv[i-1]);
- return(NULL);
+ fprintf(stderr, "error: missing argument for %s\n", argv[i-1]);
+ return(1);
}
free(pmo_root);
pmo_root = (char*)malloc(PATH_MAX);
if(realpath(argv[i], pmo_root) == NULL) {
perror("bad root path");
- return(NULL);
+ return(1);
}
} else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--nosave")) {
pmo_nosave = 1;
@@ -888,15 +966,19 @@ char* parseargs(int op, int argc, char** argv)
/* PM_QUERY only */
i++;
if(i >= argc) {
- printf("error: missing argument for %s\n", argv[i-1]);
- return(NULL);
+ fprintf(stderr, "error: missing argument for %s\n", argv[i-1]);
+ return(1);
+ }
+ if(strlen(argv[i]) > PATH_MAX) {
+ fprintf(stderr, "error: argument %d is too long.\n", i);
+ return(1);
}
free(pmo_q_owns);
pmo_q_owns = (char*)malloc(PATH_MAX);
if(realpath(argv[i], pmo_q_owns) == NULL) {
perror("bad path specified for --owns");
pmo_nofunc = 1;
- return(NULL);
+ return(1);
}
} else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--list")) {
/* PM_QUERY only */
@@ -908,20 +990,22 @@ char* parseargs(int op, int argc, char** argv)
/* PM_QUERY only */
pmo_q_info = 1;
} else {
- pkg = argv[i];
+ /* add the target to our pseudo linked list */
+ pm_targets = (fileset_t)realloc(pm_targets, (++pm_targct) * sizeof(char*));
+ pm_targets[pm_targct-1] = argv[i];
}
}
- if(op != PM_QUERY && pkg == NULL) {
- printf("error: no package specified\n\n");
+ if(op != PM_QUERY && pm_targct < 1) {
+ fprintf(stderr, "error: no package specified\n\n");
usage(op, (char*)basename(argv[0]));
- return(NULL);
+ return(1);
}
- if(op == PM_QUERY && pmo_q_isfile && pkg == NULL) {
- printf("error: no package file specified\n\n");
- return(NULL);
+ if(op == PM_QUERY && pmo_q_isfile && pm_targct < 1) {
+ fprintf(stderr, "error: no package file specified\n\n");
+ return(1);
}
- return(pkg);
+ return(0);
}
/* Display usage/syntax for the specified operation.
diff --git a/pacman.h b/pacman.h
index 76914964..09d471fa 100644
--- a/pacman.h
+++ b/pacman.h
@@ -21,7 +21,7 @@
#ifndef PACMAN_H
#define PACMAN_H
-#define VERSION "1.1"
+#define VERSION "1.2"
#define PKGEXT ".tar.gz"
#define PKGDB "/var/lib/pacman/pacman.db"
@@ -36,8 +36,8 @@
typedef int (*pm_opfunc_t)(char*);
typedef char** fileset_t;
typedef struct __pkginfo_t {
- char version[32];
- char name[64];
+ char version[64];
+ char name[256];
} pkginfo_t;
int pacman_add(char* pkgfile);
@@ -50,7 +50,7 @@ int db_update(fileset_t files, unsigned int filecount);
int db_find_conflicts(fileset_t files, unsigned int filecount);
int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output);
-char* parseargs(int op, int argc, char** argv);
+int parseargs(int op, int argc, char** argv);
int parse_descfile(char* descfile, unsigned short output, fileset_t* bakptr,
unsigned int* bakct);
diff --git a/pacsync b/pacsync
new file mode 100755
index 00000000..61e9106f
--- /dev/null
+++ b/pacsync
@@ -0,0 +1,281 @@
+#!/bin/bash
+
+version="1.2"
+tanpath="/var/lib/pacman"
+tandb="pacsync.db"
+errors=0
+upgrade=0
+
+message() {
+ echo "==> $1" >&2
+}
+
+usage() {
+ echo "pacsync version $version"
+ echo "usage: $0 <operation> [package]"
+ echo ""
+ echo "operations:"
+ echo " sync Download a fresh package list from the server"
+ echo " install <pkg> Download and install <pkg>"
+ echo " upgrade <pkg> Download and upgrade <pkg>"
+ echo " report Generate a report of all packages that could be upgraded"
+ echo " sysupgrade Same as \"report\", but actually do the upgrades"
+ echo " clean Removes all files from package cache to clear up diskspace"
+ echo ""
+}
+
+checkdb() {
+ if [ ! -f $tanpath/$tandb ]; then
+ message "missing package list. (use \"sync\" first)"
+ exit 1
+ fi
+}
+
+download() {
+ targ=$1
+ shift
+ cl=
+ for file in $*; do
+ cl="$cl $SYNC_SERVER/$file"
+ done
+ message "Downloading $targ"
+ $ftpagent $cl
+ if [ $? -gt 0 ]; then
+ message "ERROR: could not download $targ"
+ return 1
+ fi
+ return 0
+}
+
+dosync() {
+ cd /tmp
+ download "package list" $tandb
+ if [ $? -gt 0 ]; then
+ exit 1
+ fi
+ rm -f $tanpath/$tandb
+ mv /tmp/$tandb $tanpath/$tandb
+ message "Done."
+}
+
+doinstall() {
+ pkg2dl=
+ pkg2inst=
+ for pkgname in $*; do
+ line=`egrep "^[a-z]+/$pkgname-[a-z0-9\.]+-[0-9]+\.pkg\.tar\.gz$" $tanpath/$tandb`
+ if [ $? -gt 0 ]; then
+ message "package $pkgname not found"
+ exit 1
+ fi
+ pacman=`pacman -Q $pkgname 2>/dev/null`
+ if [ $? -eq 0 ]; then
+ message "$pkgname is already installed (try using \"upgrade\")"
+ exit 1
+ fi
+ filename=`echo $line | sed 's|^[a-z]*/||g'`
+ pkg2inst="$pkg2inst $filename"
+ if [ ! -f /var/cache/pacman/pkg/$filename ]; then
+ pkg2dl="$pkg2dl arch/$filename"
+ fi
+ done
+
+ # download packages that aren't already cached
+ if [ "$pkg2dl" != "" ]; then
+ download "packages" $pkg2dl
+ if [ $? -gt 0 ]; then
+ exit 1
+ fi
+ if [ `pwd` != "/var/cache/pacman/pkg" ]; then
+ # move downloaded files into cache
+ mkdir -p /var/cache/pacman/pkg
+ mv `echo $pkg2dl | sed 's|arch/||g'` /var/cache/pacman/pkg/
+ fi
+ fi
+
+ # install packages
+ message "Installing packages"
+ cd /var/cache/pacman/pkg
+ pacman -A $pkg2inst
+ if [ $? -gt 0 ]; then
+ echo "ERROR: some packages failed to install"
+ exit 1
+ fi
+
+ message "Done"
+ exit 0
+}
+
+doupgrade() {
+ pkg2dl=
+ pkg2up=
+ for pkgname in $*; do
+ line=`egrep "^[a-z]+/$pkgname-[a-z0-9\.]+-[0-9]+\.pkg\.tar\.gz$" $tanpath/$tandb`
+ if [ $? -gt 0 ]; then
+ message "package $pkgname not found"
+ exit 1
+ fi
+ pacman=`pacman -Q $pkgname 2>/dev/null`
+ if [ $? -gt 0 ]; then
+ message "$pkgname is not installed (use \"install\" first)"
+ exit 1
+ fi
+ pkgver=`echo $pacman | awk '{print $2}'`
+ package="$pkgname-$pkgver"
+ filename=`echo $line | sed 's|^[a-z]*/||g'`
+ # compare filename and package. if they are at all different, we
+ # assume that the newer version is on the server and do the upgrade
+ if [ "$filename" = "$package.pkg.tar.gz" ]; then
+ message "$pkgname is already up to date (skipping)"
+ else
+ pkg2up="$pkg2up $filename"
+ if [ ! -f /var/cache/pacman/pkg/$filename ]; then
+ pkg2dl="$pkg2dl arch/$filename"
+ fi
+ fi
+ done
+
+ # download packages that aren't already cached
+ if [ "$pkg2dl" != "" ]; then
+ download "packages" $pkg2dl
+ if [ $? -gt 0 ]; then
+ exit 1
+ fi
+ if [ `pwd` != "/var/cache/pacman/pkg" ]; then
+ # move downloaded files into cache
+ mkdir -p /var/cache/pacman/pkg
+ mv `echo $pkg2dl | sed 's|arch/||g'` /var/cache/pacman/pkg/
+ fi
+ fi
+
+ # install packages
+ if [ "$pkg2up" != "" ]; then
+ message "Upgrading packages"
+ cd /var/cache/pacman/pkg
+ pacman -U $pkg2up
+ if [ $? -gt 0 ]; then
+ echo "ERROR: some packages failed to upgrade"
+ exit 1
+ fi
+ message "Done"
+ fi
+
+ exit 0
+}
+
+doreport() {
+ headers=0
+ pkg2up=
+ for pkgfile in `cat $tanpath/$tandb | sed "s|^[a-z]*/||g"`; do
+ pkgname=`echo $pkgfile | sed 's|-[a-z0-9\.]*-[0-9]*\.pkg\.tar\.gz||g'`
+ pacman=`pacman -Q $pkgname 2>/dev/null`
+ if [ $? -gt 0 ]; then
+ # skip this one, it's not installed
+ continue
+ fi
+ pkgver=`echo $pacman | awk '{print $2}'`
+ locfile="$pkgname-$pkgver"
+ remfile=`echo $pkgfile | sed 's|^[a-z]*/||g' | sed 's|\.pkg\.tar\.gz||g'`
+ # compare locfile and remfile
+ if [ "$locfile" = "$remfile" ]; then
+ # this package is up to date
+ continue
+ else
+ if [ "$headers" = "0" ]; then
+ echo "+--------------------------------------+--------------------------------------+"
+ echo "| LOCAL | REMOTE |"
+ echo "+--------------------------------------+--------------------------------------+"
+ headers=1
+ fi
+ echo -n "| $locfile"
+ awk "BEGIN { for (j=length(\"$locfile\"); j<36; j++) printf \" \" }"
+ echo -n " | "
+ awk "BEGIN { for (j=length(\"$remfile\"); j<36; j++) printf \" \" }"
+ echo "$remfile |"
+ pkg2up="$pkg2up $pkgname"
+ fi
+ done
+ if [ "$headers" = "1" ]; then
+ echo "+--------------------------------------+--------------------------------------+"
+ fi
+
+ # do we upgrade?
+ if [ "$upgrade" = "1" -a "$pkg2up" != "" ]; then
+ echo ""
+ echo -n "Do you want to upgrade these packages? [Y/n] "
+ read answer
+ echo ""
+ if [ "$answer" = "y" -o "$answer" = "Y" -o "$answer" = "" ]; then
+ doupgrade $pkg2up
+ fi
+ fi
+
+ exit 0
+}
+
+if [ $# -lt 1 ]; then
+ usage
+ exit 0
+fi
+
+if [ -f /etc/pacsync.conf ]; then
+ . /etc/pacsync.conf
+else
+ message "error: missing configuration file!"
+ exit 1
+fi
+
+proto=`echo $SYNC_SERVER | sed 's|://.*||'`
+# check for a download utility
+if [ -x /usr/bin/lftpget -a "$proto" = "ftp" ]; then
+ ftpagent="/usr/bin/lftpget"
+elif [ -x /usr/bin/wget ]; then
+ ftpagent="/usr/bin/wget --passive-ftp --tries=3 --waitretry=3"
+else
+ message "error: you need an ftp client installed (lftp or wget) in /usr/bin"
+ exit 1
+fi
+
+op=$1
+shift
+if [ "$1" = "-v" ]; then
+ verbose=1
+ shift
+fi
+case $op in
+ sync)
+ dosync
+ ;;
+ install)
+ checkdb
+ if [ "$1" = "" ]; then
+ message "error: no package specified"
+ exit 1
+ fi
+ doinstall $*
+ ;;
+ upgrade)
+ checkdb
+ if [ "$1" = "" ]; then
+ message "error: no package specified"
+ exit 1
+ fi
+ doupgrade $*
+ ;;
+ report)
+ checkdb
+ doreport
+ ;;
+ sysupgrade)
+ checkdb
+ upgrade=1
+ doreport
+ ;;
+ clean)
+ message "Removing packages from cache"
+ rm -f /var/cache/pacman/pkg/*
+ ;;
+ *)
+ message "error: invalid operation"
+ exit 1
+ ;;
+esac
diff --git a/pacsync.8.in b/pacsync.8.in
new file mode 100644
index 00000000..a1316637
--- /dev/null
+++ b/pacsync.8.in
@@ -0,0 +1,53 @@
+.TH pacsync 8 "Mar 17, 2002" "pacsync #VERSION#" ""
+.SH NAME
+pacsync \- package update frontend for pacman
+.SH SYNOPSIS
+\fBpacsync <operation> [package] [package] ...\fP
+.SH DESCRIPTION
+\fBpacsync\fP is a \fIpackage update\fP frontend for the
+\fIpacman\fP package manager. It keeps track of the versions
+of packages installed on the local system and the versions of
+packages on a remote server. This allows you to issue a single
+command and have you system's packages brought into sync.
+.SH OPERATIONS
+.TP
+.B "sync"
+Download a new copy of the package list from the server. This
+should be done regularly, usually before an "install", "upgrade"
+or "sysupgrade" command.
+.TP
+.B "install <package>"
+Install a new package. \fBpacsync\fP will first look for the package
+in the cache directory. If it is not there, it will attempt to
+download the file from the server. On success, the package will
+be installed. (Note that the downloaded file is also copied to
+a cache directory on your filesystem. You can delete it with
+"clean").
+.TP
+.B "upgrade <package>"
+Upgrade a package. This is the same as \fIinstall\fP, except a package
+is upgraded (ie, it is already installed in the system).
+.TP
+.B "report"
+Generate an upgrade report. This operation will compare all local
+package versions to remote versions, and then show you a report of
+the differences.
+.TP
+.B "sysupgrade"
+Full system upgrade. This is the same as report except after confirmation,
+\fBpacsync\fP will upgrade all packages that are not up to date.
+.TP
+.B "clean"
+This will remove all downloaded packages from the cache directory. This
+can/should be used regularly to free up diskspace.
+.SH CONFIGURATION
+Configuration options are stored in /etc/pacsync.conf. Currently there is only
+one directive.
+.TP
+.B "SYNC_SERVER"
+This should be set to the full URL of the download server closest to you.
+FTP is preferred, but HTTP is supported also, provided you have wget.
+.SH AUTHOR
+.nf
+Judd Vinet <jvinet@zeroflux.org>
+.fi
diff --git a/pacsync.conf b/pacsync.conf
new file mode 100644
index 00000000..52d54c30
--- /dev/null
+++ b/pacsync.conf
@@ -0,0 +1,8 @@
+#
+# /etc/pacsync.conf
+#
+
+# the full URL of the server (up to the /arch package directory)
+SYNC_SERVER="ftp://ftp.archlinux.org"
+#SYNC_SERVER="http://www.archlinux.org/pub"
+