xref: /minix3/minix/kernel/system/do_settime.c (revision d91f738bd8d93aa6befa2a8d07581040607a512a)
1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc  *   m_type:	SYS_SETTIME
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The parameters for this kernel call are:
5433d6423SLionel Sambuc  *   m_lsys_krn_sys_settime.now
6433d6423SLionel Sambuc  *   m_lsys_krn_sys_settime.clock_id
7433d6423SLionel Sambuc  *   m_lsys_krn_sys_settime.sec
8433d6423SLionel Sambuc  *   m_lsys_krn_sys_settime.nsec
9433d6423SLionel Sambuc  */
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc #include "kernel/system.h"
12433d6423SLionel Sambuc #include <minix/endpoint.h>
13433d6423SLionel Sambuc #include <time.h>
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc /*===========================================================================*
16433d6423SLionel Sambuc  *				do_settime				     *
17433d6423SLionel Sambuc  *===========================================================================*/
do_settime(struct proc * caller,message * m_ptr)18433d6423SLionel Sambuc int do_settime(struct proc * caller, message * m_ptr)
19433d6423SLionel Sambuc {
20433d6423SLionel Sambuc   clock_t newclock;
21433d6423SLionel Sambuc   int32_t ticks;
22*d91f738bSDavid van Moolenbroek   time_t boottime, timediff, timediff_ticks;
23433d6423SLionel Sambuc 
24*d91f738bSDavid van Moolenbroek   /* only realtime can change */
25*d91f738bSDavid van Moolenbroek   if (m_ptr->m_lsys_krn_sys_settime.clock_id != CLOCK_REALTIME)
26433d6423SLionel Sambuc 	return EINVAL;
27433d6423SLionel Sambuc 
28*d91f738bSDavid van Moolenbroek   /* user just wants to adjtime() */
29*d91f738bSDavid van Moolenbroek   if (m_ptr->m_lsys_krn_sys_settime.now == 0) {
30433d6423SLionel Sambuc 	/* convert delta value from seconds and nseconds to ticks */
31433d6423SLionel Sambuc 	ticks = (m_ptr->m_lsys_krn_sys_settime.sec * system_hz) +
32433d6423SLionel Sambuc 		(m_ptr->m_lsys_krn_sys_settime.nsec/(1000000000/system_hz));
33433d6423SLionel Sambuc 	set_adjtime_delta(ticks);
34433d6423SLionel Sambuc 	return(OK);
35433d6423SLionel Sambuc   } /* else user wants to set the time */
36433d6423SLionel Sambuc 
37*d91f738bSDavid van Moolenbroek   boottime = get_boottime();
38*d91f738bSDavid van Moolenbroek 
39433d6423SLionel Sambuc   timediff = m_ptr->m_lsys_krn_sys_settime.sec - boottime;
40433d6423SLionel Sambuc   timediff_ticks = timediff * system_hz;
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc   /* prevent a negative value for realtime */
43433d6423SLionel Sambuc   if (m_ptr->m_lsys_krn_sys_settime.sec <= boottime ||
44433d6423SLionel Sambuc       timediff_ticks < LONG_MIN/2 || timediff_ticks > LONG_MAX/2) {
45433d6423SLionel Sambuc   	/* boottime was likely wrong, try to correct it. */
46*d91f738bSDavid van Moolenbroek 	set_boottime(m_ptr->m_lsys_krn_sys_settime.sec);
47433d6423SLionel Sambuc 	set_realtime(1);
48433d6423SLionel Sambuc 	return(OK);
49433d6423SLionel Sambuc   }
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc   /* calculate the new value of realtime in ticks */
52433d6423SLionel Sambuc   newclock = timediff_ticks +
53433d6423SLionel Sambuc       (m_ptr->m_lsys_krn_sys_settime.nsec/(1000000000/system_hz));
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc   set_realtime(newclock);
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc   return(OK);
58433d6423SLionel Sambuc }
59