NetBSD Problem Report #43013
From www@NetBSD.org Fri Mar 19 14:47:13 2010
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by www.NetBSD.org (Postfix) with ESMTP id B6CD863B86C
for <gnats-bugs@gnats.NetBSD.org>; Fri, 19 Mar 2010 14:47:13 +0000 (UTC)
Message-Id: <20100319144713.4D54263B11D@www.NetBSD.org>
Date: Fri, 19 Mar 2010 14:47:13 +0000 (UTC)
From: brook@nmsu.edu
Reply-To: brook@nmsu.edu
To: gnats-bugs@NetBSD.org
Subject: Clarification of URL handling for pkg_add/pkgin
X-Send-Pr-Version: www-1.0
>Number: 43013
>Category: pkg
>Synopsis: Clarification of URL handling for pkg_add/pkgin
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: joerg
>State: closed
>Class: doc-bug
>Submitter-Id: net
>Arrival-Date: Fri Mar 19 14:50:00 +0000 2010
>Closed-Date: Sat Nov 20 23:38:35 +0000 2010
>Last-Modified: Sat Nov 20 23:38:35 +0000 2010
>Originator: Brook Milligan
>Release: 5.0/i386
>Organization:
New Mexico State University
>Environment:
NetBSD viola.nmsu.edu 5.0_STABLE NetBSD 5.0_STABLE (VIOLA) #0: Thu Jan 28 19:18:43 MST 2010 root@viola.nmsu.edu:/usr/obj/sys/arch/i386/compile/VIOLA i386
>Description:
I recently tried to use pkg_add and pkgin with a remote repository for
the first time. Being very familiar with using full URLs with ftp, I
interpreted the man pages for setting up these programs to mean that
the URLs specified to them would be equivalent to those specified to
ftp for downloading the same file. This of course did not work
because of the following:
- ftp interprets paths relative to the default login directory.
- pkg_add/pkgin use libfetch which precedes accesses with CDUP
commands to reach the root; therefore, paths are relative to the
root of the ftp server.
In my case, these were not the same place, so while ftp worked fine
the other commands did not. Needless to say, this was confusing.
I suggest that an addition to the pkg_add man page (see below) might
have helped me avoid some confusion.
Please improve this if it is technically incorrect or incomplete
(e.g., if http behaves differently), but this does appear to be the
behavior I have observed with ftp.
>How-To-Repeat:
Create an ftp repository with a login directory that is different from the root. Retreive a file with ftp using a URL relative to the login directory. Try to use pkg_add or pkgin to retrieve the same file with the same URL. It will fail. Successfully retrieve the file with pkg_add or pkgin using a URL relative to the root.
>Fix:
Note that this patches only pkg_add.1; it seems that pkg_add.cat1 also exists in the distribution and should be made consistent.
--- pkg_add.1.orig 2010-03-19 08:41:02.000000000 -0600
+++ pkg_add.1 2010-03-19 08:42:22.000000000 -0600
@@ -212,6 +212,8 @@
.Dq .tgz
suffix) or a
URL pointing at a file available on an ftp or web site.
+In the latter case, URLs will be resolved relative to the root of the
+server filesystem not the login directory.
Thus you may extract files directly from their anonymous ftp or WWW
locations (e.g.,
.Nm
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: pkg-manager->joerg
Responsible-Changed-By: joerg@NetBSD.org
Responsible-Changed-When: Fri, 19 Mar 2010 18:06:45 +0000
Responsible-Changed-Why:
RFC1738 bug in fetch(3)
From: Joerg Sonnenberger <joerg@britannica.bec.de>
To: gnats-bugs@NetBSD.org
Cc: brook@nmsu.edu
Subject: Re: pkg/43013: Clarification of URL handling for pkg_add/pkgin
Date: Fri, 19 Mar 2010 19:08:07 +0100
--bp/iNruPH9dso1Pn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Attached is a patch to correctly implement the desired RFC1738 behavior
for FTP.
Joerg
--bp/iNruPH9dso1Pn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ftp-urls.diff"
Index: common.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/bsd/fetch/dist/libfetch/common.c,v
retrieving revision 1.1.1.8
diff -u -p -r1.1.1.8 common.c
--- common.c 30 Jan 2010 21:26:09 -0000 1.1.1.8
+++ common.c 19 Mar 2010 14:25:55 -0000
@@ -231,6 +231,7 @@ fetch_reopen(int sd)
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
+ conn->ftp_home = NULL;
conn->cache_url = NULL;
conn->next_buf = NULL;
conn->next_len = 0;
@@ -711,6 +712,7 @@ fetch_close(conn_t *conn)
ret = close(conn->sd);
if (conn->cache_url)
fetchFreeURL(conn->cache_url);
+ free(conn->ftp_home);
free(conn->buf);
free(conn);
return (ret);
Index: common.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/bsd/fetch/dist/libfetch/common.h,v
retrieving revision 1.1.1.6
diff -u -p -r1.1.1.6 common.h
--- common.h 30 Jan 2010 21:26:09 -0000 1.1.1.6
+++ common.h 19 Mar 2010 14:24:51 -0000
@@ -73,6 +73,8 @@ struct fetchconn {
# endif
#endif
+ char *ftp_home;
+
struct url *cache_url;
int cache_af;
int (*cache_close)(conn_t *);
Index: ftp.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/external/bsd/fetch/dist/libfetch/ftp.c,v
retrieving revision 1.1.1.10
diff -u -p -r1.1.1.10 ftp.c
--- ftp.c 30 Jan 2010 21:26:13 -0000 1.1.1.10
+++ ftp.c 19 Mar 2010 15:56:05 -0000
@@ -252,7 +252,7 @@ ftp_filename(const char *file, int *len,
* command.
*/
static int
-ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen)
+ftp_pwd(conn_t *conn, char **pwd)
{
char *src, *dst, *end;
int q;
@@ -264,7 +264,10 @@ ftp_pwd(conn_t *conn, char *pwd, size_t
src = conn->buf + 4;
if (src >= end || *src++ != '"')
return (FTP_PROTOCOL_ERROR);
- for (q = 0, dst = pwd; src < end && pwdlen--; ++src) {
+ *pwd = malloc(end - src + 1);
+ if (*pwd == NULL)
+ return (FTP_PROTOCOL_ERROR);
+ for (q = 0, dst = *pwd; src < end; ++src) {
if (!q && *src == '"')
q = 1;
else if (q && *src != '"')
@@ -274,9 +277,12 @@ ftp_pwd(conn_t *conn, char *pwd, size_t
else
*dst++ = *src;
}
- if (!pwdlen)
- return (FTP_PROTOCOL_ERROR);
*dst = '\0';
+ if (**pwd != '/') {
+ free(*pwd);
+ *pwd = NULL;
+ return (FTP_PROTOCOL_ERROR);
+ }
return (FTP_OK);
}
@@ -285,69 +291,108 @@ ftp_pwd(conn_t *conn, char *pwd, size_t
* file.
*/
static int
-ftp_cwd(conn_t *conn, const char *file, int subdir)
+ftp_cwd(conn_t *conn, const char *path, int subdir)
{
const char *beg, *end;
- char pwd[PATH_MAX];
+ char *pwd, *dst;
int e, i, len;
- /* If no slashes in name, no need to change dirs. */
- if (subdir)
- end = file + strlen(file);
- else if ((end = strrchr(file, '/')) == NULL)
- return (0);
+ if (*path != '/') {
+ ftp_seterr(501);
+ return (-1);
+ }
+ ++path;
+
+ /* Simple case: still in the home directory and no directory change. */
+ if (conn->ftp_home == NULL && strchr(path, '/') == NULL)
+ return 0;
+
if ((e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY ||
- (e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
+ (e = ftp_pwd(conn, &pwd)) != FTP_OK) {
ftp_seterr(e);
return (-1);
}
+ if (conn->ftp_home == NULL && (conn->ftp_home = strdup(pwd)) == NULL) {
+ fetch_syserr();
+ free(pwd);
+ return (-1);
+ }
+ if (*path == '/') {
+ while (path[1] == '/')
+ ++path;
+ dst = strdup(path);
+ } else if (strcmp(conn->ftp_home, "/") == 0) {
+ dst = strdup(path - 1);
+ } else {
+ asprintf(&dst, "%s/%s", conn->ftp_home, path);
+ }
+ if (dst == NULL) {
+ fetch_syserr();
+ free(pwd);
+ return (-1);
+ }
+
+ if (subdir)
+ end = dst + strlen(dst);
+ else
+ end = strrchr(dst, '/');
+
for (;;) {
len = strlen(pwd);
/* Look for a common prefix between PWD and dir to fetch. */
- for (i = 0; i <= len && i <= end - file; ++i)
- if (pwd[i] != file[i])
+ for (i = 0; i <= len && i <= end - dst; ++i)
+ if (pwd[i] != dst[i])
break;
/* Keep going up a dir until we have a matching prefix. */
if (strcmp(pwd, "/") == 0)
break;
- if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/'))
+ if (pwd[i] == '\0' && (dst[i - 1] == '/' || dst[i] == '/'))
break;
+ free(pwd);
if ((e = ftp_cmd(conn, "CDUP\r\n")) != FTP_FILE_ACTION_OK ||
(e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY ||
- (e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
+ (e = ftp_pwd(conn, &pwd)) != FTP_OK) {
ftp_seterr(e);
+ free(dst);
return (-1);
}
}
+ free(pwd);
#ifdef FTP_COMBINE_CWDS
/* Skip leading slashes, even "////". */
- for (beg = file + i; beg < end && *beg == '/'; ++beg, ++i)
+ for (beg = dst + i; beg < end && *beg == '/'; ++beg, ++i)
/* nothing */ ;
/* If there is no trailing dir, we're already there. */
- if (beg >= end)
+ if (beg >= end) {
+ free(dst);
return (0);
+ }
/* Change to the directory all in one chunk (e.g., foo/bar/baz). */
e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(end - beg), beg);
- if (e == FTP_FILE_ACTION_OK)
+ if (e == FTP_FILE_ACTION_OK) {
+ free(dst);
return (0);
+ }
#endif /* FTP_COMBINE_CWDS */
/* That didn't work so go back to legacy behavior (multiple CWDs). */
- for (beg = file + i; beg < end; beg = file + i + 1) {
+ for (beg = dst + i; beg < end; beg = dst + i + 1) {
while (*beg == '/')
++beg, ++i;
- for (++i; file + i < end && file[i] != '/'; ++i)
+ for (++i; dst + i < end && dst[i] != '/'; ++i)
/* nothing */ ;
- e = ftp_cmd(conn, "CWD %.*s\r\n", file + i - beg, beg);
+ e = ftp_cmd(conn, "CWD %.*s\r\n", dst + i - beg, beg);
if (e != FTP_FILE_ACTION_OK) {
+ free(dst);
ftp_seterr(e);
return (-1);
}
}
+ free(dst);
return (0);
}
--bp/iNruPH9dso1Pn--
From: brook@biology.nmsu.edu (Brook Milligan)
To: gnats-bugs@NetBSD.org
Cc: joerg@NetBSD.org, gnats-admin@netbsd.org, pkgsrc-bugs@netbsd.org,
brook@nmsu.edu
Subject: Re: pkg/43013: Clarification of URL handling for pkg_add/pkgin
Date: Fri, 19 Mar 2010 22:14:30 -0600
Joerg,
I applied your patch, but the same problem remains. As a result, I've
been looking over the code some more and have a few points to note.
I think I have narrowed down the problem that I am seeing. Here is
one section of the calling sequence as indicated by some printf()
statements I added (note that the URL I gave to pkg_add was
ftp://localhost/All/emacs and that the file All/emacs-23.1nb2.tgz
exists in the ftp login directory):
fetchList(): pattern=emacs*, flags=c
fetchListFTP(): NLST
ftp_request(): op=NLST, op_arg=emacs*, flags=c
ftp_request(): path=/All
ftp_cwd(): path=/All, subdir=1
ftp_cwd(): path=All
ftp_cwd(): conn->ftp_home=(null)
ftp_cwd(): strchr(path, '/')=(null)
I think the key point here is the subdir argument to ftp_cwd, which is
initialized by the expression 'op_arg != NULL' in ftp_request().
Since I am requesting /All/emacs* that value seems correct to indicate
that the path requested for cwd (i.e., /All) is a subdirectory not a
file. However, here is the code that is executed within ftp_cwd
immediately after the printf() above:
/* Simple case: still in the home directory and no directory change. */
if (conn->ftp_home == NULL && strchr(path, '/') == NULL)
return 0;
Clearly, this condition holds and ftp_cwd immediately exits.
My analysis of this suggests, however, that only if subdir=0 should
this exit immediately. When there is not a '/' in the path, there are
two cases: (i) the path points to a file (i.e., subdir=0) or (ii) the
path points to the directory in which the file resides (i.e.,
subdir=1). In the example I have above, the second case holds and one
CWD command, not zero, should be emitted.
If all this logic is correct, I would expect something like the
following instead:
--- ftp.c
+++ ftp.c.orig
@@ -304,7 +304,7 @@
++path;
/* Simple case: still in the home directory and no directory change. */
- if (conn->ftp_home == NULL && strchr(path, '/') == NULL)
+ if (conn->ftp_home == NULL && strchr(path, '/') == NULL && !subdir)
return 0;
if ((e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY ||
Indeed, that change makes this example complete correctly.
Since you are much more familiar with all of this code than I, please
verify that my logic is correct and that there are not other
implications of the change I suggest.
Thanks alot for taking a look at this.
Cheers,
Brook
From: Joerg Sonnenberger <joerg@britannica.bec.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: pkg/43013: Clarification of URL handling for pkg_add/pkgin
Date: Sat, 20 Mar 2010 13:40:54 +0100
On Sat, Mar 20, 2010 at 04:15:05AM +0000, Brook Milligan wrote:
> Clearly, this condition holds and ftp_cwd immediately exits.
Right, missed that edge case. Actually, it is should be
(!subdir || *path == '\0').
Joerg
From: Joerg Sonnenberger <joerg@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/43013 CVS commit: pkgsrc/net/libfetch
Date: Sun, 21 Mar 2010 16:48:43 +0000
Module Name: pkgsrc
Committed By: joerg
Date: Sun Mar 21 16:48:43 UTC 2010
Modified Files:
pkgsrc/net/libfetch: Makefile
pkgsrc/net/libfetch/files: common.c common.h ftp.c
Log Message:
libfetch-2.31:
PR 43013 by Brook Milligan: fetch(3) violates RFC 1738 for ftp:// URLs
if the home directory is not the root directory.
Remember the current directory the first time a CWD / CDUP has to be
issued. Use the document as full URL if the URL started with two /
(quoted or not), otherwise append it to the initial directory.
To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 pkgsrc/net/libfetch/Makefile
cvs rdiff -u -r1.25 -r1.26 pkgsrc/net/libfetch/files/common.c
cvs rdiff -u -r1.15 -r1.16 pkgsrc/net/libfetch/files/common.h
cvs rdiff -u -r1.34 -r1.35 pkgsrc/net/libfetch/files/ftp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Joerg Sonnenberger <joerg@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/43013 CVS commit: src/external/bsd/fetch/dist/libfetch
Date: Wed, 24 Mar 2010 20:51:46 +0000
Module Name: src
Committed By: joerg
Date: Wed Mar 24 20:51:46 UTC 2010
Update of /cvsroot/src/external/bsd/fetch/dist/libfetch
In directory ivanova.netbsd.org:/tmp/cvs-serv26424
Log Message:
libfetch-2.31:
PR 43013 by Brook Milligan: fetch(3) violates RFC 1738 for ftp:// URLs
if the home directory is not the root directory.
Remember the current directory the first time a CWD / CDUP has to be
issued. Use the document as full URL if the URL started with two /
(quoted or not), otherwise append it to the initial directory.
Status:
Vendor Tag: PKGSRC
Release Tags: libfetch-2-31
U src/external/bsd/fetch/dist/libfetch/common.c
U src/external/bsd/fetch/dist/libfetch/common.h
U src/external/bsd/fetch/dist/libfetch/errlist.sh
U src/external/bsd/fetch/dist/libfetch/fetch.3
U src/external/bsd/fetch/dist/libfetch/fetch.c
U src/external/bsd/fetch/dist/libfetch/fetch.h
U src/external/bsd/fetch/dist/libfetch/file.c
U src/external/bsd/fetch/dist/libfetch/ftp.c
U src/external/bsd/fetch/dist/libfetch/ftp.errors
U src/external/bsd/fetch/dist/libfetch/http.c
U src/external/bsd/fetch/dist/libfetch/http.errors
No conflicts created by this import
State-Changed-From-To: open->pending-pullups
State-Changed-By: joerg@NetBSD.org
State-Changed-When: Tue, 20 Apr 2010 00:59:34 +0000
State-Changed-Why:
Waiting on releng (#1351 for netbsd-5, #1390 for netbsd-4)
From: Jeff Rizzo <riz@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/43013 CVS commit: [netbsd-4] src/external/bsd/fetch/dist/libfetch
Date: Sun, 13 Jun 2010 05:59:11 +0000
Module Name: src
Committed By: riz
Date: Sun Jun 13 05:59:11 UTC 2010
Modified Files:
src/external/bsd/fetch/dist/libfetch [netbsd-4]: common.c common.h
ftp.c
Removed Files:
src/external/bsd/fetch/dist/libfetch [netbsd-4]: fetch.cat3
Log Message:
Pull up following revision(s) (requested by joerg in ticket #1390):
external/bsd/fetch/dist/libfetch/common.c: patch
external/bsd/fetch/dist/libfetch/common.h: patch
external/bsd/fetch/dist/libfetch/fetch.cat3: removed
external/bsd/fetch/dist/libfetch/ftp.c: patch
libfetch-2.31:
PR 43013 by Brook Milligan: fetch(3) violates RFC 1738 for ftp:// URLs
if the home directory is not the root directory.
Remember the current directory the first time a CWD / CDUP has to be
issued. Use the document as full URL if the URL started with two /
(quoted or not), otherwise append it to the initial directory.
To generate a diff of this commit:
cvs rdiff -u -r1.1.1.5.4.3 -r1.1.1.5.4.4 \
src/external/bsd/fetch/dist/libfetch/common.c
cvs rdiff -u -r1.1.1.4.4.3 -r1.1.1.4.4.4 \
src/external/bsd/fetch/dist/libfetch/common.h
cvs rdiff -u -r1.1.1.3.4.3 -r0 \
src/external/bsd/fetch/dist/libfetch/fetch.cat3
cvs rdiff -u -r1.1.1.6.4.3 -r1.1.1.6.4.4 \
src/external/bsd/fetch/dist/libfetch/ftp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Jeff Rizzo" <riz@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/43013 CVS commit: [netbsd-5] src/external/bsd/fetch/dist/libfetch
Date: Sat, 20 Nov 2010 20:37:41 +0000
Module Name: src
Committed By: riz
Date: Sat Nov 20 20:37:41 UTC 2010
Modified Files:
src/external/bsd/fetch/dist/libfetch [netbsd-5]: common.c common.h
ftp.c
Log Message:
Pull up following revision(s) (requested by joerg in ticket #1351):
external/bsd/fetch/dist/libfetch/common.c: patch
external/bsd/fetch/dist/libfetch/common.h: patch
external/bsd/fetch/dist/libfetch/ftp.c: patch
update to libfetch-2.31:
PR 43013 by Brook Milligan: fetch(3) violates RFC 1738 for ftp:// URLs
if the home directory is not the root directory.
Remember the current directory the first time a CWD / CDUP has to be
issued. Use the document as full URL if the URL started with two /
(quoted or not), otherwise append it to the initial directory.
To generate a diff of this commit:
cvs rdiff -u -r1.1.1.2.4.2 -r1.1.1.2.4.3 \
src/external/bsd/fetch/dist/libfetch/common.c \
src/external/bsd/fetch/dist/libfetch/common.h
cvs rdiff -u -r1.1.1.3.2.2 -r1.1.1.3.2.3 \
src/external/bsd/fetch/dist/libfetch/ftp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: pending-pullups->closed
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Sat, 20 Nov 2010 23:38:35 +0000
State-Changed-Why:
pullups complete.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.