#!/usr/sbin/dtrace -s /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * This D script shows processes that create timestamps outside the * 32-Bit time_t range (1901-2038). * * Feedback please to constantin.gonzalez@sun.com */ /* * Version: 1.2 * * History: * V1.2: 2008-07-04: * - The filenames array is now global, but 2-dimensional with the pid * as the 2nd dimension to catch fds that are allocated in one thread, * then used in another thread of the same process. * - Use constants for LONG_MIN and LONG_MAX for better readability. * - Split up the actions for utimes and futimesat into individual * probes and avoid if-then constructs based on probefunc for better * readability. * - Use proper casting and data structures in the predicates to improve * readability. * - Fix a bug that incorrectly referenced the second array element in * the predicate (16 vs 8 bytes offsetr). * V1.1: 2008-07-03: * - Better robustness against multiple threads firing at the same time. * - Cover futimesat in addition to utimes but needs to keep a list * of filenames and fds to report filenames. * - Check both arguments (atime and mtime) for erroneous values. * V1.0: Initial release. */ /* Space to store some values in.*/ self struct timeval *atime; self struct timeval *mtime; string filename; string filenames[int, pid_t]; /* Constants */ inline int64_t LONG_MIN = -2147483648; inline int64_t LONG_MAX = 2147483647; syscall::open:entry, syscall::open64:entry { filename = stringof(copyinstr(arg0)); } syscall::open:return, syscall::open64:return /arg0 >= 0/ { filenames[arg0, pid] = filename; } /* Free up memory when files are closed */ syscall::close:entry { filenames[arg0, pid] = 0; } fbt::utimes:entry /* * utimes accepts a filename in arg0 and an array of two struct timeval * elements in arg1. * Fetch the pointers using copyin, cast arg1 into struct timeval array and * compare the two elements against 32-Bit LONG_MIN and LONG_MAX. */ / ((struct timeval *) copyin(arg1, sizeof(void *)))[0].tv_sec <= LONG_MIN || ((struct timeval *) copyin(arg1, sizeof(void *)))[0].tv_sec >= LONG_MAX || ((struct timeval *) copyin(arg1, sizeof(void *)))[1].tv_sec <= LONG_MIN || ((struct timeval *) copyin(arg1, sizeof(void *)))[1].tv_sec >= LONG_MAX / { /* Read out and print current timeval values. */ /* Read out the filename. */ /* Use stringof even if copyinstr is supposed to yield a string, because it could (although shouldn't) be NULL */ self->file= stringof(copyinstr(arg0)); /* Fetch time structures */ self->atime = copyin(arg1, sizeof(struct timeval)); self->mtime = copyin(arg1 + sizeof(struct timeval), sizeof(struct timeval)); /* Print out what we have. */ printf( "\nUID: %d, PID: %d, program: %s, file: %s\n atime: %Y, mtime: %Y\n", uid, pid, execname, self->file, self->atime->tv_sec*1000000000, self->mtime->tv_sec*1000000000 ); } fbt::futimesat:entry /* * futimesat accepts a file descriptor in arg0, a filename in arg1 and an * array of struct timeval in arg2. * We do basically the same as above, only that we need slightly more work * to get to the filename. */ / ((struct timeval *) copyin(arg2, sizeof(void *)))[0].tv_sec <= LONG_MIN || ((struct timeval *) copyin(arg2, sizeof(void *)))[0].tv_sec >= LONG_MAX || ((struct timeval *) copyin(arg2, sizeof(void *)))[1].tv_sec <= LONG_MIN || ((struct timeval *) copyin(arg2, sizeof(void *)))[1].tv_sec >= LONG_MAX / { /* Read out and print current timeval values. */ /* The file descriptor. */ self->fd = arg0; /* A pointer to the filename string. */ self->fileptr = arg1; /* Figure out our filename based on whether a string is supplied or we have to look up an fd in our filename table. */ self->file = self->fileptr?copyinstr(self->fileptr):filenames[self->fd, pid]; /* Fetch atime and mtime structures */ self->atime = copyin(arg2, sizeof(struct timeval)); self->mtime = copyin(arg2 + sizeof(struct timeval), sizeof(struct timeval)); /* Print out what we have. */ printf( "\nUID: %d, PID: %d, program: %s, file: %s\n atime: %Y, mtime: %Y\n", uid, pid, execname, self->file, self->atime->tv_sec*1000000000, self->mtime->tv_sec*1000000000 ); }