1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <errno.h> 30 #include <time.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <sys/times.h> 34 #include <sys/lx_syscall.h> 35 #include <sys/lx_misc.h> 36 37 /* 38 * time() - This cannot be passthrough because on Linux a bad buffer will 39 * set errno to EFAULT, and on Solaris the failure mode is documented 40 * as "undefined." 41 * 42 * (At present, Solaris' time(2) will segmentation fault, as the call 43 * is simply a libc wrapper atop the time() syscall that will 44 * dereference the passed pointer if it is non-zero.) 45 */ 46 int 47 lx_time(uintptr_t p1) 48 { 49 time_t ret = time((time_t *)0); 50 51 if ((ret == (time_t)-1) || 52 ((p1 != 0) && (uucopy(&ret, (time_t *)p1, sizeof (ret)) != 0))) 53 return (-errno); 54 55 return (ret); 56 } 57 58 /* 59 * times() - The Linux implementation avoids writing to NULL, while Solaris 60 * returns EFAULT. 61 */ 62 int 63 lx_times(uintptr_t p1) 64 { 65 clock_t ret; 66 struct tms buf, *tp = (struct tms *)p1; 67 68 ret = times(&buf); 69 70 if ((ret == -1) || 71 ((tp != NULL) && uucopy((void *)&buf, tp, sizeof (buf)) != 0)) 72 return (-errno); 73 74 return ((ret == -1) ? -errno : ret); 75 } 76 77 /* 78 * setitimer() - the Linux implementation can handle tv_usec values greater 79 * than 1,000,000 where Solaris would return EINVAL. 80 * 81 * There's still an issue here where Linux can handle a 82 * tv_sec value greater than 100,000,000 but Solaris cannot, 83 * but that would also mean setting an interval timer to fire 84 * over _three years_ in the future so it's unlikely anything 85 * other than Linux test suites will trip over it. 86 */ 87 int 88 lx_setitimer(uintptr_t p1, uintptr_t p2, uintptr_t p3) 89 { 90 struct itimerval itv; 91 struct itimerval *itp = (struct itimerval *)p2; 92 93 if (itp != NULL) { 94 if (uucopy(itp, &itv, sizeof (itv)) != 0) 95 return (-errno); 96 97 /* 98 * Adjust any tv_usec fields >= 1,000,000 by adding any whole 99 * seconds so indicated to tv_sec and leaving tv_usec as the 100 * remainder. 101 */ 102 if (itv.it_interval.tv_usec >= MICROSEC) { 103 itv.it_interval.tv_sec += 104 itv.it_interval.tv_usec / MICROSEC; 105 106 itv.it_interval.tv_usec %= MICROSEC; 107 } 108 if (itv.it_value.tv_usec >= MICROSEC) { 109 itv.it_value.tv_sec += 110 itv.it_value.tv_usec / MICROSEC; 111 112 itv.it_value.tv_usec %= MICROSEC; 113 } 114 115 itp = &itv; 116 } 117 118 return ((setitimer((int)p1, itp, (struct itimerval *)p3) != 0) ? 119 -errno : 0); 120 } 121 122 /* 123 * NOTE: The Linux man pages state this structure is obsolete and is 124 * unsupported, so it is declared here for sizing purposes only. 125 */ 126 struct lx_timezone { 127 int tz_minuteswest; /* minutes W of Greenwich */ 128 int tz_dsttime; /* type of dst correction */ 129 }; 130 131 /* 132 * lx_gettimeofday() and lx_settimeofday() are implemented here rather than 133 * as pass-through calls to Solaris' libc due to the need to return EFAULT 134 * for a bad buffer rather than die with a segmentation fault. 135 */ 136 int 137 lx_gettimeofday(uintptr_t p1, uintptr_t p2) 138 { 139 struct timeval tv; 140 struct lx_timezone tz; 141 142 bzero(&tz, sizeof (tz)); 143 (void) gettimeofday(&tv, NULL); 144 145 if ((p1 != NULL) && 146 (uucopy(&tv, (struct timeval *)p1, sizeof (tv)) < 0)) 147 return (-errno); 148 149 /* 150 * The Linux man page states use of the second parameter is obsolete, 151 * but gettimeofday(2) should still return EFAULT if it is set 152 * to a bad non-NULL pointer (sigh...) 153 */ 154 if ((p2 != NULL) && 155 (uucopy(&tz, (struct lx_timezone *)p2, sizeof (tz)) < 0)) 156 return (-errno); 157 158 return (0); 159 } 160 161 int 162 lx_settimeofday(uintptr_t p1, uintptr_t p2) 163 { 164 struct timeval tv; 165 struct lx_timezone tz; 166 167 if ((p1 != NULL) && 168 (uucopy((struct timeval *)p1, &tv, sizeof (tv)) < 0)) 169 return (-errno); 170 171 /* 172 * The Linux man page states use of the second parameter is obsolete, 173 * but settimeofday(2) should still return EFAULT if it is set 174 * to a bad non-NULL pointer (sigh...) 175 */ 176 if ((p2 != NULL) && 177 (uucopy((struct lx_timezone *)p2, &tz, sizeof (tz)) < 0)) 178 return (-errno); 179 180 if ((p1 != NULL) && (settimeofday(&tv, NULL) < 0)) 181 return (-errno); 182 183 return (0); 184 }