diff --git a/CHANGES.md b/CHANGES.md index 2a38acf20d..da9a4e4534 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,7 @@ Features * [#988](https://github.com/java-native-access/jna/issues/988): Added `PdhLookupPerfIndexByEnglishName` to `c.s.j.platform.win32.PdhUtil` - [@dbwiddis](https://github.com/dbwiddis). * [#992](https://github.com/java-native-access/jna/pull/992): Improve stability of windows tests and add appveyor configuration for windows CI builds - [@matthiasblaesing](https://github.com/matthiasblaesing). * [#994](https://github.com/java-native-access/jna/issues/994): Added `CoInitializeSecurity` and `CoSetProxyBlanket` to `c.s.j.platform.win32.Ole32`, added new `c.s.j.platform.win32.Wbemcli` classes needed to query WMI, and added a `WbemcliUtil` class implementing WMI queries. - [@dbwiddis](https://github.com/dbwiddis). +* [#995](https://github.com/java-native-access/jna/pull/995): Added structures and methods to `c.s.j.platform.mac.SystemB` for Process, Network interface, Swapfile, Time, and Filesystem info - [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index c75e1579af..b31182ae65 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java @@ -25,10 +25,12 @@ package com.sun.jna.platform.mac; +import java.util.Arrays; import java.util.List; import com.sun.jna.Library; import com.sun.jna.Native; +import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.Structure; import com.sun.jna.ptr.IntByReference; @@ -65,6 +67,31 @@ public interface SystemB extends Library { int UINT64_SIZE = Native.getNativeSize(long.class); int INT_SIZE = Native.getNativeSize(int.class); + // params.h + int MAXCOMLEN = 16; + int MAXPATHLEN = 1024; + int PROC_PIDPATHINFO_MAXSIZE = MAXPATHLEN * 4; + + // proc_info.h + int PROC_ALL_PIDS = 1; + int PROC_PIDTASKALLINFO = 2; + int PROC_PIDTBSDINFO = 3; + int PROC_PIDTASKINFO = 4; + int PROC_PIDVNODEPATHINFO = 9; + + // length of fs type name including null + int MFSTYPENAMELEN = 16; + // length of buffer for returned name + int MNAMELEN = MAXPATHLEN; + + // fsstat paths + int MNT_WAIT = 0x0001; + int MNT_NOWAIT = 0x0010; + int MNT_DWAIT = 0x0100; + + // resource.h + int RUSAGE_INFO_V2 = 2; + @Structure.FieldOrder({"cpu_ticks"}) public static class HostCpuLoadInfo extends Structure { public int cpu_ticks[] = new int[CPU_STATE_MAX]; @@ -146,6 +173,395 @@ public static class VMStatistics64 extends Structure { public long total_uncompressed_pages_in_compressor; } + @Structure.FieldOrder({"pbsd", "ptinfo"}) + class ProcTaskAllInfo extends Structure { + public ProcBsdInfo pbsd; + public ProcTaskInfo ptinfo; + } + + @Structure.FieldOrder({"pbi_flags", "pbi_status", "pbi_xstatus", "pbi_pid", "pbi_ppid", + "pbi_uid", "pbi_gid", "pbi_ruid", "pbi_rgid", "pbi_svuid", "pbi_svgid", "rfu_1", "pbi_comm", + "pbi_name", "pbi_nfiles", "pbi_pgid", "pbi_pjobc", "e_tdev", "e_tpgid", "pbi_nice", + "pbi_start_tvsec", "pbi_start_tvusec"}) + class ProcBsdInfo extends Structure { + public int pbi_flags; + public int pbi_status; + public int pbi_xstatus; + public int pbi_pid; + public int pbi_ppid; + public int pbi_uid; + public int pbi_gid; + public int pbi_ruid; + public int pbi_rgid; + public int pbi_svuid; + public int pbi_svgid; + public int rfu_1; + public byte[] pbi_comm = new byte[MAXCOMLEN]; + public byte[] pbi_name = new byte[2 * MAXCOMLEN]; + public int pbi_nfiles; + public int pbi_pgid; + public int pbi_pjobc; + public int e_tdev; + public int e_tpgid; + public int pbi_nice; + public long pbi_start_tvsec; + public long pbi_start_tvusec; + } + + @Structure.FieldOrder({"pti_virtual_size", "pti_resident_size", "pti_total_user", + "pti_total_system", "pti_threads_user", "pti_threads_system", "pti_policy", "pti_faults", + "pti_pageins", "pti_cow_faults", "pti_messages_sent", "pti_messages_received", "pti_syscalls_mach", + "pti_syscalls_unix", "pti_csw", "pti_threadnum", "pti_numrunning", "pti_priority"}) + class ProcTaskInfo extends Structure { + public long pti_virtual_size; /* virtual memory size (bytes) */ + public long pti_resident_size; /* resident memory size (bytes) */ + public long pti_total_user; /* total time (nanoseconds) */ + public long pti_total_system; + public long pti_threads_user; /* existing threads only */ + public long pti_threads_system; + public int pti_policy; /* default policy for new threads */ + public int pti_faults; /* number of page faults */ + public int pti_pageins; /* number of actual pageins */ + public int pti_cow_faults; /* number of copy-on-write faults */ + public int pti_messages_sent; /* number of messages sent */ + public int pti_messages_received; /* number of messages received */ + public int pti_syscalls_mach; /* number of mach system calls */ + public int pti_syscalls_unix; /* number of unix system calls */ + public int pti_csw; /* number of context switches */ + public int pti_threadnum; /* number of threads in the task */ + public int pti_numrunning; /* number of running threads */ + public int pti_priority; /* task priority */ + } + + @Structure.FieldOrder({"v_swtch", "v_trap", "v_syscall", "v_intr", "v_soft", "v_faults", + "v_lookups", "v_hits", "v_vm_faults", "v_cow_faults", "v_swpin", "v_swpout", "v_pswpin", + "v_pswpout", "v_pageins", "v_pageouts", "v_pgpgin", "v_pgpgout", "v_intrans", "v_reactivated", + "v_rev", "v_scan", "v_dfree", "v_pfree", "v_zfod", "v_nzfod", "v_page_size", "v_kernel_pages", + "v_free_target", "v_free_min", "v_free_count", "v_wire_count", "v_active_count", + "v_inactive_target", "v_inactive_count"}) + class VMMeter extends Structure { + /* + * General system activity. + */ + public int v_swtch; /* context switches */ + public int v_trap; /* calls to trap */ + public int v_syscall; /* calls to syscall() */ + public int v_intr; /* device interrupts */ + public int v_soft; /* software interrupts */ + public int v_faults; /* total faults taken */ + /* + * Virtual memory activity. + */ + public int v_lookups; /* object cache lookups */ + public int v_hits; /* object cache hits */ + public int v_vm_faults; /* number of address memory faults */ + public int v_cow_faults; /* number of copy-on-writes */ + public int v_swpin; /* swapins */ + public int v_swpout; /* swapouts */ + public int v_pswpin; /* pages swapped in */ + public int v_pswpout; /* pages swapped out */ + public int v_pageins; /* number of pageins */ + public int v_pageouts; /* number of pageouts */ + public int v_pgpgin; /* pages paged in */ + public int v_pgpgout; /* pages paged out */ + public int v_intrans; /* intransit blocking page faults */ + public int v_reactivated; /* + * number of pages reactivated from free list + */ + public int v_rev; /* revolutions of the hand */ + public int v_scan; /* scans in page out daemon */ + public int v_dfree; /* pages freed by daemon */ + public int v_pfree; /* pages freed by exiting processes */ + public int v_zfod; /* pages zero filled on demand */ + public int v_nzfod; /* number of zfod's created */ + /* + * Distribution of page usages. + */ + public int v_page_size; /* page size in bytes */ + public int v_kernel_pages; /* number of pages in use by kernel */ + public int v_free_target; /* number of pages desired free */ + public int v_free_min; /* minimum number of pages desired free */ + public int v_free_count; /* number of pages free */ + public int v_wire_count; /* number of pages wired down */ + public int v_active_count; /* number of pages active */ + public int v_inactive_target; /* number of pages desired inactive */ + public int v_inactive_count; /* number of pages inactive */ + } + + @Structure.FieldOrder({"ri_uuid", "ri_user_time", "ri_system_time", "ri_pkg_idle_wkups", + "ri_interrupt_wkups", "ri_pageins", "ri_wired_size", "ri_resident_size", "ri_phys_footprint", + "ri_proc_start_abstime", "ri_proc_exit_abstime", "ri_child_user_time", "ri_child_system_time", + "ri_child_pkg_idle_wkups", "ri_child_interrupt_wkups", "ri_child_pageins", + "ri_child_elapsed_abstime", "ri_diskio_bytesread", "ri_diskio_byteswritten" }) + class RUsageInfoV2 extends Structure { + public byte[] ri_uuid = new byte[16]; + public long ri_user_time; + public long ri_system_time; + public long ri_pkg_idle_wkups; + public long ri_interrupt_wkups; + public long ri_pageins; + public long ri_wired_size; + public long ri_resident_size; + public long ri_phys_footprint; + public long ri_proc_start_abstime; + public long ri_proc_exit_abstime; + public long ri_child_user_time; + public long ri_child_system_time; + public long ri_child_pkg_idle_wkups; + public long ri_child_interrupt_wkups; + public long ri_child_pageins; + public long ri_child_elapsed_abstime; + public long ri_diskio_bytesread; + public long ri_diskio_byteswritten; + } + + @Structure.FieldOrder({"vip_vi", "vip_path"}) + class VnodeInfoPath extends Structure { + public byte[] vip_vi = new byte[152]; // vnode_info but we don't + // need its data + public byte[] vip_path = new byte[MAXPATHLEN]; + } + + @Structure.FieldOrder({"pvi_cdir", "pvi_rdir"}) + class VnodePathInfo extends Structure { + public VnodeInfoPath pvi_cdir; + public VnodeInfoPath pvi_rdir; + } + + /** + * The statfs() routine returns information about a mounted file system. The + * path argument is the path name of any file or directory within the + * mounted file system. The buf argument is a pointer to a statfs structure. + */ + @Structure.FieldOrder({"f_bsize", "f_iosize", "f_blocks", "f_bfree", "f_bavail", "f_files", + "f_ffree", "f_fsid", "f_owner", "f_type", "f_flags", "f_fssubtype", "f_fstypename", "f_mntonname", + "f_mntfromname", "f_reserved" }) + class Statfs extends Structure { + public int f_bsize; /* fundamental file system block size */ + public int f_iosize; /* optimal transfer block size */ + public long f_blocks; /* total data blocks in file system */ + public long f_bfree; /* free blocks in fs */ + public long f_bavail; /* free blocks avail to non-superuser */ + public long f_files; /* total file nodes in file system */ + public long f_ffree; /* free file nodes in fs */ + public int[] f_fsid = new int[2]; /* file system id */ + public int f_owner; /* user that mounted the filesystem */ + public int f_type; /* type of filesystem */ + public int f_flags; /* copy of mount exported flags */ + public int f_fssubtype; /* fs sub-type (flavor) */ + /* fs type name */ + public byte[] f_fstypename = new byte[MFSTYPENAMELEN]; + /* directory on which mounted */ + public byte[] f_mntonname = new byte[MAXPATHLEN]; + /* mounted filesystem */ + public byte[] f_mntfromname = new byte[MAXPATHLEN]; + public int[] f_reserved = new int[8]; /* For future use */ + } + + /** + * Return type for sysctl vm.swapusage + */ + @Structure.FieldOrder({"xsu_total", "xsu_avail", "xsu_used", "xsu_pagesize", "xsu_encrypted"}) + class XswUsage extends Structure { + public long xsu_total; + public long xsu_avail; + public long xsu_used; + public int xsu_pagesize; + public boolean xsu_encrypted; + } + + /** + * Data type as part of IFmsgHdr + */ + @Structure.FieldOrder({"ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", + "ifi_recvquota", "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", + "ifi_ipackets", "ifi_ierrors", "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", + "ifi_obytes", "ifi_imcasts", "ifi_omcasts", "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", + "ifi_xmittiming", "ifi_lastchange", "ifi_unused2", "ifi_hwassist", "ifi_reserved1", + "ifi_reserved2"}) + class IFdata extends Structure { + public byte ifi_type; // ethernet, tokenring, etc + public byte ifi_typelen; // Length of frame type id + public byte ifi_physical; // e.g., AUI, Thinnet, 10base-T, etc + public byte ifi_addrlen; // media address length + public byte ifi_hdrlen; // media header length + public byte ifi_recvquota; // polling quota for receive intrs + public byte ifi_xmitquota; // polling quota for xmit intrs + public byte ifi_unused1; // for future use + public int ifi_mtu; // maximum transmission unit + public int ifi_metric; // routing metric (external only) + public int ifi_baudrate; // linespeed + public int ifi_ipackets; // packets received on interface + public int ifi_ierrors; // input errors on interface + public int ifi_opackets; // packets sent on interface + public int ifi_oerrors; // output errors on interface + public int ifi_collisions; // collisions on csma interfaces + public int ifi_ibytes; // total number of octets received + public int ifi_obytes; // total number of octets sent + public int ifi_imcasts; // packets received via multicast + public int ifi_omcasts; // packets sent via multicast + public int ifi_iqdrops; // dropped on input, this interface + public int ifi_noproto; // destined for unsupported protocol + public int ifi_recvtiming; // usec spent receiving when timing + public int ifi_xmittiming; // usec spent xmitting when timing + public Timeval ifi_lastchange; // time of last administrative change + public int ifi_unused2; // used to be the default_proto + public int ifi_hwassist; // HW offload capabilities + public int ifi_reserved1; // for future use + public int ifi_reserved2; // for future use + } + + /** + * Return type for sysctl CTL_NET,PF_ROUTE + */ + @Structure.FieldOrder({"ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", + "ifm_index", "ifm_data" }) + class IFmsgHdr extends Structure { + public short ifm_msglen; // to skip over non-understood messages + public byte ifm_version; // future binary compatability + public byte ifm_type; // message type + public int ifm_addrs; // like rtm_addrs + public int ifm_flags; // value of if_flags + public short ifm_index; // index for associated ifp + public IFdata ifm_data; // statistics and other data about if + + public IFmsgHdr() { + super(); + } + + public IFmsgHdr(Pointer p) { + super(p); + } + } + + /** + * Data type as part of IFmsgHdr + */ + @Structure.FieldOrder({ "ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", + "ifi_recvquota", "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", + "ifi_ipackets", "ifi_ierrors", "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", + "ifi_obytes", "ifi_imcasts", "ifi_omcasts", "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", + "ifi_xmittiming", "ifi_lastchange"}) + class IFdata64 extends Structure { + public byte ifi_type; // ethernet, tokenring, etc + public byte ifi_typelen; // Length of frame type id + public byte ifi_physical; // e.g., AUI, Thinnet, 10base-T, etc + public byte ifi_addrlen; // media address length + public byte ifi_hdrlen; // media header length + public byte ifi_recvquota; // polling quota for receive intrs + public byte ifi_xmitquota; // polling quota for xmit intrs + public byte ifi_unused1; // for future use + public int ifi_mtu; // maximum transmission unit + public int ifi_metric; // routing metric (external only) + public long ifi_baudrate; // linespeed + public long ifi_ipackets; // packets received on interface + public long ifi_ierrors; // input errors on interface + public long ifi_opackets; // packets sent on interface + public long ifi_oerrors; // output errors on interface + public long ifi_collisions; // collisions on csma interfaces + public long ifi_ibytes; // total number of octets received + public long ifi_obytes; // total number of octets sent + public long ifi_imcasts; // packets received via multicast + public long ifi_omcasts; // packets sent via multicast + public long ifi_iqdrops; // dropped on input, this interface + public long ifi_noproto; // destined for unsupported protocol + public int ifi_recvtiming; // usec spent receiving when timing + public int ifi_xmittiming; // usec spent xmitting when timing + public Timeval ifi_lastchange; // time of last administrative change + } + + /** + * Return type for sysctl CTL_NET,PF_ROUTE + */ + @Structure.FieldOrder({ "ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", + "ifm_index", "ifm_snd_len", "ifm_snd_maxlen", "ifm_snd_drops", "ifm_timer", "ifm_data"}) + class IFmsgHdr2 extends Structure { + public short ifm_msglen; // to skip over non-understood messages + public byte ifm_version; // future binary compatability + public byte ifm_type; // message type + public int ifm_addrs; // like rtm_addrs + public int ifm_flags; // value of if_flags + public short ifm_index; // index for associated ifp + public int ifm_snd_len; // instantaneous length of send queue + public int ifm_snd_maxlen; // maximum length of send queue + public int ifm_snd_drops; // number of drops in send queue + public int ifm_timer; // time until if_watchdog called + public IFdata64 ifm_data; // statistics and other data about if + + public IFmsgHdr2(Pointer p) { + super(p); + } + } + + /** + * Return type for getpwuid + */ + @Structure.FieldOrder({"pw_name", "pw_passwd", "pw_uid", "pw_gid", "pw_change", "pw_class", + "pw_gecos", "pw_dir", "pw_shell", "pw_expire", "pw_fields" }) + class Passwd extends Structure { + public String pw_name; // user name + public String pw_passwd; // encrypted password + public int pw_uid; // user uid + public int pw_gid; // user gid + public NativeLong pw_change; // password change time + public String pw_class; // user access class + public String pw_gecos; // Honeywell login info + public String pw_dir; // home directory + public String pw_shell; // default shell + public NativeLong pw_expire; // account expiration + public int pw_fields; // internal: fields filled in + } + + /** + * Return type for getgrgid + */ + @Structure.FieldOrder({"gr_name", "gr_passwd", "gr_gid", "gr_mem"}) + class Group extends Structure { + public String gr_name; /* group name */ + public String gr_passwd; /* group password */ + public int gr_gid; /* group id */ + public PointerByReference gr_mem; /* group members */ + } + + /** + * Time value + */ + @Structure.FieldOrder({"tv_sec", "tv_usec"}) + class Timeval extends Structure { + public NativeLong tv_sec; // seconds + public int tv_usec; // microseconds + } + + /** + * Time Zone + */ + @Structure.FieldOrder({ "tz_minuteswest", "tz_dsttime"}) + class Timezone extends Structure { + public int tz_minuteswest; /* of Greenwich */ + public int tz_dsttime; /* type of dst correction to apply */ + } + + /** + * The system's notion of the current Greenwich time and the current time + * zone is obtained with the gettimeofday() call, and set with the + * settimeofday() call. The time is expressed in seconds and microseconds + * since midnight (0 hour), January 1, 1970. The resolution of the system + * clock is hardware dependent, and the time may be updated continuously or + * in ``ticks.'' If tp is NULL and tzp is non-NULL, gettimeofday() will + * populate the timezone struct in tzp. If tp is non-NULL and tzp is NULL, + * then only the timeval struct in tp is populated. If both tp and tzp are + * NULL, nothing is returned. + * + * @param tp + * Timeval structure + * @param tzp + * Timezone structure + * @return A 0 return value indicates that the call succeeded. A -1 return + * value indicates an error occurred, and in this case an error code + * is stored into the global variable errno. + */ + int gettimeofday(Timeval tp, Timezone tzp); + /** * The mach_host_self system call returns the calling thread's host name * port. It has an effect equivalent to receiving a send right for the host @@ -344,4 +760,129 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, * @see getloadavg(3) */ int getloadavg(double[] loadavg, int nelem); + + /** + * This function searches the password database for the given user uid, + * always returning the first one encountered. + * + * @param uid + * The user ID + * @return a Passwd structure matching that user + */ + Passwd getpwuid(int uid); + + /** + * This function searches the group database for the given group name + * pointed to by the group id given by gid, returning the first one + * encountered. Identical group gids may result in undefined behavior. + * + * @param gid + * The group ID + * @return a Group structure matching that group + */ + Group getgrgid(int gid); + + /** + * Search through the current processes + * + * @param type + * types of processes to be searched + * @param typeinfo + * adjunct information for type + * @param buffer + * a C array of int-sized values to be filled with process + * identifiers that hold an open file reference matching the + * specified path or volume. Pass NULL to obtain the minimum + * buffer size needed to hold the currently active processes. + * @param buffersize + * the size (in bytes) of the provided buffer. + * @return the number of bytes of data returned in the provided buffer; -1 + * if an error was encountered; + */ + int proc_listpids(int type, int typeinfo, int[] buffer, int buffersize); + + /** + * Return in buffer a proc_*info structure corresponding to the flavor for + * the specified process + * + * @param pid + * the process identifier + * @param flavor + * the type of information requested + * @param arg + * argument possibly needed for some flavors + * @param buffer + * holds results + * @param buffersize + * size of results + * @return the number of bytes of data returned in the provided buffer; -1 + * if an error was encountered; + */ + int proc_pidinfo(int pid, int flavor, long arg, Structure buffer, int buffersize); + + /** + * Return in buffer the name of the specified process + * + * @param pid + * the process identifier + * @param buffer + * holds results + * @param buffersize + * size of results + * @return the length of the name returned in buffer if successful; 0 + * otherwise + */ + int proc_pidpath(int pid, Pointer buffer, int buffersize); + + /** + * Return resource usage information for the given pid, which can be a live + * process or a zombie. + * + * @param pid + * the process identifier + * @param flavor + * the type of information requested + * @param buffer + * holds results + * @return 0 on success; or -1 on failure, with errno set to indicate the + * specific error. + */ + int proc_pid_rusage(int pid, int flavor, RUsageInfoV2 buffer); + + /** + * The getfsstat() function returns information about all mounted file + * systems. The buf argument is a pointer to an array of statfs structures. + * + * Fields that are undefined for a particular file system are set to -1. The + * buffer is filled with an array of statfs structures, one for each mounted + * file system up to the size specified by bufsize. + * + * @param buf + * Array of statfs structures that will be filled with results. + * If buf is given as NULL, getfsstat() returns just the number + * of mounted file systems. + * @param bufsize + * Size of the buffer to fill + * @param flags + * If flags is set to MNT_NOWAIT, getfsstat() will directly + * return the information retained in the kernel to avoid delays + * caused by waiting for updated information from a file system + * that is perhaps temporarily unable to respond. Some of the + * information returned may be out of date, however; if flags is + * set to MNT_WAIT or MNT_DWAIT instead, getfsstat() will request + * updated information from each mounted filesystem before + * returning. + * @return Upon successful completion, the number of statfs structures is + * returned. Otherwise, -1 is returned and the global variable errno + * is set to indicate the error. + */ + int getfsstat64(Statfs[] buf, int bufsize, int flags); + + /** + * Returns the process ID of the calling process. The ID is guaranteed to be + * unique and is useful for constructing temporary file names. + * + * @return the process ID of the calling process. + */ + int getpid(); } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java index 0ac161e0d4..25322a5fc0 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java @@ -16,20 +16,33 @@ */ package com.sun.jna.platform.mac; -import junit.framework.TestCase; - +import com.sun.jna.Memory; +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.SystemB.Group; import com.sun.jna.platform.mac.SystemB.HostCpuLoadInfo; import com.sun.jna.platform.mac.SystemB.HostLoadInfo; +import com.sun.jna.platform.mac.SystemB.IFmsgHdr; +import com.sun.jna.platform.mac.SystemB.IFmsgHdr2; +import com.sun.jna.platform.mac.SystemB.Passwd; +import com.sun.jna.platform.mac.SystemB.ProcTaskAllInfo; +import com.sun.jna.platform.mac.SystemB.RUsageInfoV2; +import com.sun.jna.platform.mac.SystemB.Statfs; +import com.sun.jna.platform.mac.SystemB.Timeval; +import com.sun.jna.platform.mac.SystemB.Timezone; +import com.sun.jna.platform.mac.SystemB.VMMeter; import com.sun.jna.platform.mac.SystemB.VMStatistics; import com.sun.jna.platform.mac.SystemB.VMStatistics64; - -import com.sun.jna.Memory; -import com.sun.jna.Platform; -import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.SystemB.VnodeInfoPath; +import com.sun.jna.platform.mac.SystemB.VnodePathInfo; +import com.sun.jna.platform.mac.SystemB.XswUsage; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; +import junit.framework.TestCase; + /** * Exercise the {@link SystemB} class. * @@ -169,8 +182,155 @@ public void testGetLoadAvg() { assertTrue(loadavg[2] >= 0); } - public static void main(java.lang.String[] argList) { - junit.textui.TestRunner.run(SystemBTest.class); - } + public void testTimeofDay() { + Timeval tp = new Timeval(); + long before = System.currentTimeMillis(); + assertEquals(0, SystemB.INSTANCE.gettimeofday(tp, null)); + long timeofday = tp.tv_sec.longValue() * 1000L + tp.tv_usec / 1000; + long after = System.currentTimeMillis(); + assertTrue(before <= timeofday); + assertTrue(after >= timeofday); + + Timezone tzp = new Timezone(); + assertEquals(0, SystemB.INSTANCE.gettimeofday(null, tzp)); + // DST is 0 or 1 + assertTrue(tzp.tz_dsttime <= 1); + // Timezones are GMT -12 (west) to +14 hours + assertTrue(tzp.tz_minuteswest <= 12 * 60); + assertTrue(tzp.tz_minuteswest >= -14 * 60); + } + + public void testVMMeter() { + int machPort = SystemB.INSTANCE.mach_host_self(); + VMMeter vmstats = new VMMeter(); + assertEquals(0, SystemB.INSTANCE.host_statistics(machPort, SystemB.HOST_VM_INFO, vmstats, + new IntByReference(vmstats.size()))); + assertTrue(vmstats.v_lookups >= 0); + } + + public void testStatfs() { + // Use statfs to populate mount point map + int numfs = SystemB.INSTANCE.getfsstat64(null, 0, 0); + Statfs[] fs = new Statfs[numfs]; + // Fill array with results + SystemB.INSTANCE.getfsstat64(fs, numfs * new Statfs().size(), SystemB.MNT_NOWAIT); + // Iterate all mounted file systems + for (Statfs f : fs) { + assertTrue(f.f_bfree <= f.f_blocks); + assertTrue(f.f_ffree <= f.f_files); + } + } + + public void testXswUsage() { + XswUsage xswUsage = new XswUsage(); + assertEquals(0, SystemB.INSTANCE.sysctlbyname("vm.swapusage", xswUsage.getPointer(), + new IntByReference(xswUsage.size()), null, 0)); + xswUsage.read(); + assertTrue(xswUsage.xsu_used <= xswUsage.xsu_total); + } + public void testProcessStructures() { + // Calc max # of processes + IntByReference size = new IntByReference(4); + Memory mem = new Memory(4); + assertEquals(0, SystemB.INSTANCE.sysctlbyname("kern.maxproc", mem, size, null, 0)); + int maxProc = mem.getInt(0); + + // Get list of pids + int[] pids = new int[maxProc]; + int bytesReturned = SystemB.INSTANCE.proc_listpids(SystemB.PROC_ALL_PIDS, 0, pids, maxProc * 4); + assertTrue(bytesReturned > 0); + assertEquals(0, bytesReturned % 4); + + // Current pid should be in list + int pid = SystemB.INSTANCE.getpid(); + assertTrue(pid > 0); + boolean foundPid = false; + for (int i = 0; i < pids.length; i++) { + if (pids[i] == pid) { + foundPid = true; + break; + } + } + assertTrue(foundPid); + + // ProcTaskAllInfo + ProcTaskAllInfo taskAllInfo = new ProcTaskAllInfo(); + bytesReturned = SystemB.INSTANCE.proc_pidinfo(pid, SystemB.PROC_PIDTASKALLINFO, 0, taskAllInfo, + taskAllInfo.size()); + assertTrue(bytesReturned > 0); + assertEquals(0, bytesReturned % Native.getNativeSize(ProcTaskAllInfo.class)); + + Pointer buf = new Memory(SystemB.PROC_PIDPATHINFO_MAXSIZE); + bytesReturned = SystemB.INSTANCE.proc_pidpath(pid, buf, SystemB.PROC_PIDPATHINFO_MAXSIZE); + String path = buf.getString(0).trim(); + assertEquals(bytesReturned, path.length()); + + // ProcTaskInfo + assertTrue(taskAllInfo.ptinfo.pti_threadnum > 0); + + // ProcBsdInfo + Passwd user = SystemB.INSTANCE.getpwuid(taskAllInfo.pbsd.pbi_uid); + assertEquals(user.pw_uid, taskAllInfo.pbsd.pbi_uid); + + Group group = SystemB.INSTANCE.getgrgid(taskAllInfo.pbsd.pbi_gid); + assertEquals(group.gr_gid, taskAllInfo.pbsd.pbi_gid); + + RUsageInfoV2 rUsageInfoV2 = new RUsageInfoV2(); + assertEquals(0, SystemB.INSTANCE.proc_pid_rusage(pid, SystemB.RUSAGE_INFO_V2, rUsageInfoV2)); + assertTrue(rUsageInfoV2.ri_diskio_bytesread >= 0); + + VnodePathInfo vpi = new VnodePathInfo(); + bytesReturned = SystemB.INSTANCE.proc_pidinfo(pid, SystemB.PROC_PIDVNODEPATHINFO, 0, vpi, vpi.size()); + assertTrue(bytesReturned > 0); + assertEquals(0, bytesReturned % Native.getNativeSize(VnodeInfoPath.class)); + + String cwd = Native.toString(vpi.pvi_cdir.vip_path); + assertTrue(cwd.length() > 0); + } + + public void testIFs() { + int RTM_IFINFO2 = 0x12; + // Get buffer of all interface information + int CTL_NET = 4; + int PF_ROUTE = 17; + int NET_RT_IFLIST2 = 6; + int[] mib = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 }; + + IntByReference len = new IntByReference(); + assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, null, len, null, 0)); + // Add enough room for max size of IFmsgHdr to avoid JNA bounds check + // problems with worst case structure size + Memory buf = new Memory(len.getValue() + 112); + assertEquals(0, SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, 0)); + + // Iterate offset from buf's pointer up to limit of buf + int lim = len.getValue(); + int next = 0; + while (next < lim) { + // Get pointer to current native part of buf + Pointer p = buf.share(next); + // Cast pointer to if_msghdr + IFmsgHdr ifm = new IFmsgHdr(p); + ifm.read(); + // Advance next + next += ifm.ifm_msglen; + // Skip messages which are not the right format + if (ifm.ifm_type != RTM_IFINFO2) { + continue; + } + // Cast pointer to if_msghdr2 + IFmsgHdr2 if2m = new IFmsgHdr2(p); + if2m.read(); + + + assertTrue(if2m.ifm_index >= 0); + assertTrue(if2m.ifm_data.ifi_ibytes >= 0); + assertTrue(if2m.ifm_data.ifi_lastchange.tv_usec >= 0); + } + } + + public static void main(java.lang.String[] argList) { + junit.textui.TestRunner.run(SystemBTest.class); + } } diff --git a/native/dispatch.c b/native/dispatch.c index 072aed4176..6cee809fb1 100644 --- a/native/dispatch.c +++ b/native/dispatch.c @@ -653,7 +653,7 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args, int err = GET_LAST_ERROR(); JNA_set_last_error(env, err); if ((flags & THROW_LAST_ERROR) && err) { - char emsg[MSG_SIZE]; + char emsg[MSG_SIZE - 3 /* literal characters */ - 10 /* max length of %d */]; snprintf(msg, sizeof(msg), "[%d] %s", err, STR_ERROR(err, emsg, sizeof(emsg))); throw_type = ELastError; throw_msg = msg; @@ -1896,7 +1896,7 @@ dispatch_direct(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) { int err = GET_LAST_ERROR(); JNA_set_last_error(env, err); if (data->throw_last_error && err) { - char emsg[MSG_SIZE]; + char emsg[MSG_SIZE - 3 /* literal characters */ - 10 /* max length of %d */]; snprintf(msg, sizeof(msg), "[%d] %s", err, STR_ERROR(err, emsg, sizeof(emsg))); throw_type = ELastError; throw_msg = msg; @@ -3096,7 +3096,7 @@ Java_com_sun_jna_Native_getWindowHandle0(JNIEnv* UNUSED_JAWT(env), jclass UNUSED return -1; } if ((pJAWT_GetAWT = (void*)FIND_ENTRY(jawt_handle, METHOD_NAME)) == NULL) { - char msg[MSG_SIZE], buf[MSG_SIZE]; + char msg[MSG_SIZE], buf[MSG_SIZE - 31 /* literal characters */ - sizeof(METHOD_NAME)]; snprintf(msg, sizeof(msg), "Error looking up JAWT method %s: %s", METHOD_NAME, LOAD_ERROR(buf, sizeof(buf))); throwByName(env, EUnsatisfiedLink, msg); diff --git a/native/testlib.c b/native/testlib.c index 575cf010ae..609ed75ede 100644 --- a/native/testlib.c +++ b/native/testlib.c @@ -805,7 +805,7 @@ callCallbackWithStructByValue(TestStructureByValue (*func)(TestStructureByValue) EXPORT callback_t callCallbackWithCallback(cb_callback_t cb) { - return (*cb)((callback_t)cb); + return (*cb)((callback_t)(void*)cb); } static int32_t