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 a 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> #include <err.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) { warn("mknod(%s) errno %d", 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) warn("truncate(\"%s\") failed with errno %s", 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) warn("unlink(%s) errno %d", nodes[n].fname, errno); } } ===================================================== Compile the program and run it as user root. output (if program name is trunc) should be: truncate("/tmp/trunc_file") succeeded trunc: truncate("/tmp/trunc_fifo") failed with errno EINVAL: Invalid argument trunc: truncate("/tmp/trunc_socket") failed with errno EINVAL: Invalid argument trunc: truncate("/tmp/trunc_char_dev") failed with errno EINVAL: Invalid argument trunc: truncate("/tmp/trunc_blk_dev") failed with errno EINVAL: Invalid argument trunc: 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..44750b9e2 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.