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. 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); 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)); 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); } } ===================================================== 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. .TP .B EIO An I/O error occurred updating the inode.