Re: [patch] truncate.2: EINVAL is returned for non regular files except directories

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux