Reputation: 13
Why is it when you use this
struct utmp rec;
(although, using any variable declared as type time_t would also demostrate this problem ie declaring "time_t rec;" )
this is ok -
rec.ut_time = time(NULL);
But not this -
time(&rec.ut_time);
The second line of code has the error passing argument 1 of time
from incompatible pointer type [-Wincompatible-pointer-types]
It is a c code file and I am using gcc to compile on Ubuntu.
The man page for time()
states -
time_t time(time_t *tloc);
If
tloc
is non-NULL, the return value is also stored in the memory pointed to by tloc. But then, under Bugs: Thetloc
argument is obsolescent and should always be NULL in new code. Whentloc
is NULL, the call cannot fail.
In a (2003) linux programming text book I am using, they are using the method time(&rec.ut_time);
And the time function with a parameter is what I see in a lot of older github examples.
But do newer versions of compliers have an issue with passing an argument in time()
?
Maybe I am focusing too much on this, and should just use rec.ut_time = time(NULL);
as it works.
Upvotes: 1
Views: 630
Reputation: 13
In case it helps people, I will show here the complete function from the text book (Understanding Unix/Linux Programming. Molay). With the problem code corrected (code lines are commented as "added code" and "problem code").
/* Marks a utmp record as logged out. Does not blank the username or
remote host. Returns -1 on error, 0 on success.
*/
int logout_tty(char *line) {
int fd;
struct utmp rec;
struct timeval tv; // added code. for use within gettimeofday().
int len = sizeof(struct utmp);
int retval = -1; // assume an error
if ((fd = open(UTMP_FILE, O_RDWR)) == -1) {
perror(UTMP_FILE);
return -1;
}
/* note on utmp and time(). Originally tried using time() to set the time to
ut_tv.tv_sec in the while loop below. time() expects a type time_t.
But ut_tv.tv_sec in struct utmp is int32_t . Because of this the utmp man page
recommends the use of gettimeofday() instead of time().
*/
// search and replace
while (read(fd, &rec, len) == len) {
if (strncmp(rec.ut_line, line, sizeof(rec.ut_line)) == 0) {
rec.ut_type = DEAD_PROCESS; // set type
//if (time(&rec.ut_time) != -1) // problem code. set time
if ((gettimeofday(&tv, NULL)) != -1) { // added code. set time
rec.ut_tv.tv_sec = tv.tv_sec; // added code
if (lseek(fd, -len, SEEK_CUR) != -1) { // back up
if (write(fd, &rec, len) == len) { // update
retval = 0; // success
}
}
break;
}
}
}
if (close(fd) == -1) {
retval = -1;
}
return retval;
}
Upvotes: 0
Reputation: 133879
The book is wrong, of course. The Linux utmp(5)
manual states that the struct utmp.ut_tv
is not of type compatible with struct timeval
Note that on biarch platforms, that is, systems which can run both 32-bit and 64-bit applications (x86-64, ppc64, s390x, etc.),
ut_tv
is the same size in 32-bit mode as in 64-bit mode. The same goes forut_session
andut_time
if they are present. This allows data files and shared memory to be shared between 32-bit and 64-bit applications. This is achieved by changing the type ofut_session
toint32_t
, and that ofut_tv
to a struct with twoint32_t
fieldstv_sec
andtv_usec
. Sinceut_tv
may not be the same asstruct timeval
, then instead of the call:gettimeofday((struct timeval *) &ut.ut_tv, NULL);
the following method of setting this field is recommended:
struct utmp ut; struct timeval tv; gettimeofday(&tv, NULL); ut.ut_tv.tv_sec = tv.tv_sec; ut.ut_tv.tv_usec = tv.tv_usec;
You get the warning because ut_time
is defined as a macro that expands to ut_tv.tv_sec
; and the tv_sec
member of rec.ut_tv
is int32_t
even on systems that have 64-bit time_t
and whose struct timeval
would contain time_t tv_sec
.
The proper way of setting the time is with gettimeofday
as above because it would set the microsecond field too.
Upvotes: 2