Thread (9 messages) 9 messages, 4 authors, 2014-03-19

Re: For review: open_by_name_at(2) man page [v2]

From: Michael Kerrisk (man-pages) <hidden>
Date: 2014-03-19 13:11:18
Also in: linux-fsdevel, lkml

Hi Mike,

On 03/19/2014 07:42 AM, Mike Frysinger wrote:
On Tue 18 Mar 2014 13:55:15 Michael Kerrisk wrote:
quoted
The
.I flags
argument is a bit mask constructed by ORing together
zero or more of the following value:
.TP
.B AT_EMPTY_PATH
Allow
.I pathname
to be an empty string.
See above.
(which may have been obtained using the
.BR open (2)
.B O_PATH
flag).
.TP
.B AT_SYMLINK_FOLLOW
By default,
.BR name_to_handle_at ()
does not dereference
.I pathname
if it is a symbolic link.
The flag
.B AT_SYMLINK_FOLLOW
can be specified in
.I flags
to cause
.I pathname
to be dereferenced if it is a symbolic link.
this section is only talking about |flags|, and further this part is only 
talking about AT_SYMLINK_FOLLOW.  so this last sentence sounds super 
redundant.
how about reversing the sentence order so that both are implicit like is done 
in the openat() page and the description of O_NOFOLLOW ?
I'm not sure that I completely understand you here, but I agree that this could 
be better. I've rewritten somewhat.
quoted
.B ENOTDIR
The file descriptor supplied in
.I dirfd
does not refer to a directory,
and it it is not the case that both
"it" is duplicated
Fixed.

quoted
.SS Obtaining a persistent filesystem ID
The mount IDs in
.IR /proc/self/mountinfo
can be reused as filesystems are unmounted and mounted.
Therefore, the mount ID returned by
.BR name_to_handle_at (3)
should be () and not (3)
Fixed.
side note: this seems like an easy error to script for ...
Yep, I've got some scripts that I run manually now and then to 
check for this sort of stuff.
quoted
$ \fBecho 'Kannst du bitte überlegen?' > cecilia.txt\fP
aber, ich spreche kein Deutsch :(

do we have a standard about sticking to english ?  i wonder if people are more 
likely to be confused or to appreciate it ...
Fair enough. I'm too influenced by recent work on the locale pages (and 
family conversations ;-)). I'll switch it to English
quoted
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \\
                        } while (0)
i wonder if err.h makes sense now that this is a man page for completely 
linux-specific syscalls :).  and you use _GNU_SOURCE.
I'm not really convinced about using these functions, but I'll reflect 
on it more.
quoted
int
main(int argc, char *argv[])
{
    struct file_handle *fhp;
    int mount_id, fhsize, s;

    if (argc < 2 || strcmp(argv[1], "\-\-help") == 0) {
argc != 2 ?
Yes, some cruft crept in.
quoted
    /* Allocate file_handle structure */

    fhsize = sizeof(struct file_handle *);
pretty sure this is wrong 
<blush>
as sizeof() here returns the size of a pointer, not 
the size of the struct.  it's why i prefer the form:

	fhsize = sizeof(*fhp);

less typing and harder to screw up by accident.
Yep, changed.
granted, the case below won't crash since the kernel only reads/writes 
sizeof(unsigned int) and i'm not aware of any system where that is larger than 
sizeof(void *), but it's still wrong :).
quoted
    s = name_to_handle_at(AT_FDCWD, argv[1], fhp, &mount_id, 0);
another personal style: create dedicated variables for each arg you unpack out 
of argv[1].  it's generally OK when you only take one arg, but when you get 
more than one, you end up flipping back and forth between the usage trying to 
figure out what index 1 represents instead of focusing on what the code is 
doing.
	const char *pathname = argv[1];
Yup.
quoted
    fhsize = sizeof(struct file_handle) + fhp\->handle_bytes;
fhsize += fhp->handle_bytes ?

it's the same, but i think nicer ;)
Depends on your perspective. It relies on no one changing the code
so that fhsize is modified after the earlier initialization. And
also, with this line, I see exactly what is going on, in one place.
I'll leave as is.
quoted
    /* Write mount ID, file handle size, and file handle to stdout,
       for later reuse by t_open_by_handle_at.c */

    if (write(STDOUT_FILENO, &mount_id, sizeof(int)) != sizeof(int) ||
            write(STDOUT_FILENO, &fhsize, sizeof(int)) != sizeof(int) ||
            write(STDOUT_FILENO, fhp, fhsize) != fhsize) {
seems like a whole lot of code spew for a simple printf() ?  you'd have to 
adjust the other program to use scanf(), but seems like the end result would 
be nicer for users to experiment with ?
Yes. I'd already reflected on exactly that and made a change to using text 
formats.
quoted
static int
open_mount_path_by_id(int mount_id)
{
    char *linep;
    size_t lsize;
    char mount_path[PATH_MAX];
    int fmnt_id, fnd, nread;
could we buy a few more letters for these vars ?  i guess fmnt_id is the 
filesystem mount id, and fnd is "find".
When I was a kid, you had to pay a dollar for each letter...
(I've made a few changes.)
also, getline() returns a ssize_t, not an int.
Fixed.
quoted
    FILE *fp;

    fp  = fopen("/proc/self/mountinfo", "r");
only one space before the =
Yup.
i would encourage using the "e" flag whenever possible in the hopes that 
someone might start using it in their own code base.

	fp = fopen("/proc/self/mountinfo", "re");
I'm of two minds about this. I foresee the day when I get a bug report that
says: "Why did you use 'e' here (or O_CLOEXEC)? It's not needed". So, I'm 
inclined to leave this.
quoted
    for (fnd = 0; !fnd ; ) {
in my experience, seems like a while() loop makes more sense when you're 
implementing a while() loop ...
	fnd = 0;
	while (!fnd) {
Yup. ;-}.
quoted
        linep = NULL;
        nread = getline(&linep, &lsize, fp);
this works, but it's unusual when using getline() as it kind of defeats the 
purpose of using the dyn allocation feature.

	fnd = 0;
	linep = NULL;
	while (!fnd) {
		nread = getline(&linep, &lsize, fp);
		...
	}
	free(linep);

i don't think it complicates the code much more ?
Yes. Fixed.
quoted
        if (nread == \-1)
            break;

	nread = sscanf(linep, "%d %*d %*s %*s %s", &fmnt_id, mount_path);
indent is off here
Fixed.
quoted
    return open(mount_path, O_RDONLY | O_DIRECTORY);
O_CLOEXEC for funsies ?
See above comment.
quoted
int
main(int argc, char *argv[])
{
    struct file_handle *fhp;
    int mount_id, fd, mount_fd, fhsize;
    ssize_t nread;
#define BSIZE 1000
    char buf[BSIZE];
why not sizeof(buf) and avoid the define ?
Done.
quoted
    if (argc > 1 && strcmp(argv[1], "\-\-help") == 0) {
        fprintf(stderr, "Usage: %s [mount\-dir]]\\n",
                argv[0]);
how about also aborting when argc > 2 ?
Yes.
quoted
    if (argc > 1)
        mount_fd = open(argv[1], O_RDONLY | O_DIRECTORY);
O_CLOEXEC ?
See comment above.
quoted
    nread = read(fd, buf, BSIZE);
    if (nread == \-1)
        errExit("read");
    printf("Read %ld bytes\\n", (long) nread);
yikes, that's a bad habit to encourage.  read() returns a ssize_t, so print it 
out using %zd.
Calling it a bad habit seems a bit too strong. It's a habit conditioned by writing 
code that runs on systems that don't have C99. Less important these days, of course.
I've changed it.
quoted
.SH SEE ALSO
.BR blkid (1),
.BR findfs (1),
i don't have a findfs(1).  i do have a findfs(8) ...
Thanks. blkid(8) also, actually.

Thanks for the comments, Mike.

Cheers,

Michael


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help