[PATCH] implementations of the 13 openat syscalls

Bernhard Kaindl bk at suse.de
Tue Mar 28 03:09:01 UTC 2006


Hi,
   the attached patch implements strace'ing for the 13 *at syscalls which
have recently been added to the Linux kernel (2.6.15+) and to glibc-2.4
to the current strace CVS:

In the order in which they got syscall numbers on x86_64 and mips,
they are:

openat(int dfd, const char *filename, int flags, int mode);
mkdirat(int dfd, const char * pathname, int mode);
mknodat(int dfd, const char * filename, int mode, unsigned dev);
fchownat(int dfd, const char *filename, uid_t user, gid_t group, int flag);
futimesat(int dfd, char *filename, struct timeval *utimes);
fstatat(int dfd, char *filename, struct stat *statbuf, int flag);
unlinkat(int dfd, const char * pathname, int flag);
renameat(int olddfd, const char * oldname, int newdfd, const char * newname);
linkat(int olddfd, const char *oldname, int newdfd, const char *newname, int flags);
symlinkat(const char * oldname, int newdfd, const char * newname);
readlinkat(int dfd, const char *path, char __user *buf, int bufsiz);
fchmodat(int dfd, const char * filename, mode_t mode);
faccessat(int dfd, const char *filename, int mode);

I tested the implementation on x86_64 with the testcases which are
provided in the glibc-2.4 io directory and using the 'pwd' command
of the current coreutils package. Looking at the output, all is
well there and I also execised a code branch which is was covered
by the glibc testcases by creating a test case which uses mknodat
to create a character device, so AFAICT, it's complete. Only tested
on x86_64 so far.

Depending on the archtecture, fstatat may be implemented as

newfstatat(int dfd, char *filename, struct stat *statbuf, int flag);
or
fstatat64(int dfd, char *filename, struct stat64 *statbuf, int flag);

You can find information about these calls at:
http://kerneltrap.org/node/6088
http://lwn.net/Articles/164887

I tested only the use of newfstatat for fstatat on x86_64.

Regarding the syscallents, I have these entries on x86_64:

+       { 4,    0,      sys_openat,             "openat"        }, /* 257 */
+       { 3,    0,      sys_mkdirat,            "mkdirat"       }, /* 258 */
+       { 4,    0,      sys_mknodat,            "mknodat"       }, /* 259 */
+       { 5,    0,      sys_fchownat,           "fchownat"      }, /* 260 */
+       { 3,    0,      sys_futimesat,          "futimesat"     }, /* 261 */
+       { 4,    0,      sys_fstatat,            "fstatat"       }, /* 262 */
+       { 3,    0,      sys_unlinkat,           "unlinkat"      }, /* 263 */
+       { 4,    0,      sys_renameat,           "renameat"      }, /* 264 */
+       { 5,    0,      sys_linkat,             "linkat"        }, /* 265 */
+       { 3,    0,      sys_symlinkat,          "symlinkat"     }, /* 266 */
+       { 4,    0,      sys_readlinkat,         "readlinkat"    }, /* 267 */
+       { 3,    0,      sys_fchmodat,           "fchmodat"      }, /* 268 */
+       { 3,    0,      sys_faccessat,          "faccessat"     }, /* 269 */

I left the second column in the table at 0 for all calls for now,
but I see that the version without "at" have flage like TF and/or
TD set - I did'd check jet which flags should be set for which of
these calls.

If someone can point me to the place where to look or an explanation,
that could be helpful, I'd add the syscalls for linux-i386 then too.
--
Bernhard Kaindl
-------------- next part --------------
--- strace/file.c
+++ strace/file.c
@@ -324,6 +324,33 @@ struct tcb *tcp;
 	return 0;
 }
 
+static inline void printdfd(dfd)
+int dfd;
+{
+	if (dfd == AT_FDCWD)
+		tprintf("AT_FDCWD, ");
+	else
+		tprintf("%d, ", dfd);
+}
+
+int
+sys_openat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		/* flags */
+		printflags(openmodes, tcp->u_arg[2] + 1, "O_???");
+		if (tcp->u_arg[2] & O_CREAT) {
+			/* mode */
+			tprintf(", %#lo", tcp->u_arg[3]);
+		}
+	}
+	return 0;
+}
+
 #ifdef LINUXSPARC
 static const struct xlat openmodessol[] = {
 	{ 0,		"O_RDWR"	},
@@ -400,6 +427,19 @@ struct tcb *tcp;
 }
 
 int
+sys_faccessat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		printflags(access_flags, tcp->u_arg[2], "?_OK");
+	}
+	return 0;
+}
+
+int
 sys_umask(tcp)
 struct tcb *tcp;
 {
@@ -1128,6 +1168,27 @@ struct tcb *tcp;
 }
 #endif
 
+static const struct xlat fstatatflags[] = {
+	{ AT_SYMLINK_NOFOLLOW,	"AT_SYMLINK_NOFOLLOW"	},
+	{ 0,			NULL			},
+};
+
+int
+sys_fstatat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+	} else {
+		printstat(tcp, tcp->u_arg[2]);
+		tprintf(", ");
+		printflags(fstatatflags, tcp->u_arg[3], "AT_???");
+	}
+	return 0;
+}
+
 int
 sys_fstat64(tcp)
 struct tcb *tcp;
@@ -1696,6 +1757,18 @@ struct tcb *tcp;
 }
 
 int
+sys_mkdirat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", %#lo", tcp->u_arg[2]);
+	}
+	return 0;
+}
+
+int
 sys_rmdir(tcp)
 struct tcb *tcp;
 {
@@ -1757,6 +1830,70 @@ struct tcb *tcp;
 	return 0;
 }
 
+static const struct xlat unlinkatflags[] = {
+	{ AT_REMOVEDIR,	"AT_REMOVEDIR"	},
+	{ 0,		NULL		},
+};
+
+int
+sys_linkat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		printdfd(tcp->u_arg[2]);
+		printpath(tcp, tcp->u_arg[3]);
+		tprintf(", %ld", tcp->u_arg[4]);
+	}
+	return 0;
+}
+
+int
+sys_unlinkat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		printflags(unlinkatflags, tcp->u_arg[2], "AT_???");
+	}
+	return 0;
+}
+
+int
+sys_symlinkat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printpath(tcp, tcp->u_arg[0]);
+		tprintf(", ");
+		printdfd(tcp->u_arg[1]);
+		printpath(tcp, tcp->u_arg[2]);
+	}
+	return 0;
+}
+
+int
+sys_readlinkat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+	} else {
+		if (syserror(tcp))
+			tprintf("%#lx", tcp->u_arg[2]);
+		else
+			printpathn(tcp, tcp->u_arg[2], tcp->u_rval);
+		tprintf(", %lu", tcp->u_arg[3]);
+	}
+	return 0;
+}
+
 int
 sys_symlink(tcp)
 struct tcb *tcp;
@@ -1799,6 +1936,20 @@ struct tcb *tcp;
 }
 
 int
+sys_renameat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		printdfd(tcp->u_arg[2]);
+		printpath(tcp, tcp->u_arg[3]);
+	}
+	return 0;
+}
+
+int
 sys_chown(tcp)
 struct tcb *tcp;
 {
@@ -1823,6 +1974,30 @@ struct tcb *tcp;
 }
 
 int
+sys_fchownat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		printuid(", ", tcp->u_arg[2]);
+		printuid(", ", tcp->u_arg[3]);
+	}
+	return 0;
+}
+
+int
+sys_fchmodat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		tprintf("%ld, %#lo", tcp->u_arg[1], tcp->u_arg[2]);
+	}
+	return 0;
+}
+
+int
 sys_chmod(tcp)
 struct tcb *tcp;
 {
@@ -1870,6 +2045,19 @@ struct tcb *tcp;
 }
 
 int
+sys_futimesat(tcp)
+struct tcb *tcp;
+{
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", ");
+		printtv(tcp, tcp->u_arg[2]);
+	}
+	return 0;
+}
+
+int
 sys_utime(tcp)
 struct tcb *tcp;
 {
@@ -1923,6 +2111,36 @@ struct tcb *tcp;
 }
 
 int
+sys_mknodat(tcp)
+struct tcb *tcp;
+{
+	int mode = tcp->u_arg[2];
+
+	if (entering(tcp)) {
+		printdfd(tcp->u_arg[0]);
+		printpath(tcp, tcp->u_arg[1]);
+		tprintf(", %s", sprintmode(mode));
+		switch (mode & S_IFMT) {
+		case S_IFCHR: case S_IFBLK:
+#ifdef LINUXSPARC
+			if _personality == 1)
+			tprintf(", makedev(%lu, %lu)",
+				(unsigned long) ((tcp->u_arg[3] >> 18) & 0x3fff),
+				(unsigned long) (tcp->u_arg[3] & 0x3ffff));
+			else
+#endif
+			tprintf(", makedev(%lu, %lu)",
+				(unsigned long) major(tcp->u_arg[3]),
+				(unsigned long) minor(tcp->u_arg[3]));
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+int
 sys_mkfifo(tcp)
 struct tcb *tcp;
 {
--- strace/linux/syscall.h
+++ strace/linux/syscall.h
@@ -115,6 +115,12 @@ int sys_query_module();
 int sys_poll();
 int sys_mincore();
 
+/* the 13 openat syscalls */
+int sys_openat(), sys_mkdirat(), sys_mknodat(), sys_fchownat();
+int sys_futimesat(), sys_fstatat(), sys_unlinkat(), sys_renameat();
+int sys_linkat(), sys_symlinkat(), sys_readlinkat();
+int sys_fchmodat(), sys_faccessat();
+
 /* architecture-specific calls */
 #ifdef ALPHA
 int sys_osf_select();
--- strace/linux/x86_64/syscallent.h
+++ strace/linux/x86_64/syscallent.h
@@ -252,3 +252,19 @@
 	{ 5,	0,	printargs,		"SYS_251"	}, /* 251 */
 	{ 5,	0,	printargs,		"SYS_252"	}, /* 252 */
 	{ 5,	0,	printargs,		"SYS_253"	}, /* 253 */
+	{ 5,	0,	printargs,		"SYS_254"	}, /* 254 */
+	{ 5,	0,	printargs,		"SYS_255"	}, /* 255 */
+	{ 5,	0,	printargs,		"SYS_256"	}, /* 256 */
+	{ 4,	0,	sys_openat,		"openat"	}, /* 257 */
+	{ 3,	0,	sys_mkdirat,		"mkdirat"	}, /* 258 */
+	{ 4,	0,	sys_mknodat,		"mknodat"	}, /* 259 */
+	{ 5,	0,	sys_fchownat,		"fchownat"	}, /* 260 */
+	{ 3,	0,	sys_futimesat,		"futimesat"	}, /* 261 */
+	{ 4,	0,	sys_fstatat,		"fstatat"	}, /* 262 */
+	{ 3,	0,	sys_unlinkat,		"unlinkat"	}, /* 263 */
+	{ 4,	0,	sys_renameat,		"renameat"	}, /* 264 */
+	{ 5,	0,	sys_linkat,		"linkat"	}, /* 265 */
+	{ 3,	0,	sys_symlinkat,		"symlinkat"	}, /* 266 */
+	{ 4,	0,	sys_readlinkat,		"readlinkat"	}, /* 267 */
+	{ 3,	0,	sys_fchmodat,		"fchmodat"	}, /* 268 */
+	{ 3,	0,	sys_faccessat,		"faccessat"	}, /* 269 */


More information about the Strace-devel mailing list