public inbox for ecos-patches@sourceware.org
 help / color / mirror / Atom feed
From: Andrew Lunn <andrew@lunn.ch>
To: eCos Patches <ecos-patches@ecos.sourceware.org>
Subject: disk usage cyg_fs_getinfo()
Date: Fri, 04 Aug 2006 09:30:00 -0000	[thread overview]
Message-ID: <20060804093005.GC17682@lunn.ch> (raw)

[-- Attachment #1: Type: text/plain, Size: 874 bytes --]

Hi Folks

Attached are four patches which extend the cyg_fs_getinfo call to
retrieve information about the current filesystem disk usage. Using
the key FS_INFO_BLOCK_USAGE you can get the current total number of
blocks in the filesystem, the number of free blocks and the size of a
block. 

With fatfs this is straight forward since there are blocks of fixed
size. With romfs and ramfs the blocks are 1 byte in size. romfs never
has any free blocks, so all you can find out is how big the disk
is. ramfs can be dynamically sized on the heap. In this case the call
is not implemented. When a fixed pool is used the call is implemented.

jffs2 works in terms of flash blocks. 

I have committed romfs, ramfs and fatfs. 

I know Gary is working in updating the jffs2 port to the latest mtd
release in git, so i've not committed this yet. Gary, should i commit?

        Andrew

[-- Attachment #2: fatfs.diff --]
[-- Type: text/plain, Size: 3924 bytes --]

Index: fs/fat/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/ChangeLog,v
retrieving revision 1.12
diff -u -r1.12 ChangeLog
--- fs/fat/current/ChangeLog	3 Aug 2005 20:40:48 -0000	1.12
+++ fs/fat/current/ChangeLog	4 Aug 2006 09:15:54 -0000
@@ -1,3 +1,11 @@
+2006-08-04  Paul Fine  <pfine@dtccom.com>
+            Andrew Lunn <andrew.lunn@ascom.ch>
+	
+	* src/fats.c: Added functionality to the fatfs_getinfo() function
+	to return disk usage information about the filesystem, making this
+	information accessible through the cyg_fs_getinfo() interface.
+	* tests/fatfs1.c: Added code to test the disk usage.
+	
 2005-07-30  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/fatfs_supp.c: Correct types to remove compiler warnings.
Index: fs/fat/current/src/fatfs.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/src/fatfs.c,v
retrieving revision 1.4
diff -u -r1.4 fatfs.c
--- fs/fat/current/src/fatfs.c	11 Nov 2004 19:33:30 -0000	1.4
+++ fs/fat/current/src/fatfs.c	4 Aug 2006 09:15:54 -0000
@@ -1109,6 +1109,22 @@
             err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
             break;
 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+        case FS_INFO_BLOCK_USAGE: {
+	  cyg_uint32 total_clusters;
+	  cyg_uint32 free_clusters;
+	  struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
+	  fatfs_disk_t  *disk   = (fatfs_disk_t *) mte->data;
+
+	  err = fatfs_get_disk_usage(disk, &total_clusters, &free_clusters);
+	  if (err)
+	    return err;
+	  usage->total_blocks = total_clusters; 
+	  usage->free_blocks = free_clusters;
+	  usage->block_size = disk->cluster_size;
+	  break;
+	}
+#endif
         default:
             err = EINVAL;
             break;
Index: fs/fat/current/tests/fatfs1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/tests/fatfs1.c,v
retrieving revision 1.2
diff -u -r1.2 fatfs1.c
--- fs/fat/current/tests/fatfs1.c	27 Mar 2005 18:22:01 -0000	1.2
+++ fs/fat/current/tests/fatfs1.c	4 Aug 2006 09:15:54 -0000
@@ -432,6 +432,9 @@
 {
     int err;
     int existingdirents=-1;
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    struct cyg_fs_block_usage usage;
+#endif
 
     CYG_TEST_INIT();
 
@@ -448,6 +451,16 @@
     listdir( "/", true, -1, &existingdirents );
 
     // --------------------------------------------------------------
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
 
     createfile( "/foo", 20257 );
     checkfile( "foo" );
@@ -480,6 +493,15 @@
     checkfile( "/bar/bundy" );
     comparefiles("/fee", "bundy" );
 
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
     // --------------------------------------------------------------
 
     diag_printf("<INFO>: unlink fee\n");    

[-- Attachment #3: ram.diff --]
[-- Type: text/plain, Size: 6436 bytes --]

? fs/ram/current/tests/ramfs3.c
Index: fs/ram/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/ram/current/ChangeLog,v
retrieving revision 1.17
diff -u -r1.17 ChangeLog
--- fs/ram/current/ChangeLog	17 May 2006 16:12:11 -0000	1.17
+++ fs/ram/current/ChangeLog	4 Aug 2006 09:16:15 -0000
@@ -1,3 +1,10 @@
+2006-06-25  Andrew Lunn  <lunn@laptop.lunn.ch>
+
+	* src/ramfs.c (find_direntry): Don't search off the end of the
+	directory node into hyperspace.
+	* src/ramfs.c (ramfs_getinfo): Support for block usage call.
+	* tests/ramfs1.c (main): Add file system block usage test. 
+
 2006-05-17  Andy Jackson  <andy@grapevinetech.co.uk>
 
 	* tests/ramfs1.c (createfile): Fix compile warnings.
Index: fs/ram/current/src/ramfs.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/ram/current/src/ramfs.c,v
retrieving revision 1.9
diff -u -r1.9 ramfs.c
--- fs/ram/current/src/ramfs.c	2 Oct 2005 14:03:14 -0000	1.9
+++ fs/ram/current/src/ramfs.c	4 Aug 2006 09:16:15 -0000
@@ -1210,11 +1210,11 @@
         ramfs_dirent *d;
         cyg_uint8 *buf;
         size_t size;
-        
+
         // look for a first name fragment
         for(;;)
         {
-            err = findbuffer_node( dir, pos, &buf, &size, false );
+	  err = findbuffer_node( dir, pos, &buf, &size, false );
             if( err != ENOERR || size == 0)
                 return NULL;
 
@@ -1223,7 +1223,10 @@
             if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
             {
                 pos += sizeof(ramfs_dirent);
-                continue;
+		if ( pos < dir->size )
+		  continue;
+		// End if directory, didn't find it.
+		return NULL;
             }
 
             break;
@@ -1248,17 +1251,17 @@
                     fraglen = d->fraglen;
 
                 // compare strings, if different, look for another
-                if( memcmp( frag, d->name, fraglen ) != 0 )
-                    break;
-
+                if( memcmp( frag, d->name, fraglen ) != 0 ) {
+		  break;
+		}
                 frag        += fraglen;
             
                 // If we are at the last fragment, then the whole name string
                 // has matched and we have a successful search.
                 
-                if( d->last )
-                        return first;
-
+                if( d->last ) 
+		  return first;
+		
                 // Otherwise move on to next entry in chain
                 err = findbuffer_node( dir, d->next, &buf, &size, false );
                 if( err != ENOERR )
@@ -1977,7 +1980,7 @@
 
 // -------------------------------------------------------------------------
 // ramfs_getinfo()
-// Getinfo. Currently only support pathconf().
+// Getinfo. Currently only support pathconf() and filesystem usage.
 
 static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                              int key, void *buf, int len )
@@ -1996,7 +1999,26 @@
     case FS_INFO_CONF:
         err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
         break;
-        
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
+	// When using malloc for storage this does not make much
+	// sense, so only implement this when using pre-allocated
+	// blocks
+    case FS_INFO_BLOCK_USAGE: {
+      struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
+      ramfs_block *b;
+      
+      usage->total_blocks = CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE;
+      usage->free_blocks = 0;
+      // Iterate over the free list to count its size
+      b = block_free_list;
+      while(b) {
+	usage->free_blocks++;
+	b=*(ramfs_block **)b;
+      }
+      usage->block_size = CYGNUM_RAMFS_BLOCK_SIZE;
+      return ENOERR;
+    }
+#endif
     default:
         err = EINVAL;
     }
Index: fs/ram/current/tests/ramfs1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/ram/current/tests/ramfs1.c,v
retrieving revision 1.3
diff -u -r1.3 ramfs1.c
--- fs/ram/current/tests/ramfs1.c	17 May 2006 16:12:12 -0000	1.3
+++ fs/ram/current/tests/ramfs1.c	4 Aug 2006 09:16:16 -0000
@@ -61,6 +61,7 @@
 #include <pkgconf/hal.h>
 #include <pkgconf/kernel.h>
 #include <pkgconf/io_fileio.h>
+#include <pkgconf/fs_ram.h>
 
 #include <cyg/kernel/ktypes.h>         // base kernel types
 #include <cyg/infra/cyg_trac.h>        // tracing macros
@@ -415,6 +416,9 @@
 {
     int err;
     int existingdirents=-1;
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
+    struct cyg_fs_block_usage usage;
+#endif
 
     CYG_TEST_INIT();
 
@@ -431,7 +435,16 @@
     listdir( "/", true, -1, &existingdirents );
     if ( existingdirents < 2 )
         CYG_TEST_FAIL("Not enough dir entries\n");
-
+    // --------------------------------------------------------------
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
     // --------------------------------------------------------------
 
     createfile( "/foo", 202 );
@@ -552,6 +565,16 @@
     listdir( "..", true, existingdirents+3, NULL );
 
     // --------------------------------------------------------------
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
 
     diag_printf("<INFO>: unlink tinky\n");    
     err = unlink( "tinky" );

[-- Attachment #4: rom.diff --]
[-- Type: text/plain, Size: 4173 bytes --]

Index: fs/rom/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/rom/current/ChangeLog,v
retrieving revision 1.19
diff -u -r1.19 ChangeLog
--- fs/rom/current/ChangeLog	15 Feb 2006 20:04:51 -0000	1.19
+++ fs/rom/current/ChangeLog	4 Aug 2006 09:21:05 -0000
@@ -1,3 +1,8 @@
+2006-08-04 Andrew Lunn <andrew.lunn@ascom.ch>
+	
+	* src/romfs.c (romfs_getinfo): Support for block usage call.
+	* tests/romfs1.c (main): Add file system block usage test. 
+
 2006-02-15  Andrew Lunn  <andrew.lunn@ascom.ch>
             Peter Korsgaard  <jacmet@sunsite.dk>
 	
Index: fs/rom/current/src/romfs.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/rom/current/src/romfs.c,v
retrieving revision 1.7
diff -u -r1.7 romfs.c
--- fs/rom/current/src/romfs.c	5 Oct 2004 08:00:43 -0000	1.7
+++ fs/rom/current/src/romfs.c	4 Aug 2006 09:21:05 -0000
@@ -800,7 +800,7 @@
 
 // -------------------------------------------------------------------------
 // romfs_getinfo()
-// Getinfo. Currently only support pathconf().
+// Getinfo. Currently only support pathconf() and file system block usage
 
 static int romfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                              int key, void *buf, int len )
@@ -819,7 +819,16 @@
     case FS_INFO_CONF:
         err = romfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
         break;
-        
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    case FS_INFO_BLOCK_USAGE: {
+      struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
+      struct romfs_disk *disk = (struct romfs_disk*) mte->data;
+      usage->total_blocks = disk->disksize;
+      usage->free_blocks = 0;
+      usage->block_size = 1;
+      return ENOERR;
+    }
+#endif
     default:
         err = EINVAL;
     }
Index: fs/rom/current/tests/romfs1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/rom/current/tests/romfs1.c,v
retrieving revision 1.1
diff -u -r1.1 romfs1.c
--- fs/rom/current/tests/romfs1.c	13 Dec 2004 15:34:53 -0000	1.1
+++ fs/rom/current/tests/romfs1.c	4 Aug 2006 09:21:06 -0000
@@ -91,11 +91,11 @@
 //==========================================================================
 
 #define SHOW_RESULT( _fn, _res ) \
-diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
+  diag_printf("<FAIL>: " #_fn "() returned %d %s\n", (int)_res, _res<0?strerror(errno):"");
 
 #define CHKFAIL_TYPE( _fn, _res, _type ) { \
 if ( _res != -1 ) \
-    diag_printf("<FAIL>: " #_fn "() returned %d (expected -1)\n", _res); \
+  diag_printf("<FAIL>: " #_fn "() returned %d (expected -1)\n", (int)_res); \
 else if ( errno != _type ) \
     diag_printf("<FAIL>: " #_fn "() failed with errno %d (%s),\n    expected %d (%s)\n", errno, strerror(errno), _type, strerror(_type) ); \
 }
@@ -166,7 +166,7 @@
             }
             else
             {
-                diag_printf(" [mode %08x ino %08x nlink %d size %d]",
+                diag_printf(" [mode %08x ino %08x nlink %d size %ld]",
                             sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
             }
         }
@@ -286,6 +286,9 @@
 {
     int err;
     char address[16];
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    struct cyg_fs_block_usage usage;
+#endif
 
     CYG_TEST_INIT();
 
@@ -377,6 +380,17 @@
     CHKFAIL_TYPE( umount, err, EINVAL );
 #endif
 
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
+
     err = umount( "/" );
     if( err < 0 ) SHOW_RESULT( umount, err );    
 

[-- Attachment #5: jffs2.diff --]
[-- Type: text/plain, Size: 3284 bytes --]

? fs/jffs2/current/support/jffs2.ecm
? fs/jffs2/current/support/mktestfs.sh
Index: fs/jffs2/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/ChangeLog,v
retrieving revision 1.51
diff -u -r1.51 ChangeLog
--- fs/jffs2/current/ChangeLog	9 May 2006 16:17:55 -0000	1.51
+++ fs/jffs2/current/ChangeLog	4 Aug 2006 09:16:45 -0000
@@ -1,3 +1,9 @@
+2006-06-25  Andrew Lunn  <lunn@laptop.lunn.ch>
+
+	* src/fs-ecos.c (jffs2_getinfo): Add cyg_fs_getinfo support
+	for getting the block usage of the file system.
+	* tests/jffs2_1.c: Test for new getinfo call.
+
 2006-03-09  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/fs-ecos.c: Generalise the check for broken ARM compilers
Index: fs/jffs2/current/src/fs-ecos.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/src/fs-ecos.c,v
retrieving revision 1.39
diff -u -r1.39 fs-ecos.c
--- fs/jffs2/current/src/fs-ecos.c	9 May 2006 16:17:55 -0000	1.39
+++ fs/jffs2/current/src/fs-ecos.c	4 Aug 2006 09:16:47 -0000
@@ -1171,7 +1171,7 @@
 
 // -------------------------------------------------------------------------
 // jffs2_getinfo()
-// Getinfo. Currently only support pathconf().
+// Getinfo. Currently only support pathconf() and block usage
 
 static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
 			 int key, void *buf, int len)
@@ -1195,6 +1195,18 @@
 		err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
 		break;
 
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+	case FS_INFO_BLOCK_USAGE: {
+	  struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
+	  struct super_block *jffs2_sb = (struct super_block *)mte->data;
+	  struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
+	  
+	  usage->total_blocks = c->flash_size;
+	  usage->free_blocks = c->free_size;
+	  usage->block_size = 1;
+	  return ENOERR;
+	}
+#endif
 	default:
 		err = EINVAL;
 	}
Index: fs/jffs2/current/tests/jffs2_1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/jffs2/current/tests/jffs2_1.c,v
retrieving revision 1.5
diff -u -r1.5 jffs2_1.c
--- fs/jffs2/current/tests/jffs2_1.c	3 Aug 2005 20:39:51 -0000	1.5
+++ fs/jffs2/current/tests/jffs2_1.c	4 Aug 2006 09:16:48 -0000
@@ -420,6 +420,9 @@
     int err;
     //int i;
     int existingdirents=-1;
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    struct cyg_fs_block_usage usage;
+#endif
 
     CYG_TEST_INIT();
 
@@ -436,6 +439,15 @@
     listdir( "/", true, -1, &existingdirents );
     if ( existingdirents < 2 )
         CYG_TEST_FAIL("Not enough dir entries\n");
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+		usage.total_blocks, usage.total_blocks * usage.block_size); 
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+		usage.free_blocks, usage.free_blocks * usage.block_size); 
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
 
     // --------------------------------------------------------------
 

             reply	other threads:[~2006-08-04  9:30 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-04  9:30 Andrew Lunn [this message]
2009-01-27 22:02 Nathan Heijermans

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060804093005.GC17682@lunn.ch \
    --to=andrew@lunn.ch \
    --cc=ecos-patches@ecos.sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).