FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > ArchLinux > ArchLinux Pacman Development

 
 
LinkBack Thread Tools
 
Old 02-17-2008, 02:12 PM
Chantry Xavier
 
Default Add CheckNewVersion option.

This patch offers a way to fix FS#9228.
By putting "CheckNewVersion = pacman" in pacman.conf, the version check will
happen before the transaction really starts, and before any replacements is
made.
Otherwise, no version check is done.

The sync301 pactest was updated to use this CheckNewVersion option.

Example session with CheckNewVersion = pacman, and a newer pacman version
available :
$ pacman -Su (or pacman -S <any targets>)
:: the following packages should be upgraded first :
pacman
:: Do you want to cancel the current operation
:: and upgrade these packages now? [Y/n]

resolving dependencies...
looking for inter-conflicts...

Targets: pacman-x.y.z-t

Total Download Size: x.xx MB
Total Installed Size: x.xx MB

Proceed with installation? [Y/n] n

As Nagy previously noted, doing this check on any -S operations might look
intrusive, but it can be required.
For example, the case where you want to install a package with versioned
provisions, using a pacman version which didn't support that feature yet
(and there is already a newer pacman in sync db supporting it).

Signed-off-by: Chantry Xavier <shiningxc@gmail.com>
---
doc/pacman.conf.5.txt | 6 +++
pactest/pmtest.py | 3 +-
pactest/tests/sync301.py | 4 ++-
src/pacman/conf.c | 2 +
src/pacman/conf.h | 1 +
src/pacman/pacman.c | 8 ++++
src/pacman/sync.c | 81 ++++++++++++++++++++++------------------------
7 files changed, 61 insertions(+), 44 deletions(-)

diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt
index e8f7454..c48ec68 100644
--- a/doc/pacman.conf.5.txt
+++ b/doc/pacman.conf.5.txt
@@ -80,6 +80,12 @@ Options
Instructs pacman to ignore any upgrades for this package when performing
a '--sysupgrade'.

+*CheckNewVersion =* package ...::
+ Instructs pacman to check for newer version of these packages before any
+ '-S' or '-Su' operation. The user will then have the choice to either cancel
+ the current operation and install these packages or go on with the current
+ operation. This could typically be done for pacman itself.
+
*IgnoreGroup =* group ...::
Instructs pacman to ignore any upgrades for all packages in this
group when performing a '--sysupgrade'.
diff --git a/pactest/pmtest.py b/pactest/pmtest.py
index d54d7ba..9b45384 100755
--- a/pactest/pmtest.py
+++ b/pactest/pmtest.py
@@ -83,7 +83,8 @@ class pmtest:
"noupgrade": [],
"ignorepkg": [],
"ignoregroup": [],
- "noextract": []
+ "noextract": [],
+ "checknewversion": [],
}

# Test rules
diff --git a/pactest/tests/sync301.py b/pactest/tests/sync301.py
index e8526b9..cde08c6 100644
--- a/pactest/tests/sync301.py
+++ b/pactest/tests/sync301.py
@@ -16,10 +16,12 @@ self.addpkg2db("local", lp)
lp1 = pmpkg("pkg1", "1.0-1")
self.addpkg2db("local", lp1)

+self.option["checknewversion"] = ["pacman"]
+
self.args = "-Su"

self.addrule("PACMAN_RETCODE=0")
self.addrule("PKG_EXIST=pacman")
self.addrule("PKG_VERSION=pacman|1.0-2")
+self.addrule("PKG_VERSION=pkg1|1.0-1")
self.addrule("PKG_EXIST=dep")
-self.addrule("PKG_REQUIREDBY=dep|pacman")
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index bf3a462..72c1408 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -45,6 +45,7 @@ config_t *config_new(void)
newconfig->rootdir = NULL;
newconfig->dbpath = NULL;
newconfig->logfile = NULL;
+ newconfig->checknewversion = NULL;

return(newconfig);
}
@@ -55,6 +56,7 @@ int config_free(config_t *oldconfig)
return(-1);
}

+ FREELIST(oldconfig->checknewversion);
free(oldconfig->configfile);
free(oldconfig->rootdir);
free(oldconfig->dbpath);
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index f804f56..2bbfb10 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -70,6 +70,7 @@ typedef struct __config_t {
unsigned short totaldownload; /* When downloading, display the amount
downloaded, rate, ETA, and percent
downloaded of the total download list */
+ alpm_list_t *checknewversion;
} config_t;

/* Operations */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index f185320..31af78d 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -515,6 +515,11 @@ static int parseargs(int argc, char *argv[])
return(0);
}

+/* helper for being used with setrepeatingoption */
+void option_add_checknewversion(const char *name) {
+ config->checknewversion = alpm_list_add(config->checknewversion, strdup(name));
+}
+
/** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
* settings. Refactored out of the parseconfig code since all of them did
* the exact same thing and duplicated code.
@@ -675,6 +680,9 @@ static int _parseconfig(const char *file, const char *givensection,
} else if(strcmp(key, "HoldPkg") == 0
|| strcmp(upperkey, "HOLDPKG") == 0) {
setrepeatingoption(ptr, "HoldPkg", alpm_option_add_holdpkg);
+ } else if(strcmp(key, "CheckNewVersion") == 0
+ || strcmp(upperkey, "CHECKNEWVERSION") == 0) {
+ setrepeatingoption(ptr, "CheckNewVersion", option_add_checknewversion);
} else if(strcmp(key, "DBPath") == 0 || strcmp(upperkey, "DBPATH") == 0) {
/* don't overwrite a path specified on the command line */
if(!config->dbpath) {
diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index bb2a8bb..66bd598 100644
--- a/src/pacman/sync.c
+++ b/src/pacman/sync.c
@@ -488,6 +488,24 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
return(0);
}

+static alpm_list_t *checknewversion() {
+ alpm_list_t *i, *res = NULL;
+
+ for(i = config->checknewversion; i; i = alpm_list_next(i)) {
+ char *pkgname = alpm_list_getdata(i);
+ pmpkg_t *pkg = alpm_db_get_pkg(alpm_option_get_localdb(), pkgname);
+ if(pkg == NULL) {
+ continue;
+ }
+
+ if(alpm_sync_newversion(pkg, alpm_option_get_syncdbs())) {
+ res = alpm_list_add(res, strdup(pkgname));
+ }
+ }
+
+ return(res);
+}
+
static int sync_trans(alpm_list_t *targets)
{
int retval = 0;
@@ -507,7 +525,6 @@ static int sync_trans(alpm_list_t *targets)
}

if(config->op_s_upgrade) {
- alpm_list_t *pkgs, *i;
printf(_(":: Starting full system upgrade...
"));
alpm_logaction("starting full system upgrade
");
if(alpm_trans_sysupgrade() == -1) {
@@ -515,46 +532,6 @@ static int sync_trans(alpm_list_t *targets)
retval = 1;
goto cleanup;
}
-
- if(!(alpm_trans_get_flags() & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) {
- /* check if pacman itself is one of the packages to upgrade.
- * this can prevent some of the "syntax error" problems users can have
- * when sysupgrade'ing with an older version of pacman.
- */
- pkgs = alpm_trans_get_pkgs();
- for(i = pkgs; i; i = alpm_list_next(i)) {
- pmsyncpkg_t *sync = alpm_list_getdata(i);
- pmpkg_t *spkg = alpm_sync_get_pkg(sync);
- /* TODO pacman name should probably not be hardcoded. In addition, we
- * have problems on an -Syu if pacman has to pull in deps, so recommend
- * an '-S pacman' operation */
- if(strcmp("pacman", alpm_pkg_get_name(spkg)) == 0) {
- printf("
");
- printf(_(":: pacman has detected a newer version of itself.
"));
- if(yesno(_(":: Do you want to cancel the current operation
"
- ":: and install the new pacman version now? [Y/n] "))) {
- if(alpm_trans_release() == -1) {
- fprintf(stderr, _("error: failed to release transaction (%s)
"),
- alpm_strerrorlast());
- retval = 1;
- goto cleanup;
- }
- if(alpm_trans_init(PM_TRANS_TYPE_SYNC, config->flags,
- cb_trans_evt, cb_trans_conv, cb_trans_progress) == -1) {
- fprintf(stderr, _("error: failed to init transaction (%s)
"),
- alpm_strerrorlast());
- return(1);
- }
- if(alpm_trans_addtarget("pacman") == -1) {
- fprintf(stderr, _("error: pacman: %s
"), alpm_strerrorlast());
- retval = 1;
- goto cleanup;
- }
- break;
- }
- }
- }
- }
} else {
alpm_list_t *i;

@@ -795,7 +772,27 @@ int pacman_sync(alpm_list_t *targets)
}

if(needs_transaction()) {
- if(sync_trans(targets) == 1) {
+ alpm_list_t *targs = alpm_list_strdup(targets);
+ if(!(config->flags & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) {
+ /* check for newer packages version */
+ alpm_list_t *newversion = checknewversion();
+ if(newversion) {
+ printf(_(":: the following packages should be upgraded first :
"));
+ list_display(" ", newversion);
+ if(yesno(_(":: Do you want to cancel the current operation
"
+ ":: and upgrade these packages now? [Y/n] "))) {
+ FREELIST(targs);
+ targs = newversion;
+ config->flags = 0;
+ config->op_s_upgrade = 0;
+ }
+ printf("
");
+ }
+ }
+
+ int ret = sync_trans(targs);
+ FREELIST(targs);
+ if(ret == 1) {
return(1);
}
}
--
1.5.4


_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-18-2008, 05:33 AM
"Dan McGee"
 
Default Add CheckNewVersion option.

On Feb 17, 2008 9:12 AM, Chantry Xavier <shiningxc@gmail.com> wrote:
> This patch offers a way to fix FS#9228.
> By putting "CheckNewVersion = pacman" in pacman.conf, the version check will
> happen before the transaction really starts, and before any replacements is
> made.
> Otherwise, no version check is done.
>
> The sync301 pactest was updated to use this CheckNewVersion option.
>
> Example session with CheckNewVersion = pacman, and a newer pacman version
> available :
> $ pacman -Su (or pacman -S <any targets>)
> :: the following packages should be upgraded first :
> pacman
> :: Do you want to cancel the current operation
> :: and upgrade these packages now? [Y/n]
>
> resolving dependencies...
> looking for inter-conflicts...
>
> Targets: pacman-x.y.z-t
>
> Total Download Size: x.xx MB
> Total Installed Size: x.xx MB
>
> Proceed with installation? [Y/n] n
>
> As Nagy previously noted, doing this check on any -S operations might look
> intrusive, but it can be required.
> For example, the case where you want to install a package with versioned
> provisions, using a pacman version which didn't support that feature yet
> (and there is already a newer pacman in sync db supporting it).

Hmm, so say I put glibc in my CheckNewVersion option list, and I am
not running the version in the sync DB. If I were to do this:
pacman -S mpd

I would be prompted to upgrade glibc? This seems a bit overreaching,
as this is exactly what I did today on my server box. I would
prefer it only be invoked on a --sysupgrade operation. But you do have
a valid point.

I'm also not sure about "CheckNewVersion" from a naming standpoint.
Maybe something more like "UpgradeFirst" or something? We check for a
new version of every package, so the name seems a bit misleading.


> Signed-off-by: Chantry Xavier <shiningxc@gmail.com>
> ---
> doc/pacman.conf.5.txt | 6 +++
> pactest/pmtest.py | 3 +-
> pactest/tests/sync301.py | 4 ++-
> src/pacman/conf.c | 2 +
> src/pacman/conf.h | 1 +
> src/pacman/pacman.c | 8 ++++
> src/pacman/sync.c | 81 ++++++++++++++++++++++------------------------
> 7 files changed, 61 insertions(+), 44 deletions(-)
>
> diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt
> index e8f7454..c48ec68 100644
> --- a/doc/pacman.conf.5.txt
> +++ b/doc/pacman.conf.5.txt
> @@ -80,6 +80,12 @@ Options
> Instructs pacman to ignore any upgrades for this package when performing
> a '--sysupgrade'.
>
> +*CheckNewVersion =* package ...::
> + Instructs pacman to check for newer version of these packages before any
> + '-S' or '-Su' operation. The user will then have the choice to either cancel
> + the current operation and install these packages or go on with the current
> + operation. This could typically be done for pacman itself.
> +
> *IgnoreGroup =* group ...::
> Instructs pacman to ignore any upgrades for all packages in this
> group when performing a '--sysupgrade'.
> diff --git a/pactest/pmtest.py b/pactest/pmtest.py
> index d54d7ba..9b45384 100755
> --- a/pactest/pmtest.py
> +++ b/pactest/pmtest.py
> @@ -83,7 +83,8 @@ class pmtest:
> "noupgrade": [],
> "ignorepkg": [],
> "ignoregroup": [],
> - "noextract": []
> + "noextract": [],
> + "checknewversion": [],
> }
>
> # Test rules
> diff --git a/pactest/tests/sync301.py b/pactest/tests/sync301.py
> index e8526b9..cde08c6 100644
> --- a/pactest/tests/sync301.py
> +++ b/pactest/tests/sync301.py
> @@ -16,10 +16,12 @@ self.addpkg2db("local", lp)
> lp1 = pmpkg("pkg1", "1.0-1")
> self.addpkg2db("local", lp1)
>
> +self.option["checknewversion"] = ["pacman"]
> +
> self.args = "-Su"
>
> self.addrule("PACMAN_RETCODE=0")
> self.addrule("PKG_EXIST=pacman")
> self.addrule("PKG_VERSION=pacman|1.0-2")
> +self.addrule("PKG_VERSION=pkg1|1.0-1")
> self.addrule("PKG_EXIST=dep")
> -self.addrule("PKG_REQUIREDBY=dep|pacman")
> diff --git a/src/pacman/conf.c b/src/pacman/conf.c
> index bf3a462..72c1408 100644
> --- a/src/pacman/conf.c
> +++ b/src/pacman/conf.c
> @@ -45,6 +45,7 @@ config_t *config_new(void)
> newconfig->rootdir = NULL;
> newconfig->dbpath = NULL;
> newconfig->logfile = NULL;
> + newconfig->checknewversion = NULL;
>
> return(newconfig);
> }
> @@ -55,6 +56,7 @@ int config_free(config_t *oldconfig)
> return(-1);
> }
>
> + FREELIST(oldconfig->checknewversion);
> free(oldconfig->configfile);
> free(oldconfig->rootdir);
> free(oldconfig->dbpath);
> diff --git a/src/pacman/conf.h b/src/pacman/conf.h
> index f804f56..2bbfb10 100644
> --- a/src/pacman/conf.h
> +++ b/src/pacman/conf.h
> @@ -70,6 +70,7 @@ typedef struct __config_t {
> unsigned short totaldownload; /* When downloading, display the amount
> downloaded, rate, ETA, and percent
> downloaded of the total download list */
> + alpm_list_t *checknewversion;
> } config_t;
>
> /* Operations */
> diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
> index f185320..31af78d 100644
> --- a/src/pacman/pacman.c
> +++ b/src/pacman/pacman.c
> @@ -515,6 +515,11 @@ static int parseargs(int argc, char *argv[])
> return(0);
> }
>
> +/* helper for being used with setrepeatingoption */
> +void option_add_checknewversion(const char *name) {
> + config->checknewversion = alpm_list_add(config->checknewversion, strdup(name));
> +}
> +
> /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
> * settings. Refactored out of the parseconfig code since all of them did
> * the exact same thing and duplicated code.
> @@ -675,6 +680,9 @@ static int _parseconfig(const char *file, const char *givensection,
> } else if(strcmp(key, "HoldPkg") == 0
> || strcmp(upperkey, "HOLDPKG") == 0) {
> setrepeatingoption(ptr, "HoldPkg", alpm_option_add_holdpkg);
> + } else if(strcmp(key, "CheckNewVersion") == 0
> + || strcmp(upperkey, "CHECKNEWVERSION") == 0) {
> + setrepeatingoption(ptr, "CheckNewVersion", option_add_checknewversion);
> } else if(strcmp(key, "DBPath") == 0 || strcmp(upperkey, "DBPATH") == 0) {
> /* don't overwrite a path specified on the command line */
> if(!config->dbpath) {
> diff --git a/src/pacman/sync.c b/src/pacman/sync.c
> index bb2a8bb..66bd598 100644
> --- a/src/pacman/sync.c
> +++ b/src/pacman/sync.c
> @@ -488,6 +488,24 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
> return(0);
> }
>
> +static alpm_list_t *checknewversion() {
> + alpm_list_t *i, *res = NULL;
> +
> + for(i = config->checknewversion; i; i = alpm_list_next(i)) {
> + char *pkgname = alpm_list_getdata(i);
> + pmpkg_t *pkg = alpm_db_get_pkg(alpm_option_get_localdb(), pkgname);
> + if(pkg == NULL) {
> + continue;
> + }
> +
> + if(alpm_sync_newversion(pkg, alpm_option_get_syncdbs())) {
> + res = alpm_list_add(res, strdup(pkgname));
> + }
> + }
> +
> + return(res);
> +}
> +
> static int sync_trans(alpm_list_t *targets)
> {
> int retval = 0;
> @@ -507,7 +525,6 @@ static int sync_trans(alpm_list_t *targets)
> }
>
> if(config->op_s_upgrade) {
> - alpm_list_t *pkgs, *i;
> printf(_(":: Starting full system upgrade...
"));
> alpm_logaction("starting full system upgrade
");
> if(alpm_trans_sysupgrade() == -1) {
> @@ -515,46 +532,6 @@ static int sync_trans(alpm_list_t *targets)
> retval = 1;
> goto cleanup;
> }
> -
> - if(!(alpm_trans_get_flags() & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) {
> - /* check if pacman itself is one of the packages to upgrade.
> - * this can prevent some of the "syntax error" problems users can have
> - * when sysupgrade'ing with an older version of pacman.
> - */
> - pkgs = alpm_trans_get_pkgs();
> - for(i = pkgs; i; i = alpm_list_next(i)) {
> - pmsyncpkg_t *sync = alpm_list_getdata(i);
> - pmpkg_t *spkg = alpm_sync_get_pkg(sync);
> - /* TODO pacman name should probably not be hardcoded. In addition, we
> - * have problems on an -Syu if pacman has to pull in deps, so recommend
> - * an '-S pacman' operation */
> - if(strcmp("pacman", alpm_pkg_get_name(spkg)) == 0) {
> - printf("
");
> - printf(_(":: pacman has detected a newer version of itself.
"));
> - if(yesno(_(":: Do you want to cancel the current operation
"
> - ":: and install the new pacman version now? [Y/n] "))) {
> - if(alpm_trans_release() == -1) {
> - fprintf(stderr, _("error: failed to release transaction (%s)
"),
> - alpm_strerrorlast());
> - retval = 1;
> - goto cleanup;
> - }
> - if(alpm_trans_init(PM_TRANS_TYPE_SYNC, config->flags,
> - cb_trans_evt, cb_trans_conv, cb_trans_progress) == -1) {
> - fprintf(stderr, _("error: failed to init transaction (%s)
"),
> - alpm_strerrorlast());
> - return(1);
> - }
> - if(alpm_trans_addtarget("pacman") == -1) {
> - fprintf(stderr, _("error: pacman: %s
"), alpm_strerrorlast());
> - retval = 1;
> - goto cleanup;
> - }
> - break;
> - }
> - }
> - }
> - }
Oh so much cleaner now.

> } else {
> alpm_list_t *i;
>
> @@ -795,7 +772,27 @@ int pacman_sync(alpm_list_t *targets)
> }
>
> if(needs_transaction()) {
> - if(sync_trans(targets) == 1) {
> + alpm_list_t *targs = alpm_list_strdup(targets);
> + if(!(config->flags & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) {

Presumably could just add a check for config->op_s_upgrade here. I
just don't know that it makes sense to honor this variable for all -S
ops and not just -Su.

> + /* check for newer packages version */
> + alpm_list_t *newversion = checknewversion();
> + if(newversion) {
> + printf(_(":: the following packages should be upgraded first :
"));
> + list_display(" ", newversion);
> + if(yesno(_(":: Do you want to cancel the current operation
"
> + ":: and upgrade these packages now? [Y/n] "))) {
> + FREELIST(targs);
> + targs = newversion;
> + config->flags = 0;
> + config->op_s_upgrade = 0;
> + }
> + printf("
");
> + }
> + }
> +
> + int ret = sync_trans(targs);
> + FREELIST(targs);
> + if(ret == 1) {
> return(1);
> }
> }
> --
> 1.5.4

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://archlinux.org/mailman/listinfo/pacman-dev
 
Old 02-18-2008, 07:51 AM
Xavier
 
Default Add CheckNewVersion option.

On Mon, Feb 18, 2008 at 12:33:35AM -0600, Dan McGee wrote:
> On Feb 17, 2008 9:12 AM, Chantry Xavier <shiningxc@gmail.com> wrote:
> > As Nagy previously noted, doing this check on any -S operations might look
> > intrusive, but it can be required.
> > For example, the case where you want to install a package with versioned
> > provisions, using a pacman version which didn't support that feature yet
> > (and there is already a newer pacman in sync db supporting it).
>
> Hmm, so say I put glibc in my CheckNewVersion option list, and I am
> not running the version in the sync DB. If I were to do this:
> pacman -S mpd
>
> I would be prompted to upgrade glibc? This seems a bit overreaching,
> as this is exactly what I did today on my server box. I would
> prefer it only be invoked on a --sysupgrade operation. But you do have
> a valid point.
>

In this case, you would not put glibc in that option list.

And well, if there are situations where you would like to see glibc upgraded
first, and others where you would not, you just to answer yes or no to
pacman's question. It's interactive and you can choose the path you want.

To have only glibc in that option list might be dangerous, if the newer glibc
is incompatible with the current pacman. But if both pacman and glibc are
there, it should be fine I think.

> I'm also not sure about "CheckNewVersion" from a naming standpoint.
> Maybe something more like "UpgradeFirst" or something? We check for a
> new version of every package, so the name seems a bit misleading.
>

CheckNewVersion seemed alright, but UpgradeFirst looks better and more
explicit about what it does, I will use that name everywhere.

> > if(needs_transaction()) {
> > - if(sync_trans(targets) == 1) {
> > + alpm_list_t *targs = alpm_list_strdup(targets);
> > + if(!(config->flags & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) {
>
> Presumably could just add a check for config->op_s_upgrade here. I
> just don't know that it makes sense to honor this variable for all -S
> ops and not just -Su.
>

Indeed, it would be easy to do that here. But you didn't convince me with
your previous glibc argument.
Besides, as you just said, we just need to add a simple check to change this
behavior, so it could always be done later if it's really needed

_______________________________________________
pacman-dev mailing list
pacman-dev@archlinux.org
http://archlinux.org/mailman/listinfo/pacman-dev
 

Thread Tools




All times are GMT. The time now is 04:17 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org