Hello Quentin, On Sun, Oct 01, 2023 at 02:33:25PM +0100, Quentin Armitage wrote: > truncate(2) returns EINVAL if the file argument is a socket, a FIFO or a character or block > device. The current man page indicates that ftruncate() returns EINVAL for an fd that does > not reference regular file, but for truncate() the only reason given for returning EINVAL is > that the length is invalid. Please keep the commit message within 72 columns. > > The following test program demonstrates the errors returned by truncate(): > ===================================================== > #define _GNU_SOURCE > > #include <unistd.h> > #include <stdio.h> > #include <stdlib.h> > #include <errno.h> > #include <sys/types.h> > #include <fcntl.h> > #include <sys/stat.h> > #include <sys/sysmacros.h> > #include <string.h> > > struct { > const char *fname; > mode_t mode; > unsigned dev_maj; > unsigned dev_min; > } nodes[] = { > { "/tmp/trunc_file", S_IFREG | 0666 }, > { "/tmp/trunc_fifo", S_IFIFO | 0666 }, > { "/tmp/trunc_socket", S_IFSOCK | 0666 }, > { "/tmp/trunc_char_dev", S_IFCHR | 0666, 10, 7}, // Second Amiga mouse, /dev/amigamouse1 > { "/tmp/trunc_blk_dev", S_IFBLK | 0666, 13, 3 }, // Was XT disk /dev/xd3 > { "/tmp/trunc_dir", 0666 }, > }; > > int main(int C, char **V) > { > int n; > int ret; > > for (n = 0; n < sizeof(nodes) / sizeof(nodes[0]); n++) { > /* Create the nodes */ > if (!(nodes[n].mode & S_IFMT)) > ret = mkdir(nodes[n].fname, nodes[n].mode); > else > ret = mknod(nodes[n].fname, nodes[n].mode, > makedev(nodes[n].dev_maj, nodes[n].dev_min)); > > if (ret) { > fprintf(stderr, "mknod(%s) errno %d - %m\n", nodes[n].fname, errno); warn(3) or perror(3)? > continue; > } > > /* Returns EINVAL for IFSOCK, IFIFO, S_IFBLK, S_IFCHR, EISDIR for a directory */ > ret = truncate(nodes[n].fname, 0); > > if (ret) > printf("truncate(\"%s\") failed with errno %s - %m\n", nodes[n].fname, > strerrorname_np(errno)); If there's a failure, we want stderr, don't we? If so, perror(3) or warn(3) would be more appropriate (and simpler). > else > printf("truncate(\"%s\") succeeded\n", nodes[n].fname); > > /* Remove the nodes */ > if (!(nodes[n].mode & S_IFMT)) > ret = rmdir(nodes[n].fname); > else > ret = unlink(nodes[n].fname); > if (ret) > fprintf(stderr, "unlink(%s) errno %d - %m\n", nodes[n].fname, errno); perror(3) would be simpler here; and we already know the string. > } > } > ===================================================== > > Compile the program and run it as user root. > > output should be: > truncate("/tmp/trunc_file") succeeded > truncate("/tmp/trunc_fifo") failed with errno EINVAL - Invalid argument > truncate("/tmp/trunc_socket") failed with errno EINVAL - Invalid argument > truncate("/tmp/trunc_char_dev") failed with errno EINVAL - Invalid argument > truncate("/tmp/trunc_blk_dev") failed with errno EINVAL - Invalid argument > truncate("/tmp/trunc_dir") failed with errno EISDIR - Is a directory > > Signed-off-by: Quentin Armitage <quentin@xxxxxxxxxxxxxxx> > > diff --git a/man2/truncate.2 b/man2/truncate.2 > index 703f598b3..9fc14ce5b 100644 > --- a/man2/truncate.2 > +++ b/man2/truncate.2 > @@ -112,7 +112,9 @@ and > .B EINVAL > The argument > .I length > -is negative or larger than the maximum file size. > +is negative or larger than the maximum file size, or > +the named file is a socket, a FIFO or a block or > +character device. And please use semantic newlines. $ MANWIDTH=72 man man-pages | sed -n '/Use semantic newlines/,/^$/p' Use semantic newlines In the source of a manual page, new sentences should be started on new lines, long sentences should be split into lines at clause breaks (commas, semicolons, colons, and so on), and long clauses should be split at phrase boundaries. This convention, sometimes known as "semantic newlines", makes it easier to see the effect of patches, which often operate at the level of in‐ dividual sentences, clauses, or phrases. Thanks, Alex > .TP > .B EIO > An I/O error occurred updating the inode. > >
Attachment:
signature.asc
Description: PGP signature