/* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "errno.h" #include "unistd.h" #include "limits.h" #include "utime.h" #include "time.h" #include "user_copy.h" #include "sys/times.h" #include "los_signal.h" #include "los_memory.h" #include "los_strncpy_from_user.h" #include "time_posix.h" #ifdef LOSCFG_FS_VFS int SysUtime(const char *path, const struct utimbuf *ptimes) { int ret; char *spath = NULL; struct utimbuf sptimes; if (path == NULL) { errno = EINVAL; return -EINVAL; } spath = LOS_MemAlloc(m_aucSysMem0, PATH_MAX + 1); if (spath == NULL) { errno = ENOMEM; return -ENOMEM; } ret = LOS_StrncpyFromUser(spath, path, PATH_MAX + 1); if (ret == -EFAULT) { LOS_MemFree(m_aucSysMem0, spath); return ret; } else if (ret > PATH_MAX) { LOS_MemFree(m_aucSysMem0, spath); PRINT_ERR("%s[%d], path exceeds maxlen: %d\n", __FUNCTION__, __LINE__, PATH_MAX); return -ENAMETOOLONG; } spath[ret] = '\0'; if (ptimes && LOS_ArchCopyFromUser(&sptimes, ptimes, sizeof(struct utimbuf))) { LOS_MemFree(m_aucSysMem0, spath); errno = EFAULT; return -EFAULT; } ret = utime(spath, ptimes ? &sptimes : NULL); if (ret < 0) { ret = -get_errno(); } LOS_MemFree(m_aucSysMem0, spath); return ret; } #endif time_t SysTime(time_t *tloc) { int ret; time_t stloc; ret = time(tloc ? &stloc : NULL); if (ret < 0) { return -get_errno(); } if (tloc && LOS_ArchCopyToUser(tloc, &stloc, sizeof(time_t))) { errno = EFAULT; ret = -EFAULT; } return ret; } int SysSetiTimer(int which, const struct itimerval *value, struct itimerval *ovalue) { int ret; struct itimerval svalue; struct itimerval sovalue = { 0 }; if (value == NULL) { errno = EINVAL; return -EINVAL; } if (LOS_ArchCopyFromUser(&svalue, value, sizeof(struct itimerval))) { errno = EFAULT; return -EFAULT; } ret = setitimer(which, &svalue, &sovalue); if (ret < 0) { return -get_errno(); } if (ovalue && LOS_ArchCopyToUser(ovalue, &sovalue, sizeof(struct itimerval))) { errno = EFAULT; return -EFAULT; } return ret; } int SysGetiTimer(int which, struct itimerval *value) { int ret; struct itimerval svalue = { 0 }; if (value == NULL) { errno = EINVAL; return -EINVAL; } ret = getitimer(which, &svalue); if (ret < 0) { return -get_errno(); } if (LOS_ArchCopyToUser(value, &svalue, sizeof(struct itimerval))) { errno = EFAULT; return -EFAULT; } return ret; } int SysTimerCreate(clockid_t clockID, struct ksigevent *evp, timer_t *timerID) { int ret; timer_t stimerID; struct ksigevent ksevp; if (timerID == NULL) { errno = EINVAL; return -EINVAL; } if (evp && LOS_ArchCopyFromUser(&ksevp, evp, sizeof(struct ksigevent))) { errno = EFAULT; return -EFAULT; } ret = OsTimerCreate(clockID, evp ? &ksevp : NULL, &stimerID); if (ret < 0) { return -get_errno(); } if (LOS_ArchCopyToUser(timerID, &stimerID, sizeof(timer_t))) { errno = EFAULT; return -EFAULT; } return ret; } int SysTimerGettime(timer_t timerID, struct itimerspec *value) { int ret; struct itimerspec svalue = { 0 }; if (value == NULL) { errno = EINVAL; return -EINVAL; } ret = timer_gettime(timerID, &svalue); if (ret < 0) { return -get_errno(); } if (LOS_ArchCopyToUser(value, &svalue, sizeof(struct itimerspec))) { errno = EFAULT; return -EFAULT; } return ret; } int SysTimerSettime(timer_t timerID, int flags, const struct itimerspec *value, struct itimerspec *oldValue) { int ret; struct itimerspec svalue; struct itimerspec soldValue = { 0 }; if (value == NULL) { errno = EINVAL; return -EINVAL; } if (LOS_ArchCopyFromUser(&svalue, value, sizeof(struct itimerspec))) { errno = EFAULT; return -EFAULT; } ret = timer_settime(timerID, flags, &svalue, &soldValue); if (ret < 0) { return -get_errno(); } if (oldValue && LOS_ArchCopyToUser(oldValue, &soldValue, sizeof(struct itimerspec))) { errno = EFAULT; return -EFAULT; } return ret; } int SysTimerGetoverrun(timer_t timerID) { int ret; ret = timer_getoverrun(timerID); if (ret < 0) { return -get_errno(); } return ret; } int SysTimerDelete(timer_t timerID) { int ret; ret = timer_delete(timerID); if (ret < 0) { return -get_errno(); } return ret; } int SysClockSettime(clockid_t clockID, const struct timespec *tp) { int ret; struct timespec stp; if (tp == NULL) { errno = EINVAL; return -EINVAL; } if (LOS_ArchCopyFromUser(&stp, tp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } ret = clock_settime(clockID, &stp); if (ret < 0) { return -get_errno(); } return ret; } int SysClockGettime(clockid_t clockID, struct timespec *tp) { int ret; struct timespec stp = { 0 }; if (tp == NULL) { errno = EINVAL; return -EINVAL; } ret = clock_gettime(clockID, &stp); if (ret < 0) { return -get_errno(); } if (LOS_ArchCopyToUser(tp, &stp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } return ret; } int SysClockGetres(clockid_t clockID, struct timespec *tp) { int ret; struct timespec stp = { 0 }; if (tp == NULL) { errno = EINVAL; return -EINVAL; } ret = clock_getres(clockID, &stp); if (ret < 0) { return -get_errno(); } if (LOS_ArchCopyToUser(tp, &stp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } return ret; } int SysClockNanoSleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem) { int ret; struct timespec sreq; struct timespec srem = { 0 }; if (!req || LOS_ArchCopyFromUser(&sreq, req, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } ret = clock_nanosleep(clk, flags, &sreq, rem ? &srem : NULL); if (ret < 0) { return -get_errno(); } if (rem && LOS_ArchCopyToUser(rem, &srem, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } return ret; } int SysNanoSleep(const struct timespec *rqtp, struct timespec *rmtp) { int ret; struct timespec srqtp; struct timespec srmtp = { 0 }; if (!rqtp || LOS_ArchCopyFromUser(&srqtp, rqtp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } if (rmtp && LOS_ArchCopyFromUser(&srmtp, rmtp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } ret = nanosleep(&srqtp, rmtp ? &srmtp : NULL); if (ret < 0) { return -get_errno(); } if (rmtp && LOS_ArchCopyToUser(rmtp, &srmtp, sizeof(struct timespec))) { errno = EFAULT; return -EFAULT; } return ret; } clock_t SysTimes(struct tms *buf) { clock_t ret; struct tms sbuf = { 0 }; if (buf == NULL) { errno = EFAULT; return -EFAULT; } ret = times(&sbuf); if (ret == -1) { return -get_errno(); } if (LOS_ArchCopyToUser(buf, &sbuf, sizeof(struct tms))) { errno = EFAULT; return -EFAULT; } return ret; } int SysClockSettime64(clockid_t clockID, const struct timespec64 *tp) { int ret; struct timespec t; struct timespec64 stp; if (tp == NULL) { errno = EINVAL; return -EINVAL; } if (LOS_ArchCopyFromUser(&stp, tp, sizeof(struct timespec64))) { errno = EFAULT; return -EFAULT; } if (stp.tv_sec > UINT32_MAX) { errno = ENOSYS; return -ENOSYS; } t.tv_sec = stp.tv_sec; t.tv_nsec = stp.tv_nsec; ret = clock_settime(clockID, &t); if (ret < 0) { return -get_errno(); } return ret; } int SysClockGettime64(clockid_t clockID, struct timespec64 *tp) { int ret; struct timespec t; struct timespec64 stp = { 0 }; if (tp == NULL) { errno = EINVAL; return -EINVAL; } ret = clock_gettime(clockID, &t); if (ret < 0) { return -get_errno(); } stp.tv_sec = t.tv_sec; stp.tv_nsec = t.tv_nsec; if (LOS_ArchCopyToUser(tp, &stp, sizeof(struct timespec64))) { errno = EFAULT; return -EFAULT; } return ret; } int SysClockGetres64(clockid_t clockID, struct timespec64 *tp) { int ret; struct timespec t; struct timespec64 stp = { 0 }; if (tp == NULL) { errno = EINVAL; return -EINVAL; } ret = clock_getres(clockID, &t); if (ret < 0) { return -get_errno(); } stp.tv_sec = t.tv_sec; stp.tv_nsec = t.tv_nsec; if (LOS_ArchCopyToUser(tp, &stp, sizeof(struct timespec64))) { errno = EFAULT; return -EFAULT; } return ret; } int SysClockNanoSleep64(clockid_t clk, int flags, const struct timespec64 *req, struct timespec64 *rem) { int ret; struct timespec rq; struct timespec rm = { 0 }; struct timespec64 sreq; struct timespec64 srem = { 0 }; if (!req || LOS_ArchCopyFromUser(&sreq, req, sizeof(struct timespec64))) { errno = EFAULT; return -EFAULT; } if (req != NULL) { rq.tv_sec = (sreq.tv_sec > UINT32_MAX) ? UINT32_MAX : sreq.tv_sec; rq.tv_nsec = sreq.tv_nsec; } ret = clock_nanosleep(clk, flags, &rq, rem ? &rm : NULL); if (ret < 0) { return -get_errno(); } if (rem != NULL) { srem.tv_sec = rm.tv_sec; srem.tv_nsec = rm.tv_nsec; if (LOS_ArchCopyToUser(rem, &srem, sizeof(struct timespec64))) { errno = EFAULT; return -EFAULT; } } return ret; } int SysTimerGettime64(timer_t timerID, struct itimerspec64 *value) { int ret; struct itimerspec val; struct itimerspec64 svalue = { 0 }; if (value == NULL) { errno = EINVAL; return -EINVAL; } ret = timer_gettime(timerID, &val); if (ret < 0) { return -get_errno(); } svalue.it_interval.tv_sec = val.it_interval.tv_sec; svalue.it_interval.tv_nsec = val.it_interval.tv_nsec; svalue.it_value.tv_sec = val.it_value.tv_sec; svalue.it_value.tv_nsec = val.it_value.tv_nsec; if (LOS_ArchCopyToUser(value, &svalue, sizeof(struct itimerspec64))) { errno = EFAULT; return -EFAULT; } return ret; } int SysTimerSettime64(timer_t timerID, int flags, const struct itimerspec64 *value, struct itimerspec64 *oldValue) { int ret; struct itimerspec val; struct itimerspec oldVal; struct itimerspec64 svalue; struct itimerspec64 soldValue; if (value == NULL) { errno = EINVAL; return -EINVAL; } if (LOS_ArchCopyFromUser(&svalue, value, sizeof(struct itimerspec64))) { errno = EFAULT; return -EFAULT; } if (svalue.it_interval.tv_sec > UINT32_MAX || svalue.it_value.tv_sec > UINT32_MAX) { errno = ENOSYS; return -ENOSYS; } val.it_interval.tv_sec = svalue.it_interval.tv_sec; val.it_interval.tv_nsec = svalue.it_interval.tv_nsec; val.it_value.tv_sec = svalue.it_value.tv_sec; val.it_value.tv_nsec = svalue.it_value.tv_nsec; ret = timer_settime(timerID, flags, &val, oldValue ? &oldVal : NULL); if (ret < 0) { return -get_errno(); } if (oldValue != NULL) { (void)memset_s(&soldValue, sizeof(struct itimerspec64), 0, sizeof(struct itimerspec64)); soldValue.it_interval.tv_sec = oldVal.it_interval.tv_sec; soldValue.it_interval.tv_nsec = oldVal.it_interval.tv_nsec; soldValue.it_value.tv_sec = oldVal.it_value.tv_sec; soldValue.it_value.tv_nsec = oldVal.it_value.tv_nsec; if (LOS_ArchCopyToUser(oldValue, &soldValue, sizeof(struct itimerspec64))) { errno = EFAULT; return -EFAULT; } } return ret; }