/**************************************************************************** * fs/procfs/fs_procfsuptime.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) #ifndef CONFIG_FS_PROCFS_EXCLUDE_UPTIME /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Determines the size of an intermediate buffer that must be large enough * to handle the longest line generated by this logic. */ #define UPTIME_LINELEN 16 /**************************************************************************** * Private Types ****************************************************************************/ /* This structure describes one open "file" */ struct uptime_file_s { struct procfs_file_s base; /* Base open file structure */ unsigned int linesize; /* Number of valid characters in line[] */ char line[UPTIME_LINELEN]; /* Pre-allocated buffer for formatted lines */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /* File system methods */ static int uptime_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode); static int uptime_close(FAR struct file *filep); static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static int uptime_dup(FAR const struct file *oldp, FAR struct file *newp); static int uptime_stat(FAR const char *relpath, FAR struct stat *buf); /**************************************************************************** * Public Data ****************************************************************************/ /* See fs_mount.c -- this structure is explicitly externed there. * We use the old-fashioned kind of initializers so that this will compile * with any compiler. */ const struct procfs_operations uptime_operations = { uptime_open, /* open */ uptime_close, /* close */ uptime_read, /* read */ NULL, /* write */ uptime_dup, /* dup */ NULL, /* opendir */ NULL, /* closedir */ NULL, /* readdir */ NULL, /* rewinddir */ uptime_stat /* stat */ }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: uptime_open ****************************************************************************/ static int uptime_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct uptime_file_s *attr; finfo("Open '%s'\n", relpath); /* PROCFS is read-only. Any attempt to open with any kind of write * access is not permitted. * * REVISIT: Write-able proc files could be quite useful. */ if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) { ferr("ERROR: Only O_RDONLY supported\n"); return -EACCES; } /* "uptime" is the only acceptable value for the relpath */ if (strcmp(relpath, "uptime") != 0) { ferr("ERROR: relpath is '%s'\n", relpath); return -ENOENT; } /* Allocate a container to hold the file attributes */ attr = kmm_zalloc(sizeof(struct uptime_file_s)); if (!attr) { ferr("ERROR: Failed to allocate file attributes\n"); return -ENOMEM; } /* Save the attributes as the open-specific state in filep->f_priv */ filep->f_priv = (FAR void *)attr; return OK; } /**************************************************************************** * Name: uptime_close ****************************************************************************/ static int uptime_close(FAR struct file *filep) { FAR struct uptime_file_s *attr; /* Recover our private data from the struct file instance */ attr = (FAR struct uptime_file_s *)filep->f_priv; DEBUGASSERT(attr); /* Release the file attributes structure */ kmm_free(attr); filep->f_priv = NULL; return OK; } /**************************************************************************** * Name: uptime_read ****************************************************************************/ static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { FAR struct uptime_file_s *attr; size_t linesize; off_t offset; ssize_t ret; clock_t ticktime; #if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT) double now; #else # if defined(CONFIG_SYSTEM_TIME64) uint64_t sec; # else uint32_t sec; # endif unsigned int remainder; unsigned int csec; #endif finfo("buffer=%p buflen=%d\n", buffer, (int)buflen); /* Recover our private data from the struct file instance */ attr = (FAR struct uptime_file_s *)filep->f_priv; DEBUGASSERT(attr); /* If f_pos is zero, then sample the system time. Otherwise, use * the cached system time from the previous read(). It is necessary * save the cached value in case, for example, the user is reading * the time one byte at a time. In that case, the time must remain * stable throughout the reads. */ if (filep->f_pos == 0) { /* System time */ ticktime = clock_systime_ticks() - INITIAL_SYSTEM_TIMER_TICKS; #if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT) /* Convert the up time to a seconds + hundredths of seconds string */ now = (double)ticktime / (double)CLOCKS_PER_SEC; linesize = procfs_snprintf(attr->line, UPTIME_LINELEN, "%10.2f\n", now); #else /* Convert the system up time to seconds + hundredths of seconds */ sec = ticktime / CLOCKS_PER_SEC; remainder = (unsigned int)(ticktime % CLOCKS_PER_SEC); csec = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC; /* Make sure that rounding did not force the hundredths of * a second above 99 */ if (csec > 99) { sec++; csec -= 100; } /* Convert the seconds + hundredths of seconds to a string */ #ifdef CONFIG_SYSTEM_TIME64 linesize = procfs_snprintf(attr->line, UPTIME_LINELEN, "%7" PRIu64 ".%02u\n", sec, csec); #else linesize = procfs_snprintf(attr->line, UPTIME_LINELEN, "%7lu.%02u\n", (unsigned long)sec, csec); #endif #endif /* Save the linesize in case we are re-entered with f_pos > 0 */ attr->linesize = linesize; } /* Transfer the system up time to user receive buffer */ offset = filep->f_pos; ret = procfs_memcpy(attr->line, attr->linesize, buffer, buflen, &offset); /* Update the file offset */ if (ret > 0) { filep->f_pos += ret; } return ret; } /**************************************************************************** * Name: uptime_dup * * Description: * Duplicate open file data in the new file structure. * ****************************************************************************/ static int uptime_dup(FAR const struct file *oldp, FAR struct file *newp) { FAR struct uptime_file_s *oldattr; FAR struct uptime_file_s *newattr; finfo("Dup %p->%p\n", oldp, newp); /* Recover our private data from the old struct file instance */ oldattr = (FAR struct uptime_file_s *)oldp->f_priv; DEBUGASSERT(oldattr); /* Allocate a new container to hold the task and attribute selection */ newattr = kmm_malloc(sizeof(struct uptime_file_s)); if (!newattr) { ferr("ERROR: Failed to allocate file attributes\n"); return -ENOMEM; } /* The copy the file attributes from the old attributes to the new */ memcpy(newattr, oldattr, sizeof(struct uptime_file_s)); /* Save the new attributes in the new file structure */ newp->f_priv = (FAR void *)newattr; return OK; } /**************************************************************************** * Name: uptime_stat * * Description: Return information about a file or directory * ****************************************************************************/ static int uptime_stat(FAR const char *relpath, FAR struct stat *buf) { /* "uptime" is the only acceptable value for the relpath */ if (strcmp(relpath, "uptime") != 0) { ferr("ERROR: relpath is '%s'\n", relpath); return -ENOENT; } /* "uptime" is the name for a read-only file */ memset(buf, 0, sizeof(struct stat)); buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; return OK; } /**************************************************************************** * Public Functions ****************************************************************************/ #endif /* CONFIG_FS_PROCFS_EXCLUDE_PROCESS */ #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */