PageRenderTime 331ms CodeModel.GetById 14ms app.highlight 292ms RepoModel.GetById 1ms app.codeStats 1ms

/filesystems/procfs/procfs.cc

http://macfuse.googlecode.com/
C++ | 4975 lines | 4101 code | 796 blank | 78 comment | 606 complexity | 8905523075cf982ed57d446bcdf473d7 MD5 | raw file
   1/*
   2 * procfs as a MacFUSE file system for Mac OS X
   3 *
   4 * Copyright Amit Singh. All Rights Reserved.
   5 * http://osxbook.com
   6 *
   7 * http://code.google.com/p/macfuse/
   8 *
   9 * Source License: GNU GENERAL PUBLIC LICENSE (GPL)
  10 */
  11
  12#define MACFUSE_PROCFS_VERSION "2.0"
  13#define FUSE_USE_VERSION 26
  14
  15#include <dirent.h>
  16#include <errno.h>
  17#include <fcntl.h>
  18#include <getopt.h>
  19#include <pthread.h>
  20#include <stdio.h>
  21#include <string.h>
  22#include <sys/sysctl.h>
  23
  24#include <grp.h>
  25#include <pwd.h>
  26
  27#include <mach/mach.h>
  28#include <mach/mach_vm.h>
  29#include <mach/vm_region.h>
  30#include <mach/vm_statistics.h>
  31
  32#include <Carbon/Carbon.h>
  33#include <CoreFoundation/CoreFoundation.h>
  34#include <IOKit/IOKitLib.h>
  35
  36#include <cassert>
  37#include <vector>
  38#include <pcrecpp.h>
  39
  40#include <fuse.h>
  41
  42#include "procfs_displays.h"
  43#include "procfs_proc_info.h"
  44#include "procfs_windows.h"
  45#include "sequencegrab/procfs_sequencegrab.h"
  46
  47#if MACFUSE_PROCFS_ENABLE_TPM
  48#include "procfs_tpm.h"
  49#endif /* MACFUSE_PROCFS_ENABLE_TPM */
  50
  51static int procfs_ui = 0;
  52#define PROCFS_DEFAULT_FILE_SIZE 65536
  53
  54static int total_file_patterns = 0;
  55static int total_directory_patterns = 0;
  56static int total_link_patterns = 0;
  57
  58static processor_port_array_t processor_list;
  59static mach_port_t  p_default_set = 0;
  60static mach_port_t  p_default_set_control = 0;
  61static host_priv_t  host_priv;
  62static natural_t    processor_count = 0;
  63static io_connect_t lightsensor_port = 0;
  64static io_connect_t motionsensor_port = 0;
  65static unsigned int sms_gIndex = 0;
  66static IOItemCount  sms_gStructureInputSize = 0;
  67static IOByteCount  sms_gStructureOutputSize = 0;
  68
  69/* camera */
  70static pthread_mutex_t  camera_lock;
  71static int              camera_busy = 0;
  72static CFMutableDataRef camera_tiff = (CFMutableDataRef)0;
  73
  74/* display */
  75static pthread_mutex_t  display_lock;
  76static int              display_busy = 0;
  77static CFMutableDataRef display_png = (CFMutableDataRef)0;
  78
  79static pcrecpp::RE *valid_process_pattern = new pcrecpp::RE("/(\\d+)");
  80
  81typedef struct {
  82    char x;
  83    char y;
  84    char z;
  85    short v;
  86#define FILLER_SIZE 60
  87    char scratch[FILLER_SIZE];
  88} MotionSensorData_t;
  89
  90static kern_return_t
  91sms_getOrientation_hardware_apple(MotionSensorData_t *odata)
  92{
  93    kern_return_t      kr;
  94    IOItemCount        isize = sms_gStructureInputSize;
  95    IOByteCount        osize = sms_gStructureOutputSize;
  96    MotionSensorData_t idata;
  97
  98    kr = IOConnectMethodStructureIStructureO(motionsensor_port,
  99                                             sms_gIndex,
 100                                             isize,
 101                                             &osize,
 102                                             &idata,
 103                                             odata);
 104    return kr;
 105}
 106
 107static int init_task_list(task_array_t           *task_list,
 108                          mach_msg_type_number_t *task_count)
 109{
 110    return processor_set_tasks(p_default_set_control, task_list, task_count);
 111}
 112
 113static void fini_task_list(task_array_t           task_list,
 114                           mach_msg_type_number_t task_count)
 115{
 116    unsigned int i;
 117    for (i = 0; i < task_count; i++) {
 118        mach_port_deallocate(mach_task_self(), task_list[i]);
 119    }
 120    vm_deallocate(mach_task_self(), (vm_address_t)task_list,
 121                  task_count * sizeof(task_t));
 122}
 123
 124static int init_thread_list(task_t                  the_task,
 125                            thread_array_t         *thread_list,
 126                            mach_msg_type_number_t *thread_count)
 127{
 128    return task_threads(the_task, thread_list, thread_count);
 129}
 130
 131static void fini_thread_list(thread_array_t         thread_list,
 132                             mach_msg_type_number_t thread_count)
 133{
 134    unsigned int i;
 135    for (i = 0; i < thread_count; i++) {
 136        mach_port_deallocate(mach_task_self(), thread_list[i]);
 137    }
 138    vm_deallocate(mach_task_self(), (vm_address_t)thread_list,
 139                  thread_count * sizeof(thread_act_t));
 140}
 141
 142static int init_port_list(task_t                  the_task,
 143                          mach_port_name_array_t *name_list,
 144                          mach_msg_type_number_t *name_count,
 145                          mach_port_type_array_t *type_list,
 146                          mach_msg_type_number_t *type_count)
 147{
 148    return mach_port_names(the_task,
 149                           name_list, name_count, type_list, type_count);
 150}
 151
 152static void fini_port_list(mach_port_name_array_t name_list,
 153                           mach_msg_type_number_t name_count,
 154                           mach_port_type_array_t type_list,
 155                           mach_msg_type_number_t type_count)
 156{
 157    vm_deallocate(mach_task_self(), (vm_address_t)name_list,
 158                  name_count * sizeof(mach_port_name_t));
 159    vm_deallocate(mach_task_self(), (vm_address_t)type_list,
 160                  type_count * sizeof(mach_port_type_t));
 161}
 162                           
 163
 164#define DECL_PORT_LIST() \
 165    mach_port_name_array_t name_list;  \
 166    mach_msg_type_number_t name_count; \
 167    mach_port_type_array_t type_list;  \
 168    mach_msg_type_number_t type_count;
 169#define INIT_PORT_LIST(the_task) \
 170    if (init_port_list(the_task, &name_list, &name_count, &type_list, &type_count) != 0) { \
 171        return -EIO; \
 172    }
 173#define FINI_PORT_LIST() \
 174    fini_port_list(name_list, name_count, type_list, type_count)
 175
 176#define DECL_TASK_LIST() \
 177    task_array_t           task_list; \
 178    mach_msg_type_number_t task_count;
 179#define INIT_TASK_LIST() \
 180    if (init_task_list(&task_list, &task_count) != 0) { return -EIO; }
 181#define FINI_TASK_LIST() \
 182    fini_task_list(task_list, task_count)
 183
 184#define DECL_THREAD_LIST() \
 185    thread_array_t         thread_list; \
 186    mach_msg_type_number_t thread_count;
 187#define INIT_THREAD_LIST(the_task) \
 188    if (init_thread_list(the_task, &thread_list, &thread_count) != 0) { \
 189        return -EIO; \
 190    }
 191#define FINI_THREAD_LIST() \
 192    fini_thread_list(thread_list, thread_count)
 193
 194struct procfs_dispatcher_entry;
 195typedef struct procfs_dispatcher_entry * procfs_dispatcher_entry_t;
 196
 197typedef int (*procfs_open_handler_t)(procfs_dispatcher_entry_t  e,
 198                                     const char                *argv[],
 199                                     const char                *path,
 200                                     struct fuse_file_info     *fi);
 201
 202typedef int (*procfs_release_handler_t)(procfs_dispatcher_entry_t  e,
 203                                        const char                *argv[],
 204                                        const char                *path,
 205                                        struct fuse_file_info     *fi);
 206typedef int (*procfs_opendir_handler_t)(procfs_dispatcher_entry_t  e,
 207                                        const char                *argv[],
 208                                        const char                *path,
 209                                        struct fuse_file_info     *fi);
 210
 211typedef int (*procfs_releasedir_handler_t)(procfs_dispatcher_entry_t  e,
 212                                           const char                *argv[],
 213                                           const char                *path,
 214                                           struct fuse_file_info     *fi);
 215
 216typedef int (*procfs_getattr_handler_t)(procfs_dispatcher_entry_t  e,
 217                                        const char                *argv[],
 218                                        struct stat               *stbuf);
 219
 220typedef int (*procfs_read_handler_t)(procfs_dispatcher_entry_t  e,
 221                                     const char                *argv[],
 222                                     char                      *buf,
 223                                     size_t                     size,
 224                                     off_t                      offset,
 225                                     struct fuse_file_info     *fi);
 226
 227typedef int (*procfs_readdir_handler_t)(procfs_dispatcher_entry_t  e,
 228                                        const char                *argv[],
 229                                        void                      *buf,
 230                                        fuse_fill_dir_t            filler,
 231                                        off_t                      offset,
 232                                        struct fuse_file_info     *fi);
 233
 234typedef int (*procfs_readlink_handler_t)(procfs_dispatcher_entry_t  e,
 235                                         const char                *argv[],
 236                                         char                      *buf,
 237                                         size_t                    size);
 238
 239typedef struct procfs_dispatcher_entry {
 240    int                         flag;
 241    char                       *pattern;
 242    pcrecpp::RE                *compiled_pattern;
 243    int                         argc;
 244    procfs_open_handler_t       open;
 245    procfs_release_handler_t    release;
 246    procfs_opendir_handler_t    opendir;
 247    procfs_releasedir_handler_t releasedir;
 248    procfs_getattr_handler_t    getattr;
 249    procfs_read_handler_t       read;
 250    procfs_readdir_handler_t    readdir;
 251    procfs_readlink_handler_t   readlink;
 252    const char                 *content_files[32];
 253    const char                 *content_directories[32];
 254};
 255
 256/* flags */
 257#define PROCFS_FLAG_ISDOTFILE 0x00000001
 258
 259#define PROCFS_MAX_ARGS       3
 260
 261#define OPEN_HANDLER(handler) \
 262int \
 263procfs_open_##handler(procfs_dispatcher_entry_t  e,      \
 264                      const char                *argv[], \
 265                      const char                *path,   \
 266                      struct fuse_file_info     *fi)     \
 267
 268#define RELEASE_HANDLER(handler) \
 269int \
 270procfs_release_##handler(procfs_dispatcher_entry_t  e,      \
 271                         const char                 *argv[], \
 272                         const char                 *path,   \
 273                         struct fuse_file_info      *fi)     \
 274
 275#define OPENDIR_HANDLER(handler) \
 276int \
 277procfs_opendir_##handler(procfs_dispatcher_entry_t  e,      \
 278                         const char                *argv[], \
 279                         const char                *path,   \
 280                         struct fuse_file_info     *fi)     \
 281
 282#define RELEASEDIR_HANDLER(handler) \
 283int \
 284procfs_releasedir_##handler(procfs_dispatcher_entry_t  e,      \
 285                            const char                 *argv[], \
 286                            const char                 *path,   \
 287                            struct fuse_file_info      *fi)     \
 288
 289#define GETATTR_HANDLER(handler) \
 290int \
 291procfs_getattr_##handler(procfs_dispatcher_entry_t  e,      \
 292                         const char                *argv[], \
 293                         struct stat               *stbuf)  \
 294
 295#define READ_HANDLER(handler) \
 296int \
 297procfs_read_##handler(procfs_dispatcher_entry_t  e,      \
 298                      const char                *argv[], \
 299                      char                      *buf,    \
 300                      size_t                     size,   \
 301                      off_t                      offset, \
 302                      struct fuse_file_info     *fi)     \
 303
 304#define READDIR_HANDLER(handler) \
 305int \
 306procfs_readdir_##handler(procfs_dispatcher_entry_t  e,      \
 307                         const char                *argv[], \
 308                         void                      *buf,    \
 309                         fuse_fill_dir_t            filler, \
 310                         off_t                      offset, \
 311                         struct fuse_file_info     *fi)     \
 312
 313#define READLINK_HANDLER(handler) \
 314int \
 315procfs_readlink_##handler(procfs_dispatcher_entry_t  e,      \
 316                          const char                *argv[], \
 317                          char                      *buf,    \
 318                          size_t                     size)   \
 319
 320#define PROTO_OPEN_HANDLER(handler)       OPEN_HANDLER(handler)
 321#define PROTO_RELEASE_HANDLER(handler)    RELEASE_HANDLER(handler)
 322#define PROTO_OPENDIR_HANDLER(handler)    OPENDIR_HANDLER(handler)
 323#define PROTO_RELEASEDIR_HANDLER(handler) RELEASEDIR_HANDLER(handler)
 324#define PROTO_READ_HANDLER(handler)       READ_HANDLER(handler)
 325#define PROTO_READDIR_HANDLER(handler)    READDIR_HANDLER(handler)
 326#define PROTO_READLINK_HANDLER(handler)   READLINK_HANDLER(handler)
 327#define PROTO_GETATTR_HANDLER(handler)    GETATTR_HANDLER(handler)
 328
 329#define DECL_FILE(pattern, argc, openp, releasep, getattrp, readp) \
 330    {                                        \
 331        0,                                   \
 332        pattern,                             \
 333        new pcrecpp::RE(pattern),            \
 334        argc,                                \
 335        procfs_open_##openp,                 \
 336        procfs_release_##releasep,           \
 337        procfs_opendir_enotdir,              \
 338        procfs_releasedir_enotdir,           \
 339        procfs_getattr_##getattrp,           \
 340        procfs_read_##readp,                 \
 341        procfs_readdir_enotdir,              \
 342        procfs_readlink_einval,              \
 343        { NULL },                            \
 344        { NULL }                             \
 345    },
 346
 347#define DECL_FILE_WITHFLAGS(flag, pattern, argc, openp, releasep, getattrp, readp) \
 348    {                                        \
 349        flag,                                \
 350        pattern,                             \
 351        new pcrecpp::RE(pattern),            \
 352        argc,                                \
 353        procfs_open_##openp,                 \
 354        procfs_release_##releasep,           \
 355        procfs_opendir_enotdir,              \
 356        procfs_releasedir_enotdir,           \
 357        procfs_getattr_##getattrp,           \
 358        procfs_read_##readp,                 \
 359        procfs_readdir_enotdir,              \
 360        procfs_readlink_einval,              \
 361        { NULL },                            \
 362        { NULL }                             \
 363    },
 364
 365#define DECL_DIRECTORY(pattern, argc, opendirp, releasedirp, getattrp, readdirp, contents, ...) \
 366    {                                        \
 367        0,                                   \
 368        pattern,                             \
 369        new pcrecpp::RE(pattern),            \
 370        argc,                                \
 371        procfs_open_eisdir,                  \
 372        procfs_release_eisdir,               \
 373        procfs_opendir_##opendirp,           \
 374        procfs_releasedir_##releasedirp,     \
 375        procfs_getattr_##getattrp,           \
 376        procfs_read_eisdir,                  \
 377        procfs_readdir_##readdirp,           \
 378        procfs_readlink_einval,              \
 379        contents,                            \
 380        __VA_ARGS__                          \
 381    },
 382
 383#define DECL_DIRECTORY_COMPACT(pattern, contents, ...) \
 384    {                                        \
 385        0,                                   \
 386        pattern,                             \
 387        new pcrecpp::RE(pattern),            \
 388        0,                                   \
 389        procfs_open_eisdir,                  \
 390        procfs_release_eisdir,               \
 391        procfs_opendir_default_directory,    \
 392        procfs_releasedir_default_directory, \
 393        procfs_getattr_default_directory,    \
 394        procfs_read_eisdir,                  \
 395        procfs_readdir_default,              \
 396        procfs_readlink_einval,              \
 397        contents,                            \
 398        ##__VA_ARGS__                        \
 399    },
 400
 401#define DECL_LINK(pattern, argc, openp, releasep, getattrp, readlinkp) \
 402    {                                        \
 403        0,                                   \
 404        pattern,                             \
 405        new pcrecpp::RE(pattern),            \
 406        argc,                                \
 407        procfs_open_##openp,                 \
 408        procfs_release_##releasep,           \
 409        procfs_opendir_enotdir,              \
 410        procfs_releasedir_enotdir,           \
 411        procfs_getattr_##getattrp,           \
 412        procfs_read_einval,                  \
 413        procfs_readdir_enotdir,              \
 414        procfs_readlink_##readlinkp,         \
 415        { NULL },                            \
 416        { NULL }                             \
 417    },
 418
 419#define DECL_LINK_COMPACT(pattern, argc, readlinkp) \
 420    {                                        \
 421        0,                                   \
 422        pattern,                             \
 423        new pcrecpp::RE(pattern),            \
 424        argc,                                \
 425        procfs_open_default_file,            \
 426        procfs_release_default_file,         \
 427        procfs_opendir_enotdir,              \
 428        procfs_releasedir_enotdir,           \
 429        procfs_getattr_default_link,         \
 430        procfs_read_einval,                  \
 431        procfs_readdir_enotdir,              \
 432        procfs_readlink_##readlinkp,         \
 433        { NULL },                            \
 434        { NULL }                             \
 435    },
 436
 437PROTO_OPEN_HANDLER(default_file);
 438PROTO_OPEN_HANDLER(eisdir);
 439PROTO_OPEN_HANDLER(proc__windows__identify);
 440PROTO_OPEN_HANDLER(proc__windows__screenshots__window);
 441PROTO_OPEN_HANDLER(system__hardware__camera__screenshot);
 442PROTO_OPEN_HANDLER(system__hardware__displays__display__screenshot);
 443
 444PROTO_RELEASE_HANDLER(default_file);
 445PROTO_RELEASE_HANDLER(eisdir);
 446PROTO_RELEASE_HANDLER(proc__windows__identify);
 447PROTO_RELEASE_HANDLER(proc__windows__screenshots__window);
 448PROTO_RELEASE_HANDLER(system__hardware__camera__screenshot);
 449PROTO_RELEASE_HANDLER(system__hardware__displays__display__screenshot);
 450
 451PROTO_OPENDIR_HANDLER(default_directory);
 452PROTO_OPENDIR_HANDLER(enotdir);
 453
 454PROTO_RELEASEDIR_HANDLER(default_directory);
 455PROTO_RELEASEDIR_HANDLER(enotdir);
 456
 457PROTO_GETATTR_HANDLER(default_file);
 458PROTO_GETATTR_HANDLER(default_file_finder_info);
 459PROTO_GETATTR_HANDLER(default_directory);
 460PROTO_GETATTR_HANDLER(default_link);
 461PROTO_GETATTR_HANDLER(byname__name);
 462PROTO_GETATTR_HANDLER(system__hardware__camera__screenshot);
 463PROTO_GETATTR_HANDLER(system__hardware__displays__display);
 464PROTO_GETATTR_HANDLER(system__hardware__displays__display__screenshot);
 465#if MACFUSE_PROCFS_ENABLE_TPM
 466PROTO_GETATTR_HANDLER(system__hardware__tpm__keyslots__slot);
 467PROTO_GETATTR_HANDLER(system__hardware__tpm__pcrs__pcr);
 468#endif /* MACFUSE_PROCFS_ENABLE_TPM */
 469PROTO_GETATTR_HANDLER(proc__task__ports__port);
 470PROTO_GETATTR_HANDLER(proc__task__threads__thread);
 471PROTO_GETATTR_HANDLER(proc__windows__screenshots__window);
 472
 473PROTO_READ_HANDLER(einval);
 474PROTO_READ_HANDLER(eisdir);
 475PROTO_READ_HANDLER(zero);
 476PROTO_READ_HANDLER(default_file_finder_info);
 477PROTO_READ_HANDLER(proc__carbon);
 478#if __i386__
 479PROTO_READ_HANDLER(proc__fds);
 480#endif /* __i386__ */
 481PROTO_READ_HANDLER(proc__generic);
 482PROTO_READ_HANDLER(proc__task__absolutetime_info);
 483PROTO_READ_HANDLER(proc__task__basic_info);
 484PROTO_READ_HANDLER(proc__task__events_info);
 485PROTO_READ_HANDLER(proc__task__thread_times_info);
 486PROTO_READ_HANDLER(proc__task__mach_name);
 487PROTO_READ_HANDLER(proc__task__ports__port);
 488PROTO_READ_HANDLER(proc__task__role);
 489PROTO_READ_HANDLER(proc__task__threads__thread__basic_info);
 490PROTO_READ_HANDLER(proc__task__threads__thread__states__debug);
 491PROTO_READ_HANDLER(proc__task__threads__thread__states__exception);
 492PROTO_READ_HANDLER(proc__task__threads__thread__states__float);
 493PROTO_READ_HANDLER(proc__task__threads__thread__states__thread);
 494PROTO_READ_HANDLER(proc__task__tokens);
 495PROTO_READ_HANDLER(proc__task__vmmap);
 496PROTO_READ_HANDLER(proc__task__vmmap_r);
 497PROTO_READ_HANDLER(proc__windows__generic);
 498PROTO_READ_HANDLER(proc__windows__screenshots__window);
 499PROTO_READ_HANDLER(proc__xcred);
 500PROTO_READ_HANDLER(system__firmware__variables);
 501PROTO_READ_HANDLER(system__hardware__camera__screenshot);
 502PROTO_READ_HANDLER(system__hardware__cpus__cpu__data);
 503PROTO_READ_HANDLER(system__hardware__displays__display__info);
 504PROTO_READ_HANDLER(system__hardware__displays__display__screenshot);
 505#if MACFUSE_PROCFS_ENABLE_TPM
 506PROTO_READ_HANDLER(system__hardware__tpm__hwmodel);
 507PROTO_READ_HANDLER(system__hardware__tpm__hwvendor);
 508PROTO_READ_HANDLER(system__hardware__tpm__hwversion);
 509PROTO_READ_HANDLER(system__hardware__tpm__keyslots__slot);
 510PROTO_READ_HANDLER(system__hardware__tpm__pcrs__pcr);
 511#endif /* MACFUSE_PROCFS_ENABLE_TPM */
 512PROTO_READ_HANDLER(system__hardware__xsensor);
 513
 514PROTO_READDIR_HANDLER(default);
 515PROTO_READDIR_HANDLER(enotdir);
 516PROTO_READDIR_HANDLER(byname);
 517PROTO_READDIR_HANDLER(proc__task__ports);
 518PROTO_READDIR_HANDLER(proc__task__threads);
 519PROTO_READDIR_HANDLER(proc__windows__screenshots);
 520PROTO_READDIR_HANDLER(root);
 521PROTO_READDIR_HANDLER(system__hardware__cpus);
 522PROTO_READDIR_HANDLER(system__hardware__cpus__cpu);
 523PROTO_READDIR_HANDLER(system__hardware__displays);
 524PROTO_READDIR_HANDLER(system__hardware__displays__display);
 525#if MACFUSE_PROCFS_ENABLE_TPM
 526PROTO_READDIR_HANDLER(system__hardware__tpm__keyslots);
 527PROTO_READDIR_HANDLER(system__hardware__tpm__pcrs);
 528#endif /* MACFUSE_PROCFS_ENABLE_TPM */
 529
 530PROTO_READLINK_HANDLER(einval);
 531PROTO_READLINK_HANDLER(byname__name);
 532
 533static struct procfs_dispatcher_entry
 534procfs_link_table[] = {
 535
 536    DECL_LINK(
 537        "/byname/(.+)",
 538        1,
 539        default_file,
 540        default_file,
 541        byname__name,
 542        byname__name
 543    )
 544};
 545
 546static struct procfs_dispatcher_entry
 547procfs_file_table[] = {
 548
 549    DECL_FILE_WITHFLAGS(
 550        PROCFS_FLAG_ISDOTFILE,
 551        "/system/.*\\._.*|/\\d+/.*\\._.*",
 552        0,
 553        default_file,
 554        default_file,
 555        default_file_finder_info,
 556        default_file_finder_info
 557    )
 558
 559    DECL_FILE(
 560        "/system/firmware/variables",
 561        0,
 562        default_file,
 563        default_file,
 564        default_file,
 565        system__firmware__variables
 566    )
 567
 568    DECL_FILE(
 569        "/system/hardware/(lightsensor|motionsensor|mouse)/data",
 570        1,
 571        default_file,
 572        default_file,
 573        default_file,
 574        system__hardware__xsensor
 575    )
 576
 577    DECL_FILE(
 578        "/system/hardware/camera/screenshot.tiff",
 579        0,
 580        system__hardware__camera__screenshot,
 581        system__hardware__camera__screenshot,
 582        system__hardware__camera__screenshot,
 583        system__hardware__camera__screenshot
 584    )
 585
 586    DECL_FILE(
 587        "/system/hardware/cpus/(\\d+)/data",
 588        1,
 589        default_file,
 590        default_file,
 591        default_file,
 592        system__hardware__cpus__cpu__data
 593    )
 594
 595    DECL_FILE(
 596        "/system/hardware/displays/(\\d+)/info",
 597        1,
 598        default_file,
 599        default_file,
 600        default_file,
 601        system__hardware__displays__display__info
 602    )
 603
 604    DECL_FILE(
 605        "/system/hardware/displays/(\\d+)/screenshot.png",
 606        1,
 607        system__hardware__displays__display__screenshot,
 608        system__hardware__displays__display__screenshot,
 609        system__hardware__displays__display__screenshot,
 610        system__hardware__displays__display__screenshot
 611    )
 612
 613#if MACFUSE_PROCFS_ENABLE_TPM
 614    DECL_FILE(
 615        "/system/hardware/tpm/hwmodel",
 616        0,
 617        default_file,
 618        default_file,
 619        default_file,
 620        system__hardware__tpm__hwmodel
 621    )
 622
 623    DECL_FILE(
 624        "/system/hardware/tpm/hwvendor",
 625        0,
 626        default_file,
 627        default_file,
 628        default_file,
 629        system__hardware__tpm__hwvendor
 630    )
 631
 632    DECL_FILE(
 633        "/system/hardware/tpm/hwversion",
 634        0,
 635        default_file,
 636        default_file,
 637        default_file,
 638        system__hardware__tpm__hwversion
 639    )
 640
 641    DECL_FILE(
 642        "/system/hardware/tpm/keyslots/key(\\d+)",
 643        1,
 644        default_file,
 645        default_file,
 646        system__hardware__tpm__keyslots__slot,
 647        system__hardware__tpm__keyslots__slot
 648    )
 649
 650    DECL_FILE(
 651        "/system/hardware/tpm/pcrs/pcr(\\d+)",
 652        1,
 653        default_file,
 654        default_file,
 655        system__hardware__tpm__pcrs__pcr,
 656        system__hardware__tpm__pcrs__pcr
 657    )
 658#endif /* MACFUSE_PROCFS_ENABLE_TPM */
 659
 660    DECL_FILE(
 661        "/(\\d+)/carbon/(name|psn)",
 662        2,
 663        default_file,
 664        default_file,
 665        default_file,
 666        proc__carbon
 667    )
 668
 669#if __i386__
 670    DECL_FILE(
 671        "/(\\d+)/fds",
 672        1,
 673        default_file,
 674        default_file,
 675        default_file,
 676        proc__fds
 677    )
 678#endif /* __i386__ */
 679
 680    DECL_FILE(
 681        "/(\\d+)/(cmdline|jobc|paddr|pgid|ppid|tdev|tpgid|wchan)",
 682        2,
 683        default_file,
 684        default_file,
 685        default_file,
 686        proc__generic
 687    )
 688
 689    DECL_FILE(
 690        "/(\\d+)/task/absolutetime_info/(threads_system|threads_user|total_system|total_user)",
 691        2,
 692        default_file,
 693        default_file,
 694        default_file,
 695        proc__task__absolutetime_info
 696    )
 697
 698    DECL_FILE(
 699        "/(\\d+)/task/basic_info/(policy|resident_size|suspend_count|system_time|user_time|virtual_size)",
 700        2,
 701        default_file,
 702        default_file,
 703        default_file,
 704        proc__task__basic_info
 705    )
 706
 707    DECL_FILE(
 708        "/(\\d+)/task/events_info/(cow_faults|csw|faults|messages_received|messages_sent|pageins|syscalls_mach|syscalls_unix)",
 709        2,
 710        default_file,
 711        default_file,
 712        default_file,
 713        proc__task__events_info
 714    )
 715
 716    DECL_FILE(
 717        "/(\\d+)/task/thread_times_info/(system_time|user_time)",
 718        2,
 719        default_file,
 720        default_file,
 721        default_file,
 722        proc__task__thread_times_info
 723    )
 724
 725    DECL_FILE(
 726        "/(\\d+)/task/mach_name",
 727        1,
 728        default_file,
 729        default_file,
 730        default_file,
 731        proc__task__mach_name
 732    )
 733
 734    DECL_FILE(
 735        "/(\\d+)/task/ports/([a-f\\d]+)/(msgcount|qlimit|seqno|sorights|task_rights)",
 736        3,
 737        default_file,
 738        default_file,
 739        default_file,
 740        proc__task__ports__port
 741    )
 742
 743    DECL_FILE(
 744        "/(\\d+)/task/role",
 745        1,
 746        default_file,
 747        default_file,
 748        default_file,
 749        proc__task__role
 750    )
 751
 752    DECL_FILE(
 753        "/(\\d+)/task/threads/([a-f\\d]+)/basic_info/(cpu_usage|flags|policy|run_state|sleep_time|suspend_count|system_time|user_time)",
 754        3,
 755        default_file,
 756        default_file,
 757        default_file,
 758        proc__task__threads__thread__basic_info
 759    )
 760
 761    DECL_FILE(
 762        "/(\\d+)/task/threads/([a-f\\d]+)/states/debug/(dr[0-7])",
 763        3,
 764        default_file,
 765        default_file,
 766        default_file,
 767        proc__task__threads__thread__states__debug
 768    )
 769
 770    DECL_FILE(
 771        "/(\\d+)/task/threads/([a-f\\d]+)/states/exception/(err|faultvaddr|trapno)",
 772        3,
 773        default_file,
 774        default_file,
 775        default_file,
 776        proc__task__threads__thread__states__exception
 777    )
 778
 779    DECL_FILE(
 780        "/(\\d+)/task/threads/([a-f\\d]+)/states/float/(fpu_fcw|fpu_fsw|fpu_ftw|fpu_fop|fpu_ip|fpu_cs|fpu_dp|fpu_ds|fpu_mxcsr|fpu_mxcsrmask)",
 781        3,
 782        default_file,
 783        default_file,
 784        default_file,
 785        proc__task__threads__thread__states__float
 786    )
 787
 788    DECL_FILE(
 789        "/(\\d+)/task/threads/([a-f\\d]+)/states/thread/(e[a-d]x|edi|esi|ebp|esp|ss|eflags|eip|[cdefg]s)",
 790        3,
 791        default_file,
 792        default_file,
 793        default_file,
 794        proc__task__threads__thread__states__thread
 795    )
 796
 797    DECL_FILE(
 798        "/(\\d+)/task/tokens/(audit|security)",
 799        2,
 800        default_file,
 801        default_file,
 802        default_file,
 803        proc__task__tokens
 804    )
 805
 806    DECL_FILE(
 807        "/(\\d+)/task/vmmap",
 808        1,
 809        default_file,
 810        default_file,
 811        default_file,
 812        proc__task__vmmap
 813    )
 814
 815    DECL_FILE(
 816        "/(\\d+)/task/vmmap_r",
 817        1,
 818        default_file,
 819        default_file,
 820        default_file,
 821        proc__task__vmmap_r
 822    )
 823
 824    DECL_FILE(
 825        "/(\\d+)/windows/(all|onscreen)",
 826        2,
 827        default_file,
 828        default_file,
 829        default_file,
 830        proc__windows__generic
 831    )
 832
 833    DECL_FILE(
 834        "/(\\d+)/windows/identify",
 835        1,
 836        proc__windows__identify,
 837        proc__windows__identify,
 838        default_file,
 839        zero
 840    )
 841
 842    DECL_FILE(
 843        "/(\\d+)/windows/screenshots/([a-f\\d]+).png",
 844        2,
 845        proc__windows__screenshots__window, 
 846        proc__windows__screenshots__window, 
 847        proc__windows__screenshots__window,
 848        proc__windows__screenshots__window
 849    )
 850
 851    DECL_FILE(
 852        "/(\\d+)/(ucred|pcred)/(groups|rgid|ruid|svgid|svuid|uid)",
 853        3,
 854        default_file,
 855        default_file,
 856        default_file,
 857        proc__xcred
 858    )
 859};
 860
 861static struct procfs_dispatcher_entry
 862procfs_directory_table[] = {
 863    DECL_DIRECTORY(
 864        "/",
 865        0,
 866        default_directory,
 867        default_directory,
 868        default_directory,
 869        root,
 870        { NULL },
 871        { "byname", "system", NULL }
 872    )
 873
 874    DECL_DIRECTORY(
 875        "/byname",
 876        0,
 877        default_directory,
 878        default_directory,
 879        default_directory,
 880        byname,
 881        { NULL },
 882        { NULL }
 883    )
 884
 885    DECL_DIRECTORY_COMPACT(
 886        "/system",
 887        { NULL },
 888        { "firmware", "hardware", NULL },
 889    )
 890
 891    DECL_DIRECTORY_COMPACT(
 892        "/system/firmware",
 893        { "variables", NULL },
 894        { NULL }
 895    )
 896
 897    DECL_DIRECTORY_COMPACT(
 898        "/system/hardware",
 899        { NULL },
 900#if MACFUSE_PROCFS_ENABLE_TPM
 901        {
 902            "camera", "cpus", "displays", "lightsensor", "motionsensor",
 903             "mouse", "tpm", NULL
 904        }
 905#else
 906        {
 907            "camera", "cpus", "displays", "lightsensor", "motionsensor",
 908            "mouse", NULL
 909        }
 910#endif /* MACFUSE_PROCFS_ENABLE_TPM */
 911    )
 912
 913    DECL_DIRECTORY_COMPACT(
 914        "/system/hardware/camera",
 915        { "screenshot.tiff", NULL },
 916        { NULL },
 917    )
 918
 919    DECL_DIRECTORY(
 920        "/system/hardware/cpus",
 921        0,
 922        default_directory,
 923        default_directory,
 924        default_directory,
 925        system__hardware__cpus,
 926        { NULL },
 927        { NULL },
 928    )
 929
 930    DECL_DIRECTORY(
 931        "/system/hardware/cpus/(\\d+)",
 932        1,
 933        default_directory,
 934        default_directory,
 935        default_directory,
 936        system__hardware__cpus__cpu,
 937        { "data", NULL },
 938        { NULL },
 939    )
 940
 941    DECL_DIRECTORY(
 942        "/system/hardware/displays",
 943        0,
 944        default_directory,
 945        default_directory,
 946        default_directory,
 947        system__hardware__displays,
 948        { NULL },
 949        { NULL },
 950    )
 951
 952    DECL_DIRECTORY(
 953        "/system/hardware/displays/(\\d+)",
 954        1,
 955        default_directory,
 956        default_directory,
 957        system__hardware__displays__display,
 958        system__hardware__displays__display,
 959        { "info", "screenshot.png", NULL },
 960        { NULL },
 961    )
 962
 963    DECL_DIRECTORY_COMPACT(
 964        "/system/hardware/lightsensor",
 965        { "data", NULL },
 966        { NULL },
 967    )
 968
 969    DECL_DIRECTORY_COMPACT(
 970        "/system/hardware/motionsensor",
 971        { "data", NULL },
 972        { NULL },
 973    )
 974
 975    DECL_DIRECTORY_COMPACT(
 976        "/system/hardware/mouse",
 977        { "data", NULL },
 978        { NULL },
 979    )
 980
 981#if MACFUSE_PROCFS_ENABLE_TPM
 982    DECL_DIRECTORY_COMPACT(
 983        "/system/hardware/tpm",
 984        { "hwmodel", "hwvendor", "hwversion", NULL },
 985        { "keyslots", "pcrs" }
 986    )
 987
 988    DECL_DIRECTORY(
 989        "/system/hardware/tpm/keyslots",
 990        0,
 991        default_directory,
 992        default_directory,
 993        default_directory,
 994        system__hardware__tpm__keyslots,
 995        { NULL },
 996        { NULL },
 997    )
 998
 999    DECL_DIRECTORY(
1000        "/system/hardware/tpm/pcrs",
1001        0,
1002        default_directory,
1003        default_directory,
1004        default_directory,
1005        system__hardware__tpm__pcrs,
1006        { NULL },
1007        { NULL },
1008    )
1009#endif /* MACFUSE_PROCFS_ENABLE_TPM */
1010
1011    DECL_DIRECTORY_COMPACT(
1012        "/\\d+",
1013        {
1014            "cmdline",
1015#if __i386__
1016            "fds",
1017#endif /* __i386__ */
1018            "jobc", "paddr", "pgid", "ppid", "tdev", "tpgid",
1019            "wchan", "windows", NULL
1020        },
1021        { "carbon", "pcred", "task", "ucred", NULL }
1022    )
1023
1024    DECL_DIRECTORY_COMPACT(
1025        "/\\d+/carbon",
1026        { "name", "psn", NULL },
1027        { NULL }
1028    )
1029
1030    DECL_DIRECTORY_COMPACT(
1031        "/\\d+/pcred",
1032        { "rgid", "ruid", "svgid", "svgid", NULL },
1033        { NULL }
1034    )
1035
1036    DECL_DIRECTORY_COMPACT(
1037        "/\\d+/task",
1038        { "mach_name", "role", "vmmap", "vmmap_r", NULL },
1039        {
1040            "absolutetime_info", "basic_info", "events_info", "ports",
1041            "thread_times_info", "threads", "tokens", NULL
1042        }
1043    )
1044
1045    DECL_DIRECTORY_COMPACT(
1046        "/\\d+/task/absolutetime_info",
1047        {
1048            "threads_system", "threads_user", "total_system",
1049            "total_user", NULL
1050        },
1051        { NULL }
1052    )
1053
1054    DECL_DIRECTORY_COMPACT(
1055        "/\\d+/task/basic_info",
1056        {
1057            "policy", "resident_size", "suspend_count", "system_time",
1058            "user_time", "virtual_size", NULL
1059        },
1060        { NULL }
1061    )
1062
1063    DECL_DIRECTORY_COMPACT(
1064        "/\\d+/task/events_info",
1065        {
1066            "cow_faults", "csw", "faults", "messages_received",
1067            "messages_sent", "pageins", "syscalls_mach", "syscalls_unix", NULL
1068        },
1069        { NULL }
1070    )
1071
1072    DECL_DIRECTORY(
1073        "/(\\d+)/task/ports",
1074        1,
1075        default_directory,
1076        default_directory,
1077        default_directory,
1078        proc__task__ports,
1079        { NULL },
1080        { NULL }
1081    )
1082
1083    DECL_DIRECTORY(
1084        "/(\\d+)/task/ports/([a-f\\d]+)",
1085        2,
1086        default_directory,
1087        default_directory,
1088        proc__task__ports__port,
1089        default,
1090        { "msgcount", "qlimit", "seqno", "sorights", "task_rights", NULL },
1091        { NULL }
1092    )
1093
1094    DECL_DIRECTORY_COMPACT(
1095        "/\\d+/task/thread_times_info",
1096        { "system_time", "user_time", NULL },
1097        { NULL }
1098    )
1099
1100    DECL_DIRECTORY(
1101        "/(\\d+)/task/threads",
1102        1,
1103        default_directory,
1104        default_directory,
1105        default_directory,
1106        proc__task__threads,
1107        { NULL },
1108        { NULL }
1109    )
1110
1111    DECL_DIRECTORY(
1112        "/(\\d+)/task/threads/([a-f\\d])+",
1113        2,
1114        default_directory,
1115        default_directory,
1116        proc__task__threads__thread,
1117        default,
1118        { NULL },
1119        { "basic_info", "states", NULL }
1120    )
1121
1122    DECL_DIRECTORY_COMPACT(
1123        "/\\d+/task/threads/[a-f\\d]+/basic_info",
1124        {
1125            "cpu_usage", "flags", "policy", "run_state", "sleep_time",
1126            "suspend_count", "system_time", "user_time", NULL
1127        },
1128        { NULL }
1129    )
1130
1131    DECL_DIRECTORY_COMPACT(
1132        "/\\d+/task/threads/[a-f\\d]+/states",
1133        { "debug", "exception", "float", "thread", NULL },
1134        { NULL }
1135    )
1136
1137    DECL_DIRECTORY_COMPACT(
1138        "/\\d+/task/threads/[a-f\\d]+/states/debug",
1139        { "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", NULL },
1140        { NULL }
1141    )
1142
1143    DECL_DIRECTORY_COMPACT(
1144        "/\\d+/task/threads/[a-f\\d]+/states/exception",
1145        { "err", "faultvaddr", "trapno", NULL },
1146        { NULL }
1147    )
1148
1149    DECL_DIRECTORY_COMPACT(
1150        "/\\d+/task/threads/[a-f\\d]+/states/float",
1151        {
1152            "fpu_cs", "fpu_dp", "fpu_ds", "fpu_fcw", "fpu_fop", "fpu_fsw",
1153            "fpu_ftw", "fpu_ip", "fpu_mxcsr", "fpu_mxcsrmask", NULL
1154        },
1155        { NULL }
1156    )
1157
1158    DECL_DIRECTORY_COMPACT(
1159        "/\\d+/task/threads/[a-f\\d]+/states/thread",
1160        {
1161            "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp", "ss",
1162            "eflags", "eip", "cs", "ds", "es", "fs", "gs", NULL
1163        },
1164        { NULL }
1165    )
1166
1167    DECL_DIRECTORY_COMPACT(
1168        "/\\d+/task/tokens",
1169        { "audit", "security", NULL },
1170        { NULL }
1171    )
1172
1173    DECL_DIRECTORY_COMPACT(
1174        "/\\d+/ucred",
1175        { "groups", "uid", NULL },
1176        { NULL }
1177    )
1178
1179    DECL_DIRECTORY_COMPACT(
1180        "/\\d+/windows",
1181        { "all", "onscreen", "identify", NULL },
1182        { "screenshots", NULL }
1183    )
1184
1185    DECL_DIRECTORY(
1186        "/(\\d+)/windows/screenshots",
1187        1,
1188        default_directory,
1189        default_directory,
1190        default_directory,
1191        proc__windows__screenshots,
1192        { NULL },
1193        { NULL },
1194    )
1195
1196};
1197
1198// BEGIN: OPEN/OPENDIR
1199
1200//
1201// int
1202// procfs_open/opendir_<handler>(procfs_dispatcher_entry_t  e,
1203//                               const char                *argv[],
1204//                               const char                *path,
1205//                               struct fuse_file_info     *fi)
1206
1207OPEN_HANDLER(default_file)
1208{
1209    return 0;
1210}
1211
1212OPEN_HANDLER(eisdir)
1213{
1214    return -EISDIR;
1215}
1216
1217OPEN_HANDLER(proc__windows__identify)
1218{
1219    if (fi->fh != 0) { /* XXX: need locking */
1220        return 0;
1221    } else {
1222        fi->fh = 1;
1223    }
1224    char *whandler = NULL;
1225    if ((whandler = getenv("MACFUSE_PROCFS_WHANDLER")) == NULL) {
1226        goto bail;
1227    }
1228    int npid = vfork();
1229    if (npid == 0) {
1230        execl(whandler, whandler, argv[0], NULL);
1231        return 0;
1232    }
1233
1234bail:
1235    return 0;
1236}
1237
1238OPEN_HANDLER(proc__windows__screenshots__window)
1239{
1240    if (fi->fh != 0) { /* XXX: need locking */
1241        return 0;
1242    }
1243
1244    pid_t pid = strtol(argv[0], NULL, 10);
1245    CGWindowID target = strtol(argv[1], NULL, 16);
1246    ProcessSerialNumber psn;
1247
1248    OSStatus status = GetProcessForPID(pid, &psn);
1249    if (status != noErr) {
1250        return -ENOENT;
1251    }
1252
1253    CGSConnectionID conn;
1254    CGError err = CGSGetConnectionIDForPSN(0, &psn, &conn);
1255    if (err != kCGErrorSuccess) {
1256        return -ENOENT;
1257    }
1258
1259#define MAX_WINDOWS 256
1260    CGSWindowID windowIDs[MAX_WINDOWS];
1261    int windowCount = 0;
1262    int i = 0;
1263
1264    err = CGSGetWindowList(_CGSDefaultConnection(), conn, MAX_WINDOWS,
1265                           windowIDs, &windowCount);
1266
1267    for (i = 0; i < windowCount; i++) {
1268        if (windowIDs[i] == target) {
1269            goto doread;
1270        }
1271    }
1272
1273    return -ENOENT;
1274
1275doread:
1276
1277    CFMutableDataRef window_png = (CFMutableDataRef)0;
1278    int ret = PROCFS_GetPNGForWindowAtIndex(target, &window_png);
1279
1280    if (ret == -1) {
1281        return -EIO;
1282    }
1283
1284    struct ProcfsWindowData *pwd =
1285        (struct ProcfsWindowData *)malloc(sizeof(struct ProcfsWindowData));
1286    if (!pwd) {
1287        CFRelease(window_png);
1288        return -ENOMEM;
1289    }
1290
1291    pwd->window_png = window_png;
1292    pwd->max_len = PROCFS_GetPNGSizeForWindowAtIndex(target);
1293    pwd->len = (size_t)CFDataGetLength(window_png);
1294
1295    fi->fh = (uint64_t)pwd;
1296
1297    return 0;
1298}
1299
1300OPEN_HANDLER(system__hardware__camera__screenshot)
1301{
1302    pthread_mutex_lock(&camera_lock);
1303    if (camera_busy) {
1304        pthread_mutex_unlock(&camera_lock);
1305        return -EBUSY;
1306    } else {
1307        camera_busy = 1;
1308        pthread_mutex_unlock(&camera_lock);
1309    }
1310
1311    int ret = PROCFS_GetTIFFFromCamera(&camera_tiff);
1312
1313    return ret;
1314}
1315
1316OPEN_HANDLER(system__hardware__displays__display__screenshot)
1317{
1318    pthread_mutex_lock(&display_lock);
1319    if (display_busy) {
1320        pthread_mutex_unlock(&display_lock);
1321        return -EBUSY;
1322    } else {
1323        display_busy = 1;
1324        pthread_mutex_unlock(&display_lock);
1325    }
1326
1327    unsigned long index = strtol(argv[0], NULL, 10);
1328    CGDisplayCount display_count = PROCFS_GetDisplayCount();
1329
1330    if (index >= display_count) {
1331        return -ENOENT;
1332    }
1333
1334    if (display_png) {
1335        CFRelease(display_png);
1336        display_png = (CFMutableDataRef)0;
1337    }
1338
1339    int ret = PROCFS_GetPNGForDisplayAtIndex(index, &display_png);
1340    if (ret) {
1341        if (display_png) {
1342            CFRelease(display_png);
1343            display_png = (CFMutableDataRef)0;
1344        }
1345        return -EIO;
1346    }
1347
1348    return 0;
1349}
1350
1351OPENDIR_HANDLER(default_directory)
1352{
1353    return 0;
1354}
1355
1356OPENDIR_HANDLER(enotdir)
1357{
1358    return -ENOTDIR;
1359}
1360
1361// END: OPEN/OPENDIR
1362
1363
1364// BEGIN: RELEASE/RELEASEDIR
1365
1366//
1367// int
1368// procfs_release/releasedir_<handler>(procfs_dispatcher_entry_t  e,
1369//                                     const char                *argv[],
1370//                                     const char                *path,
1371//                                     struct fuse_file_info     *fi)
1372
1373RELEASE_HANDLER(default_file)
1374{
1375    return 0;
1376}
1377
1378RELEASE_HANDLER(eisdir)
1379{
1380    return -EISDIR;
1381}
1382
1383RELEASE_HANDLER(proc__windows__identify)
1384{
1385    fi->fh = 0;
1386
1387    return 0;
1388}
1389
1390RELEASE_HANDLER(proc__windows__screenshots__window)
1391{ 
1392    if (fi->fh) {
1393        struct ProcfsWindowData *pwd = (struct ProcfsWindowData *)(fi->fh);
1394        CFRelease((CFMutableDataRef)(pwd->window_png));
1395        free((void *)pwd);
1396        fi->fh = 0;
1397    }
1398
1399    return 0;
1400}
1401
1402RELEASE_HANDLER(system__hardware__camera__screenshot)
1403{
1404    pthread_mutex_lock(&camera_lock);
1405    camera_busy = 0;
1406    pthread_mutex_unlock(&camera_lock);
1407
1408    return 0;
1409}
1410
1411RELEASE_HANDLER(system__hardware__displays__display__screenshot)
1412{
1413    pthread_mutex_lock(&display_lock);
1414    display_busy = 0;
1415    if (display_png) {
1416        CFRelease(display_png);
1417        display_png = (CFMutableDataRef)0;
1418    }
1419    pthread_mutex_unlock(&display_lock);
1420
1421    return 0;
1422}
1423
1424RELEASEDIR_HANDLER(default_directory)
1425{
1426    return 0;
1427}
1428
1429RELEASEDIR_HANDLER(enotdir)
1430{
1431    return -ENOTDIR;
1432}
1433
1434// END: RELEASE/RELEASEDIR
1435
1436
1437// BEGIN: GETATTR
1438
1439//
1440//  int
1441//  procfs_getattr_<handler>(procfs_dispatcher_entry_t  e,
1442//                           const char                *argv[],
1443//                           struct stat               *stbuf)
1444                          
1445
1446GETATTR_HANDLER(default_file)
1447{                         
1448    time_t current_time = time(NULL);
1449    stbuf->st_mode = S_IFREG | 0444;             
1450    stbuf->st_nlink = 1;  
1451    stbuf->st_size = 0;
1452    if (procfs_ui) {
1453        stbuf->st_size = PROCFS_DEFAULT_FILE_SIZE;
1454    }
1455    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1456
1457    return 0;
1458}   
1459
1460GETATTR_HANDLER(default_file_finder_info)
1461{
1462    if (!procfs_ui) {
1463        return -ENOENT;
1464    }
1465
1466    time_t current_time = time(NULL);
1467    stbuf->st_mode = S_IFREG | 0444;             
1468    stbuf->st_nlink = 1;  
1469    stbuf->st_size = 82;
1470    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1471
1472    return 0;
1473}
1474    
1475GETATTR_HANDLER(default_directory)
1476{
1477    time_t current_time = time(NULL);
1478
1479    stbuf->st_mode = S_IFDIR | 0555;
1480    stbuf->st_nlink = 1;
1481    stbuf->st_size = 0;
1482    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1483    
1484    return 0;
1485}
1486
1487GETATTR_HANDLER(default_link)
1488{
1489    stbuf->st_mode = S_IFLNK | 0755;
1490    stbuf->st_nlink = 1;
1491    stbuf->st_size = 0;
1492    
1493    return 0;
1494}
1495
1496GETATTR_HANDLER(byname__name)
1497{
1498    const char *target_Pname = argv[0];
1499    struct stat the_stat;
1500    char the_name[MAXNAMLEN + 1];  
1501    Boolean strstatus = false;
1502
1503    ProcessSerialNumber psn;
1504    OSErr osErr = noErr;
1505    OSStatus status;
1506    CFStringRef Pname;
1507    pid_t Pid;
1508
1509    psn.highLongOfPSN = kNoProcess;
1510    psn.lowLongOfPSN  = kNoProcess;
1511
1512    while ((osErr = GetNextProcess(&psn)) != procNotFound) {
1513        status = GetProcessPID(&psn, &Pid);
1514        if (status != noErr) {
1515            continue;
1516        }
1517        Pname = (CFStringRef)0;
1518        status = CopyProcessName(&psn, &Pname);
1519        if (status != noErr) {
1520            if (Pname) {
1521                CFRelease(Pname);
1522                Pname = (CFStringRef)0;
1523            }
1524            continue;
1525        }
1526
1527        strstatus = CFStringGetCString(Pname, the_name, MAXNAMLEN,
1528                                       kCFStringEncodingASCII);
1529        if (strstatus != true) {
1530            Pid = 0;
1531        } else if (strcmp(target_Pname, the_name) != 0) {
1532            Pid = 0;
1533        }
1534
1535        CFRelease(Pname);
1536        Pname = (CFStringRef)0;
1537
1538        if (Pid) {
1539            break;
1540        }
1541    }
1542
1543    if (!Pid) {
1544        return -ENOENT;
1545    }
1546
1547    time_t current_time = time(NULL);
1548    stbuf->st_mode = S_IFLNK | 0755;
1549    stbuf->st_nlink = 1;
1550    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1551    int len = snprintf(the_name, MAXNAMLEN, "../%u", Pid);
1552    the_stat.st_size = len;
1553
1554    return 0;
1555}
1556
1557GETATTR_HANDLER(system__hardware__displays__display)
1558{
1559    unsigned long index = strtol(argv[0], NULL, 10);
1560    CGDisplayCount display_count = PROCFS_GetDisplayCount();
1561
1562    if (index >= display_count) {
1563        return -ENOENT;
1564    }
1565
1566    time_t current_time = time(NULL);
1567
1568    stbuf->st_mode = S_IFDIR | 0555;
1569    stbuf->st_nlink = 1;
1570    stbuf->st_size = 0;
1571    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1572    
1573    return 0;
1574}
1575
1576GETATTR_HANDLER(system__hardware__camera__screenshot)
1577{
1578    time_t current_time = time(NULL);
1579
1580    stbuf->st_mode = S_IFREG | 0444;
1581    stbuf->st_nlink = 1;
1582    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1583    stbuf->st_size = PROCFS_GetTIFFSizeFromCamera();
1584
1585    return 0;
1586}
1587
1588GETATTR_HANDLER(system__hardware__displays__display__screenshot)
1589{
1590    unsigned long index = strtol(argv[0], NULL, 10);
1591
1592    time_t current_time = time(NULL);
1593
1594    stbuf->st_mode = S_IFREG | 0444;
1595    stbuf->st_nlink = 1;
1596    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1597    stbuf->st_size = PROCFS_GetPNGSizeForDisplayAtIndex(index);
1598
1599    return 0;
1600}
1601
1602#if MACFUSE_PROCFS_ENABLE_TPM
1603GETATTR_HANDLER(system__hardware__tpm__keyslots__slot)
1604{
1605    uint32_t keys[256];
1606    unsigned long slotno = strtol(argv[0], NULL, 10);
1607
1608    uint16_t slots_used = 0;
1609    uint32_t slots_free = 0;
1610    uint32_t slots_total = 0;
1611
1612    if (TPM_GetCapability_Slots(&slots_free)) {
1613        return -ENOENT;
1614    }
1615
1616    if (TPM_GetCapability_Key_Handle(&slots_used, keys)) {
1617        return -ENOENT;
1618    }
1619
1620    slots_total = slots_used + slots_free;
1621
1622    if (slotno >= slots_total) {
1623        return -ENOENT;
1624    }
1625
1626    time_t current_time = time(NULL);
1627    stbuf->st_nlink = 1;
1628    stbuf->st_size = 9;
1629    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1630
1631    if (slotno >= slots_used) {
1632        stbuf->st_mode = S_IFREG | 0000;
1633    } else {
1634        stbuf->st_mode = S_IFREG | 0444;
1635    }
1636
1637    return 0;
1638}
1639
1640GETATTR_HANDLER(system__hardware__tpm__pcrs__pcr)
1641{
1642    time_t current_time = time(NULL);
1643    stbuf->st_mode = S_IFREG | 0444;
1644    stbuf->st_nlink = 1;
1645    stbuf->st_size = 60;
1646    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1647
1648    return 0;
1649}  
1650#endif /* MACFUSE_PROCFS_ENABLE_TPM */
1651
1652GETATTR_HANDLER(proc__task__ports__port)
1653{
1654    kern_return_t kr;
1655    task_t the_task = MACH_PORT_NULL;
1656    pid_t pid = strtol(argv[0], NULL, 10);
1657
1658    kr = task_for_pid(mach_task_self(), pid, &the_task);
1659    if (kr != KERN_SUCCESS) {
1660        return -ENOENT;
1661    }
1662
1663    DECL_PORT_LIST();
1664    INIT_PORT_LIST(the_task);
1665
1666    int found = 0;
1667    unsigned int i;
1668    unsigned int the_port_name = strtoul(argv[1], NULL, 16);
1669
1670    for (i = 0; i < name_count; i++) {
1671        if (the_port_name == name_list[i]) {
1672            found = 1;
1673            break;
1674        }
1675    }
1676
1677    FINI_PORT_LIST();
1678
1679    if (the_task != MACH_PORT_NULL) {
1680        mach_port_deallocate(mach_task_self(), the_task);
1681    }
1682
1683    if (!found) {
1684        return -ENOENT;
1685    }
1686
1687    time_t current_time = time(NULL);
1688
1689    stbuf->st_mode = S_IFDIR | 0555;
1690    stbuf->st_nlink = 1;
1691    stbuf->st_size = 0;
1692    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1693    
1694    return 0;
1695}
1696
1697GETATTR_HANDLER(proc__task__threads__thread)
1698{
1699    kern_return_t kr;
1700    task_t the_task = MACH_PORT_NULL;
1701    pid_t pid = strtol(argv[0], NULL, 10);
1702
1703    kr = task_for_pid(mach_task_self(), pid, &the_task);
1704    if (kr != KERN_SUCCESS) {
1705        return -ENOENT;
1706    }
1707
1708    DECL_THREAD_LIST();
1709    INIT_THREAD_LIST(the_task);
1710    FINI_THREAD_LIST();
1711
1712    if (the_task != MACH_PORT_NULL) {
1713        mach_port_deallocate(mach_task_self(), the_task);
1714    }
1715
1716    unsigned int the_thread_name = strtoul(argv[1], NULL, 16);
1717    if (the_thread_name >= thread_count) {
1718        return -ENOENT;
1719    }
1720
1721    time_t current_time = time(NULL);
1722
1723    stbuf->st_mode = S_IFDIR | 0555;
1724    stbuf->st_nlink = 1;
1725    stbuf->st_size = 0;
1726    stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1727    
1728    return 0;
1729}
1730
1731GETATTR_HANDLER(proc__windows__screenshots__window)
1732{
1733    pid_t pid = strtol(argv[0], NULL, 10);
1734    CGWindowID target = strtol(argv[1], NULL, 16);
1735    ProcessSerialNumber psn;
1736
1737    OSStatus status = GetProcessForPID(pid, &psn);
1738    if (status != noErr) {
1739        return 0; /* technically not an error in this case */
1740    }
1741
1742    CGSConnectionID conn;
1743    CGError err = CGSGetConnectionIDForPSN(0, &psn, &conn);
1744    if (err != kCGErrorSuccess) {
1745        return 0; /* just be nice */
1746    }
1747
1748#define MAX_WINDOWS 256
1749    CGSWindowID windowIDs[MAX_WINDOWS];
1750    int windowCount = 0;
1751    int i = 0;
1752
1753    err = CGSGetWindowList(_CGSDefaultConnection(), conn, MAX_WINDOWS,
1754                           windowIDs, &windowCount);
1755
1756    for (i = 0; i < windowCount; i++) {
1757        if (windowIDs[i] == target) {
1758            time_t current_time = time(NULL);
1759
1760            stbuf->st_mode = S_IFREG | 0444;
1761            stbuf->st_nlink = 1;
1762            stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = current_time;
1763            stbuf->st_size = PROCFS_GetPNGSizeForWindowAtIndex(windowIDs[i]);
1764            return 0;
1765        }
1766    }
1767
1768    return -ENOENT;
1769}
1770
1771// END: GETATTR
1772
1773
1774#include <stdio.h>
1775#include <stdlib.h>
1776#include <string.h>
1777#include <libgen.h>
1778#include <sys/sysctl.h>
1779
1780int
1781procinfo(pid_t pid, struct kinfo_proc *kp)
1782{
1783    int mib[4];
1784    size_t bufsize = 0, orig_bufsize = 0;
1785    struct kinfo_proc *kprocbuf;
1786    int retry_count = 0;
1787    int local_error;
1788
1789    mib[0] = CTL_KERN;
1790    mib[1] = KERN_PROC;
1791    mib[2] = KERN_PROC_PID;
1792    mib[3] = pid;
1793
1794    kprocbuf = kp;
1795    orig_bufsize = bufsize = sizeof(struct kinfo_proc);
1796    for (retry_count = 0; ; retry_count++) {
1797        local_error = 0;
1798        bufsize = orig_bufsize;
1799        if ((local_error = sysctl(mib, 4, kp, &bufsize, NULL, 0)) < 0) {
1800            if (retry_count < 1000) {
1801                sleep(1);
1802                continue;
1803            }
1804            return local_error;
1805        } else if (local_error == 0) {
1806            break;
1807        }
1808        sleep(1);
1809    }
1810
1811    return local_error;
1812}
1813
1814int
1815getproccmdline(pid_t pid, char *cmdlinebuf, int len)
1816{
1817    int i, mib[4], rlen, tlen, thislen;
1818    int    argmax, target_argc;
1819    char *target_argv, *target_argv_end;
1820    char  *cp;
1821    size_t size;
1822
1823    if (pid == 0) {
1824        return snprintf(cmdlinebuf, len, "kernel\n");
1825    }
1826
1827    mib[0] = CTL_KERN;
1828    mib[1] = KERN_ARGMAX;
1829
1830    size = sizeof(argmax);
1831    if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
1832        return -1;
1833    }
1834
1835    target_argv = (char *)malloc(argmax);
1836    if (target_argv == NULL) {
1837        return -1;
1838    }
1839
1840    target_argv_end = target_argv + argmax;
1841
1842    mib[0] = CTL_KERN;
1843    mib[1] = KERN_PROCARGS2;
1844    mib[2] = pid;
1845
1846    size = (size_t)argmax;
1847    if (sysctl(mib, 3, target_argv, &size, NULL, 0) == -1) {
1848        free(target_argv);
1849        return -1;
1850    }
1851
1852    memcpy(&target_argc, target_argv, sizeof(target_argc));
1853    cp = target_argv + sizeof(target_argc);
1854    cp += strlen(cp) + 1; // saved exec path
1855    rlen = len;
1856    tlen = 0;
1857    for (i = 1; i < target_argc + 1; i++) {
1858        while (cp < target_argv_end && *cp == '\0')
1859            cp++;
1860        if (cp == target_argv_end) {
1861            /*
1862             * We've reached the end of target_argv without finding target_argc
1863             * arguments. This can happen when a process changes its argv.
1864             * Reported by Francis Devereux.
1865             */
1866            break;
1867        }
1868        thislen = snprintf(cmdlinebuf + tlen, rlen, "%s ", cp);
1869        tlen += thislen; 
1870        rlen -= thislen;
1871        if (rlen <= 0) {
1872            break;
1873        }
1874        cp += strlen(cp) + 1;
1875    }
1876    if (rlen > 0) {
1877        thislen = snprintf(cmdlinebuf + tlen, rlen, "\n");
1878        tlen += thislen;
1879        rlen -= thislen;
1880    }
1881    return tlen;
1882}
1883
1884// BEGIN: READ
1885
1886//    int
1887//    procfs_read_<handler>(procfs_dispatcher_entry_t  e,
1888//                          const char                *argv[],
1889//                          void                      *buf,
1890//                          size_t                     size,
1891//                          off_t                      offset,
1892//                          struct fuse_file_info     *fi)
1893
1894
1895READ_HANDLER(einval)
1896{
1897    return -EINVAL;
1898}
1899
1900READ_HANDLER(eisdir)
1901{
1902    return -EISDIR;
1903}
1904
1905READ_HANDLER(zero)
1906{
1907    return 0;
1908}
1909
1910READ_HANDLER(default_file_finder_info)
1911{
1912    if (!procfs_ui) {
1913        return -ENOENT;
1914    }
1915
1916    char tmpbuf[] = {
1917        0x0, 0x5, 0x16, 0x7, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1918        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
1919        0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0x0, 0x20, 0x0,
1920        0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x52, 0x0, 0x0, 0x0, 0x0, 0x54, 0x45,
1921       0x58, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1922        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1923        0x0, 0x0, 0x0, 0x0,
1924    };
1925    int len = 82;
1926
1927    if (offset < len) {
1928        if (offset + size > len)
1929            size = len - offset;
1930        memcpy(buf, tmpbuf + offset, size);
1931    } else             
1932        size = 0;
1933
1934    return size;
1935}
1936
1937READ_HANDLER(system__firmware__variables)
1938{
1939    io_registry_entry_t    options;
1940    CFMutableDictionaryRef optionsDict;
1941    kern_return_t          kr = KERN_FAILURE;
1942
1943    options = IORegistryEntryFromPath(kIOMasterPortDefault,
1944                                      kIODeviceTreePlane ":/options");
1945    if (options) {
1946        kr = IORegistryEntryCreateCFProperties(options, &optionsDict, 0, 0);
1947        if (kr == KERN_SUCCESS) {
1948            CFDataRef xml = CFPropertyListCreateXMLData(kCFAllocatorDefault,
1949                                (CFPropertyListRef)optionsDict);
1950
1951            int len = CFDataGetLength(xml);
1952            if (len < 0) {
1953                kr = KERN_FAILURE;
1954                goto done;
1955            }
1956
1957            const UInt8 *tmpbuf = CFDataGetBytePtr(xml);
1958   
1959            if (offset < len) {
1960                if (offset + size > len)
1961                    size = len - offset;
1962                memcpy(buf, tmpbuf + offset, size);
1963            } else
1964                size = 0;
1965done:
1966            CFRelease(xml);
1967            CFRelease(optionsDict);
1968        }
1969        IOObjectRelease(options);
1970    }
1971   
1972    if (kr != KERN_SUCCESS) {
1973        return -EIO;
1974    }
1975
1976    return size;
1977}
1978
1979READ_HANDLER(system__hardware__cpus__cpu__data)
1980{
1981    int len;
1982    kern_return_t kr;
1983    char tmpbuf[4096];
1984    const char *whichfile = argv[0];
1985    unsigned int whichcpu = atoi(whichfile);
1986
1987    if (whichcpu >= processor_count) {
1988        return -ENOENT;
1989    }
1990
1991    processor_basic_info_data_t    basic_info;
1992    processor_cpu_load_info_data_t cpu_load_info;
1993    natural_t                      info_count;
1994    host_name_port_t               myhost = mach_host_self();
1995
1996    info_count = PROCESSOR_BASIC_INFO_COUNT;
1997    kr = processor_info(processor_list[whichcpu], PROCESSOR_BASIC_INFO,
1998                        &myhost, (processor_info_t)&basic_info, &info_count);
1999    if (kr != KERN_SUCCESS) {
2000        return -EIO;
2001    }
2002    info_count = PROCESSOR_CPU_LOAD_INFO_COUNT;
2003    kr = processor_info(processor_list[whichcpu], PROCESSOR_CPU_LOAD_INFO,
2004                        &myhost, (processor_info_t)&cpu_load_info, &info_count);
2005    if (kr != KERN_SUCCESS) {
2006        return -EIO;
2007    }
2008
2009    len = 0;
2010    unsigned long ticks;
2011
2012    len += snprintf(tmpbuf + len, 4096 - len, "slot %d%s%s",
2013                    basic_info.slot_num,
2014                    (basic_info.is_master) ? " (master)," : ",",
2015                    (basic_info.running) ? " running\n" : " not running\n");
2016    len += snprintf(tmpbuf + len, 4096 - len, "type %d, subtype %d\n",
2017                    basic_info.cpu_type, basic_info.cpu_subtype);
2018
2019    ticks = cpu_load_info.cpu_ticks[CPU_STATE_USER] +
2020            cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM] +
2021            cpu_load_info.cpu_ticks[CPU_STATE_IDLE] +
2022            cpu_load_info.cpu_ticks[CPU_STATE_NICE];
2023    len += snprintf(tmpbuf + len, 4096 - len,
2024                    "%ld ticks (user %u system %u idle %u nice %u)\n",
2025                    ticks,
2026                    cpu_load_info.cpu_ticks[CPU_STATE_USER],
2027                    cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM],
2028                    cpu_load_info.cpu_ticks[CPU_STATE_IDLE],
2029                    cpu_load_info.cpu_ticks[CPU_STATE_NICE]);
2030    len += snprintf(tmpbuf + len, 4096 - len, "cpu uptime %ldh %ldm %lds\n",
2031                    (ticks / 100) / 3600, ((ticks / 100) % 3600) / 60,
2032                    (ticks / 100) % 60);
2033
2034    if (len < 0) {
2035        return -EIO;
2036    }
2037    
2038    if (offset < len) {
2039        if (offset + size > len)
2040            size = len - offset;
2041        memcpy(buf, tmpbuf + offset, size);
2042    } else             
2043        size = 0;
2044    
2045    return size;
2046}
2047
2048READ_HANDLER(system__hardware__displays__display__info)
2049{
2050    char tmpbuf[4096];
2051    unsigned long index = strtol(argv[0], NULL, 10);
2052    CGDisplayCount display_count = PROCFS_GetDisplayCount();
2053
2054    if (index >= display_count) {
2055        return -ENOENT;
2056    }
2057
2058    size_t len = 4096;
2059    int ret = PROCFS_GetInfoForDisplayAtIndex(index, tmpbuf, &len);
2060    if (ret) {
2061        return -EIO;
2062    }
2063
2064    if (len < 0) {
2065        return -EIO;
2066    }   
2067            
2068    if (offset < len) {
2069        if (offset + size > len)
2070            size = len - offset;
2071        memcpy(buf, tmpbuf + offset, size);
2072    } else           
2073        size = 0;
2074
2075    return size;
2076}
2077
2078READ_HANDLER(system__hardware__camera__screenshot)
2079{
2080    size_t max_len = PROCFS_GetTIFFSizeFromCamera();
2081    size_t len = (size_t)CFDataGetLength(camera_tiff);
2082
2083    if (len > max_len) {
2084        return -EIO;
2085    }
2086
2087    CFDataSetLength(camera_tiff, max_len);
2088
2089    const UInt8 *tmpbuf = CFDataGetBytePtr(camera_tiff);
2090        
2091    if (len < 0) {
2092        return -EIO; 
2093    }
2094
2095    if (offset < len) {
2096        if (offset + size > len)
2097            size = len - offset;
2098        memcpy(buf, tmpbuf + offset, size);
2099    } else
2100        size = 0;
2101
2102    return size;
2103}
2104
2105READ_HANDLER(system__hardware__displays__display__screenshot)
2106{
2107    unsigned long index = strtol(argv[0], NULL, 10);
2108    CGDisplayCount display_count = PROCFS_GetDisplayCount();
2109
2110    if (index >= display_count) {
2111        return -ENOENT;
2112
2113    }
2114    pthread_mutex_lock(&display_lock);
2115    if (!display_png) {
2116        pthread_mutex_unlock(&display_lock);
2117        return -EIO;
2118    }
2119    CFRetain(display_png);
2120    pthread_mutex_unlock(&display_lock);
2121
2122    size_t max_len = PROCFS_GetPNGSizeForDisplayAtIndex(index);
2123    size_t len = (size_t)CFDataGetLength(display_png);
2124
2125    if (len > max_len) {
2126        pthread_mutex_lock(&display_lock);
2127        CFRelease(display_png);
2128        pthread_mutex_unlock(&display_lock);
2129        return -EIO;
2130    }
2131
2132    CFDataSetLength(display_png, max_len);
2133    len = max_len;
2134    const UInt8 *tmpbuf = CFDataGetBytePtr(display_png);
2135
2136    if (len < 0) {
2137        pthread_mutex_lock(&display_lock);
2138        CFRelease(display_png);
2139        pthread_mutex_unlock(&display_lock);
2140        return -EIO;
2141    }
2142
2143    if (offset < len) {
2144        if (offset + size > len)
2145            size = len - offset;
2146        memcpy(buf, tmpbuf + offset, size);
2147    } else
2148        size = 0;
2149
2150    pthread_mutex_lock(&display_lock);
2151    CFRelease(display_png);
2152    pthread_mutex_unlock(&display_lock);
2153
2154    return size;
2155}
2156
2157typedef struct {
2158    const char  *classname;
2159    unsigned int index;
2160    IOItemCount  structureInputSize;
2161    IOByteCount  structureOutputSize;
2162} sms_configuration_t;
2163
2164sms_configuration_t
2165SMS_CONFIGURATIONS[] = {
2166    { "SMCMotionSensor",    5, 40, 40 }, // 0
2167    { "PMUMotionSensor",   21, 60, 60 }, // 1
2168    { "IOI2CMotionSensor", 21, 60, 60 }, // 2
2169    { NULL,                -1,  0,  0 },
2170};
2171
2172enum { sms_maxConfigurationID = 2 };
2173
2174static int sms_configurationID = -1;
2175
2176READ_HANDLER(system__hardware__xsensor)
2177{
2178    int len = -1;
2179    kern_return_t kr;
2180    char tmpbuf[4096];
2181    const char *whichfile = argv[0];
2182
2183    if (strcmp(whichfile, "lightsensor") == 0) {
2184        unsigned int  gIndex = 0;
2185        IOItemCount   scalarInputCount = 0;
2186        IOItemCount   scalarOutputCount = 2;
2187        SInt32 left = 0, right = 0;
2188        if (lightsensor_port == 0) {
2189            len = snprintf(tmpbuf, 4096, "not available\n");
2190            goto gotdata;
2191        }
2192        kr = IOConnectMethodScalarIScalarO(lightsensor_port, gIndex,
2193                                           scalarInputCount, scalarOutputCount,
2194                                           &left, &right);
2195        if (kr == KERN_SUCCESS) {
2196            len = snprintf(tmpbuf, 4096, "%ld %ld\n", left, right);
2197        } else if (kr == kIOReturnBusy) {
2198            len = snprintf(tmpbuf, 4096, "busy\n");
2199        } else {
2200            len = snprintf(tmpbuf, 4096, "error %d\n", kr);
2201        }
2202        goto gotdata;
2203    }
2204
2205    if (strcmp(whichfile, "motionsensor") == 0) {
2206        MotionSensorData_t sms_data;
2207        if (motionsensor_port == 0) {
2208            len = snprintf(tmpbuf, 4096, "not available\n");
2209            goto gotdata;
2210        }
2211        kr = sms_getOrientation_hardware_apple(&sms_data);
2212        if (kr != KERN_SUCCESS) {
2213            len = snprintf(tmpbuf, 4096, "error %d\n", kr);
2214        } else {
2215            len = snprintf(tmpbuf, 4096, "%hhd %hhd %hhd\n",
2216                           sms_data.x, sms_data.y, sms_data.z);
2217        }
2218        goto gotdata;
2219    }
2220
2221    if (strcmp(whichfile, "mouse") == 0) {
2222        HIPoint mouselocation = { 0.0, 0.0 };
2223        (void)HIGetMousePosition(kHICoordSpaceScreenPixel,
2224                                 NULL, &mouselocation);
2225        len = snprintf(tmpbuf, 4096, "%.0f %.0f\n",
2226                       mouselocation.x, mouselocation.y);
2227        goto gotdata;
2228    }
2229
2230gotdata:
2231
2232    if (len < 0) {
2233        return -EIO;
2234    }
2235    
2236    if (offset < len) {
2237        if (offset + size > len)
2238            size = len - offset;
2239        memcpy(buf, tmpbuf + offset, size);
2240    } else             
2241        size = 0;
2242    
2243    return size;
2244}
2245
2246/*
2247 * To make the tpm stuff work, you need to:
2248 *
2249 * 1. Get the Mac OS X TPM device driver from
2250 *    http://osxbook.com/book/bonus/chapter10/tpm/
2251 *
2252 * 2. Get IBM's libtpm user-space library.
2253 *
2254 * 3. Define MACFUSE_PROCFS_ENABLE_TPM to 1, compile procfs.cc, and link with
2255 *    libtpm.
2256 */
2257
2258#if MACFUSE_PROCFS_ENABLE_TPM
2259READ_HANDLER(system__hardware__tpm__hwmodel)
2260{
2261    int len;
2262    char tmpbuf[4096];
2263
2264    len = snprintf(tmpbuf, 4096, "%s\n", "SLB 9635 TT 1.2");
2265
2266    if (len <= 0) {
2267        return -EIO;
2268    }
2269
2270    if (offset < len) {
2271        if (offset + size > len)
2272            size = len - offset;
2273        memcpy(buf, tmpbuf + offset, size);
2274    } else
2275        size = 0;
2276
2277    return size;
2278}
2279
2280READ_HANDLER(system__hardware__tpm__hwvendor)
2281{
2282    int len;
2283    char tmpbuf[4096];
2284
2285    len = snprintf(tmpbuf, 4096, "%s\n", "Infineon");
2286
2287    if (len <= 0) {
2288        return -EIO;
2289    }
2290
2291    if (offset < len) {
2292        if (offset + size > len)
2293            size = len - offset;
2294        memcpy(buf, tmpbuf + offset, size);
2295    } else
2296        size = 0;
2297
2298    return size;
2299}
2300
2301READ_HANDLER(system__hardware__tpm__hwversion)
2302{
2303    int major, minor, version, rev, len;
2304    char tmpbuf[4096];
2305
2306    if (TPM_GetCapability_Version(&major, &minor, &version, &rev)) {
2307        return -EIO;
2308    }
2309
2310    len = snprintf(tmpbuf, 4096, "%d.%d.%d.%d\n", major, minor, version, rev);
2311
2312    if (len <= 0) {
2313        return -EIO;
2314    }
2315
2316    if (offset < len) {
2317        if (offset + size > len)
2318            size = len - offset;
2319        memcpy(buf, tmpbuf + offset, size);
2320    } else
2321        size = 0;
2322
2323    return size;
2324}
2325
2326READ_HANDLER(system__hardware__tpm__keyslots__slot)
2327{
2328    char tmpbuf[32] = { 0 };
2329    int len;
2330    uint32_t keys[256];
2331    unsigned long slotno = strtol(argv[0], NULL, 10);
2332
2333    uint16_t slots_used = 0;
2334    uint32_t slots_free = 0;
2335    uint32_t slots_total = 0;
2336
2337    if (TPM_GetCapability_Slots(&slots_free)) {
2338        return -ENOENT;
2339    }
2340
2341    if (TPM_GetCapability_Key_Handle(&slots_used, keys)) {
2342        return -ENOENT;
2343    }
2344
2345    slots_total = slots_used + slots_free;
2346
2347    if (slotno >= slots_used) {
2348        return -EIO;
2349    }
2350
2351    len = snprintf(tmpbuf, 32, "%08x\n", keys[slotno]);
2352    if (offset < len) {
2353        if (offset + size > len)
2354            size = len - offset;
2355        memcpy(buf, tmpbuf + offset, size);
2356    } else {
2357        size = 0;
2358    }
2359
2360    return size;
2361}
2362
2363READ_HANDLER(system__hardware__tpm__pcrs__pcr)
2364{
2365    uint32_t pcrs, the_pcr;
2366    unsigned char pcr_data[20];
2367    char tmpbuf[4096] = { 0 };
2368    int len, i;
2369
2370    if (TPM_GetCapability_Pcrs(&pcrs)) {
2371        return -EIO;
2372    }
2373
2374    the_pcr = strtol(argv[0], NULL, 10);
2375    if ((the_pcr < 0) || (the_pcr >= pcrs)) {
2376        return -ENOENT;
2377    }
2378
2379    if (TPM_PcrRead(the_pcr, pcr_data)) {
2380        return -EIO;
2381    }
2382
2383    len = 0;
2384    for (i = 0; i < 20; i++) {
2385        len += snprintf(tmpbuf + len, 4096 - len, "%02x ", pcr_data[i]);
2386    }
2387    tmpbuf[len - 1] = '\n';
2388
2389    if (offset < len) {
2390        if (offset + size > len)
2391            size = len - offset;
2392        memcpy(buf, tmpbuf + offset, size);
2393    } else {
2394        size = 0;
2395    }
2396
2397    return size;
2398}
2399#endif /* MACFUSE_PROCFS_ENABLE_TPM */
2400
2401READ_HANDLER(proc__carbon)
2402{
2403    OSStatus status = procNotFound;
2404    ProcessSerialNumber psn;
2405    CFStringRef nameRef;
2406    char tmpbuf[4096];
2407    int len = -1;
2408
2409    pid_t pid = atoi(argv[0]);
2410    const char *whichfile = argv[1];
2411
2412    if (pid <= 0) {
2413        return 0;
2414    }
2415
2416    status = GetProcessForPID(pid, &psn);
2417
2418    if (status != noErr) {
2419        return 0;
2420    }
2421
2422    if (strcmp(whichfile, "psn") == 0) {
2423        len = snprintf(tmpbuf, 4096, "%lu:%lu\n",
2424                       psn.highLongOfPSN, psn.lowLongOfPSN);
2425        goto gotdata;
2426    }
2427
2428    if (strcmp(whichfile, "name") == 0) {
2429        status = CopyProcessName(&psn, &nameRef);
2430        CFStringGetCString(nameRef, tmpbuf, 4096, kCFStringEncodingASCII);
2431        len = snprintf(tmpbuf, 4096, "%s\n", tmpbuf);
2432        CFRelease(nameRef);
2433        goto gotdata;
2434    }
2435
2436    return -ENOENT;
2437
2438gotdata:
2439
2440    if (len < 0) {
2441        return -EIO;
2442    }   
2443        
2444    if (offset < len) {
2445        if (offset + size > len)
2446            size = len - offset;
2447        memcpy(buf, tmpbuf + offset, size);
2448    } else
2449        size = 0;
2450
2451    return size;
2452}
2453
2454#if __i386__
2455READ_HANDLER(proc__fds)
2456{
2457    pid_t pid = atoi(argv[0]);
2458    char tmpbuf[65536];
2459    int len = 65536;
2460
2461    int ret = procfs_proc_pidinfo(pid, tmpbuf, &len);
2462
2463    if (ret) {
2464        return -EIO;
2465    }
2466
2467    if (offset < len) {
2468        if (offset + size > len)
2469            size = len - offset;
2470        memcpy(buf, tmpbuf + offset, size);
2471    } else
2472        size = 0;
2473
2474    return size;
2475}
2476#endif /* __i386__ */
2477
2478#define HANDLE_GENERIC_ITEM(item, fmt, datasrc)     \
2479    if (strcmp(whichfile, item) == 0) {             \
2480        len = snprintf(tmpbuf, 4096, fmt, datasrc); \
2481        goto gotdata;                               \
2482    }   
2483
2484READ_HANDLER(proc__generic)
2485{
2486    pid_t pid = atoi(argv[0]);
2487    const char *whichfile = argv[1];
2488    struct kinfo_proc kp;
2489    int len;
2490    char tmpbuf[4096];
2491
2492    len = procinfo(pid, &kp);
2493    if (len != 0) {
2494        return -EIO;
2495    }
2496
2497    len = -1;
2498
2499    if (strcmp(whichfile, "cmdline") == 0) {
2500        len = getproccmdline(pid, tmpbuf, 4096);
2501        goto gotdata;
2502    }
2503
2504    if (strcmp(whichfile, "tdev") == 0) {
2505        char *dr = devname_r(kp.kp_eproc.e_tdev, S_IFCHR, tmpbuf, 4096);
2506        if (!dr) {
2507            len = snprintf(tmpbuf, 4096, "none\n");
2508        } else {
2509            len = snprintf(tmpbuf, 4096, "%s\n", dr);
2510        }
2511        goto gotdata;
2512    }
2513
2514    HANDLE_GENERIC_ITEM("jobc",    "%hd\n", kp.kp_eproc.e_jobc);
2515    HANDLE_GENERIC_ITEM("paddr",   "%p\n",  kp.kp_eproc.e_paddr);
2516    HANDLE_GENERIC_ITEM("pgid",    "%d\n",  kp.kp_eproc.e_pgid);
2517    HANDLE_GENERIC_ITEM("ppid",    "%d\n",  kp.kp_eproc.e_ppid);
2518    HANDLE_GENERIC_ITEM("wchan",   "%s\n",
2519                        (kp.kp_eproc.e_wmesg[0]) ? kp.kp_eproc.e_wmesg : "-");
2520    HANDLE_GENERIC_ITEM("tpgid",   "%d\n",  kp.kp_eproc.e_tpgid);
2521
2522gotdata:
2523
2524    if (len < 0) {
2525        return -EIO;
2526    }
2527
2528    if (offset < len) {
2529        if (offset + size > len)
2530            size = len - offset;
2531        memcpy(buf, tmpbuf + offset, size);
2532    } else
2533        size = 0;
2534
2535    return size;
2536}
2537
2538#define READ_PROC_TASK_PROLOGUE()                          \
2539    int len = -1;                                          \
2540    kern_return_t kr;                                      \
2541    char tmpbuf[4096];                                     \
2542    task_t the_task = MACH_PORT_NULL;                      \
2543    pid_t pid = strtol(argv[0], NULL, 10);                 \
2544                                                           \
2545    kr = task_for_pid(mach_task_self(), pid, &the_task);   \
2546    if (kr != KERN_SUCCESS) {                              \
2547        return -EIO;                                       \
2548    }
2549
2550#define READ_PROC_TASK_EPILOGUE()                          \
2551                                                           \
2552    if (the_task != MACH_PORT_NULL) {                      \
2553        mach_port_deallocate(mach_task_self(), the_task);  \
2554    }                                                      \
2555                                                           \
2556    if (len < 0) {                                         \
2557        return -EIO;                                       \
2558    }                                                      \
2559                                                           \
2560    if (offset < len) {                                    \
2561        if (offset + size > len)                           \
2562            size = len - offset;                           \
2563        memcpy(buf, tmpbuf + offset, size);                \
2564    } else                                                 \
2565        size = 0;                                          \
2566                                                           \
2567    return size;
2568
2569static const char *thread_policies[] = {
2570    "UNKNOWN?",
2571    "STANDARD|EXTENDED",
2572    "TIME_CONSTRAINT",
2573    "PRECEDENCE",
2574};
2575#define THREAD_POLICIES_MAX (int)(sizeof(thread_policies)/sizeof(char *))
2576
2577READ_HANDLER(proc__task__absolutetime_info)
2578{
2579    READ_PROC_TASK_PROLOGUE();
2580
2581    task_info_data_t tinfo;
2582    mach_msg_type_number_t task_info_count;
2583    task_absolutetime_info_t absolutetime_info;
2584
2585    task_info_count = TASK_INFO_MAX;
2586    kr = task_info(the_task, TASK_ABSOLUTETIME_INFO, (task_info_t)tinfo,
2587                   &task_info_count);
2588    if (kr != KERN_SUCCESS) {
2589        return -EIO;
2590    }
2591
2592    const char *whichfile = argv[1];
2593    absolutetime_info = (task_absolutetime_info_t)tinfo;
2594
2595    if (strcmp(whichfile, "threads_system") == 0) {
2596        len  = snprintf(tmpbuf, 4096, "%lld\n",
2597                        absolutetime_info->threads_system);
2598        goto gotdata;
2599    }
2600
2601    if (strcmp(whichfile, "threads_user") == 0) {
2602        len  = snprintf(tmpbuf, 4096, "%lld\n",
2603                        absolutetime_info->threads_user);
2604        goto gotdata;
2605    }
2606
2607    if (strcmp(whichfile, "total_system") == 0) {
2608        len  = snprintf(tmpbuf, 4096, "%lld\n",
2609                        absolutetime_info->total_system);
2610        goto gotdata;
2611    }
2612
2613    if (strcmp(whichfile, "total_user") == 0) {
2614        len  = snprintf(tmpbuf, 4096, "%lld\n",
2615                        absolutetime_info->total_user);
2616        goto gotdata;
2617    }
2618
2619gotdata:
2620
2621    READ_PROC_TASK_EPILOGUE();
2622}
2623
2624READ_HANDLER(proc__task__basic_info)
2625{
2626    READ_PROC_TASK_PROLOGUE();
2627
2628    task_info_data_t tinfo;
2629    mach_msg_type_number_t task_info_count;
2630    task_basic_info_t basic_info;
2631
2632    task_info_count = TASK_INFO_MAX;
2633    kr = task_info(the_task, TASK_BASIC_INFO, (task_info_t)tinfo,
2634                   &task_info_count);
2635    if (kr != KERN_SUCCESS) {
2636        return -EIO;
2637    }
2638
2639    basic_info = (task_basic_info_t)tinfo;
2640    const char *whichfile = argv[1];
2641
2642    if (strcmp(whichfile, "policy") == 0) {
2643        if ((basic_info->policy < 0) &&
2644            (basic_info->policy > THREAD_POLICIES_MAX)) {
2645            basic_info->policy = 0;
2646        }
2647        len = snprintf(tmpbuf, 4096, "%s\n",
2648                       thread_policies[basic_info->policy]);
2649        goto gotdata;
2650    }
2651
2652    if (strcmp(whichfile, "resident_size") == 0) {
2653        len = snprintf(tmpbuf, 4096, "%u KB\n",
2654                       basic_info->resident_size >> 10);
2655        goto gotdata;
2656    }
2657
2658    if (strcmp(whichfile, "suspend_count") == 0) {
2659        len = snprintf(tmpbuf, 4096, "%u\n", basic_info->suspend_count);
2660        goto gotdata;
2661    }
2662
2663    if (strcmp(whichfile, "system_time") == 0) {
2664        len = snprintf(tmpbuf, 4096, "%us %uus\n",
2665                       basic_info->system_time.seconds,
2666                       basic_info->system_time.microseconds);
2667        goto gotdata;
2668    }
2669
2670    if (strcmp(whichfile, "user_time") == 0) {
2671        len = snprintf(tmpbuf, 4096, "%us %uus\n",
2672                       basic_info->user_time.seconds,
2673                       basic_info->user_time.microseconds);
2674        goto gotdata;
2675    }
2676
2677    if (strcmp(whichfile, "virtual_size") == 0) {
2678        len = snprintf(tmpbuf, 4096, "%u KB\n", basic_info->virtual_size >> 10);
2679        goto gotdata;
2680    }
2681
2682gotdata:
2683
2684    READ_PROC_TASK_EPILOGUE();
2685}
2686
2687READ_HANDLER(proc__task__events_info)
2688{
2689    READ_PROC_TASK_PROLOGUE();
2690
2691    task_info_data_t tinfo;
2692    mach_msg_type_number_t task_info_count;
2693    task_events_info_t events_info;
2694
2695    task_info_count = TASK_INFO_MAX;
2696    kr = task_info(the_task, TASK_EVENTS_INFO, (task_info_t)tinfo,
2697                   &task_info_count);
2698    if (kr != KERN_SUCCESS) {
2699        return -EIO;
2700    }
2701
2702    const char *whichfile = argv[1];
2703    events_info = (task_events_info_t)tinfo;
2704
2705#define HANDLE_TASK_EVENT_ITEM(item, datasrc)          \
2706    if (strcmp(whichfile, item) == 0) {                \
2707        len = snprintf(tmpbuf, 4096, "%u\n", datasrc); \
2708        goto gotdata;                                  \
2709    }
2710
2711    HANDLE_TASK_EVENT_ITEM("cow_faults", events_info->cow_faults);
2712    HANDLE_TASK_EVENT_ITEM("csw", events_info->csw);
2713    HANDLE_TASK_EVENT_ITEM("faults", events_info->faults);
2714    HANDLE_TASK_EVENT_ITEM("messages_received", events_info->messages_received);
2715    HANDLE_TASK_EVENT_ITEM("messages_sent", events_info->messages_sent);
2716    HANDLE_TASK_EVENT_ITEM("pageins", events_info->pageins);
2717    HANDLE_TASK_EVENT_ITEM("syscalls_mach", events_info->syscalls_mach);
2718    HANDLE_TASK_EVENT_ITEM("syscalls_unix", events_info->syscalls_unix);
2719
2720    return -EIO;
2721
2722gotdata:
2723
2724    READ_PROC_TASK_EPILOGUE();
2725}
2726
2727READ_HANDLER(proc__task__thread_times_info)
2728{
2729    READ_PROC_TASK_PROLOGUE();
2730
2731    task_info_data_t tinfo;
2732    mach_msg_type_number_t task_info_count;
2733    task_thread_times_info_t thread_times_info;
2734
2735    task_info_count = TASK_INFO_MAX;
2736    kr = task_info(the_task, TASK_THREAD_TIMES_INFO, (task_info_t)tinfo,
2737                   &task_info_count);
2738    if (kr != KERN_SUCCESS) {
2739        return -EIO;
2740    }
2741
2742    const char *whichfile = argv[1];
2743    thread_times_info = (task_thread_times_info_t)tinfo;
2744    
2745    if (strcmp(whichfile, "system_time") == 0) {
2746        len = snprintf(tmpbuf, 4096, "%us %uus\n",
2747                       thread_times_info->system_time.seconds,
2748                       thread_times_info->system_time.microseconds);
2749        goto gotdata;
2750    }
2751
2752    if (strcmp(whichfile, "user_time") == 0) {
2753        len = snprintf(tmpbuf, 4096, "%us %uus\n",
2754                       thread_times_info->user_time.seconds,
2755                       thread_times_info->user_time.microseconds);
2756        goto gotdata;
2757    }
2758
2759    return -ENOENT;
2760
2761gotdata:
2762
2763    READ_PROC_TASK_EPILOGUE();
2764}
2765
2766READ_HANDLER(proc__task__mach_name)
2767{
2768    READ_PROC_TASK_PROLOGUE();
2769
2770    len = snprintf(tmpbuf, 4096, "%x\n", the_task);
2771   
2772    READ_PROC_TASK_EPILOGUE();
2773}
2774
2775READ_HANDLER(proc__task__ports__port)
2776{
2777    READ_PROC_TASK_PROLOGUE();
2778    DECL_PORT_LIST();
2779    INIT_PORT_LIST(the_task);
2780    unsigned int i;
2781    char the_name[MAXNAMLEN + 1];
2782    mach_port_t the_port = MACH_PORT_NULL;
2783    mach_port_type_t the_type = 0;
2784    for (i = 0; i < name_count; i++) {
2785        snprintf(the_name, MAXNAMLEN, "%x", name_list[i]);
2786        if (strcmp(the_name, argv[1]) == 0) {
2787            the_port = name_list[i];
2788            the_type = type_list[i];
2789            break;
2790        }
2791    }
2792
2793    if (the_port == MACH_PORT_NULL) {
2794        FINI_PORT_LIST();
2795        return -ENOENT;
2796    }
2797
2798    const char *whichfile = argv[2];
2799    mach_msg_type_number_t port_info_count;
2800
2801    if (strcmp(whichfile, "task_rights") == 0) {
2802        len = 0;
2803        if (the_type & MACH_PORT_TYPE_SEND) {
2804             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "SEND");
2805        } 
2806        if (the_type & MACH_PORT_TYPE_RECEIVE) {
2807             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "RECEIVE");
2808        } 
2809        if (the_type & MACH_PORT_TYPE_SEND_ONCE) {
2810             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "SEND_ONCE");
2811        } 
2812        if (the_type & MACH_PORT_TYPE_PORT_SET) {
2813             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "PORT_SET");
2814        } 
2815        if (the_type & MACH_PORT_TYPE_DEAD_NAME) {
2816             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "DEAD_NAME");
2817        } 
2818        if (the_type & MACH_PORT_TYPE_DNREQUEST) {
2819             len += snprintf(tmpbuf + len, 4096 - len, "%s ", "DNREQUEST");
2820        } 
2821        len += snprintf(tmpbuf + len, 4096 - len, "\n");
2822        goto gotdata;
2823    }
2824
2825    mach_port_limits_t port_limits;
2826    mach_port_status_t port_status;
2827
2828    port_info_count = MACH_PORT_LIMITS_INFO_COUNT;
2829    kr = mach_port_get_attributes(the_task, the_port, MACH_PORT_LIMITS_INFO,
2830                                  (mach_port_info_t)&port_limits,
2831                                  &port_info_count);
2832
2833    if ((kr != KERN_SUCCESS) && (kr != KERN_INVALID_RIGHT)) {
2834        FINI_PORT_LIST();
2835        return -EIO;
2836    }
2837
2838    if (strcmp(whichfile, "qlimit") == 0) {
2839        if (kr == KERN_SUCCESS) {
2840            len = snprintf(tmpbuf, 4096, "%d\n", port_limits.mpl_qlimit);
2841        } else {
2842            len = snprintf(tmpbuf, 4096, "-\n");
2843        }
2844        goto gotdata;
2845    }
2846
2847    port_info_count = MACH_PORT_RECEIVE_STATUS_COUNT;
2848    kr = mach_port_get_attributes(the_task, the_port, MACH_PORT_RECEIVE_STATUS,
2849                                  (mach_port_info_t)&port_status,
2850                                  &port_info_count);
2851    if ((kr != KERN_SUCCESS) && (kr != KERN_INVALID_RIGHT)) {
2852        FINI_PORT_LIST();
2853        return -EIO;
2854    }
2855
2856    if (strcmp(whichfile, "msgcount") == 0) {
2857        if (kr == KERN_SUCCESS) {
2858            len = snprintf(tmpbuf, 4096, "%d\n", port_status.mps_msgcount);
2859        } else {
2860            len = snprintf(tmpbuf, 4096, "-\n");
2861        }
2862        goto gotdata;
2863    }
2864
2865    if (strcmp(whichfile, "seqno") == 0) {
2866        if (kr == KERN_SUCCESS) {
2867            len = snprintf(tmpbuf, 4096, "%d\n", port_status.mps_seqno);
2868        } else {
2869            len = snprintf(tmpbuf, 4096, "-\n");
2870        }
2871        goto gotdata;
2872    }
2873
2874    if (strcmp(whichfile, "sorights") == 0) {
2875        if (kr == KERN_SUCCESS) {
2876            len = snprintf(tmpbuf, 4096, "%d\n", port_status.mps_sorights);
2877        } else {
2878            len = snprintf(tmpbuf, 4096, "-\n");
2879        }
2880        goto gotdata;
2881    }
2882
2883gotdata:
2884
2885    FINI_PORT_LIST();
2886
2887    READ_PROC_TASK_EPILOGUE();
2888}
2889
2890static const char *task_roles[] = {
2891    "RENICED",
2892    "UNSPECIFIED",
2893    "FOREGROUND_APPLICATION",
2894    "BACKGROUND_APPLICATION",
2895    "CONTROL_APPLICATION",
2896    "GRAPHICS_SERVER",
2897};
2898#define TASK_ROLES_MAX (int)(sizeof(task_roles)/sizeof(char *))
2899
2900READ_HANDLER(proc__task__role)
2901{
2902    READ_PROC_TASK_PROLOGUE();
2903
2904    task_category_policy_data_t category_policy;
2905    mach_msg_type_number_t task_info_count;
2906    boolean_t get_default;
2907
2908    len = snprintf(tmpbuf, 4096, "NONE\n");
2909
2910    task_info_count = TASK_CATEGORY_POLICY_COUNT;
2911    get_default = FALSE;
2912    kr = task_policy_get(the_task, TASK_CATEGORY_POLICY,
2913                         (task_policy_t)&category_policy,
2914                         &task_info_count, &get_default);
2915    if (kr == KERN_SUCCESS) {
2916        if (get_default == FALSE) {
2917            if ((category_policy.role >= -1) &&
2918                (category_policy.role < (TASK_ROLES_MAX - 1))) {
2919                len = snprintf(tmpbuf, 4096, "%s\n",
2920                               task_roles[category_policy.role + 1]);
2921            }
2922        }
2923    }
2924
2925    READ_PROC_TASK_EPILOGUE();
2926}
2927
2928static const char *thread_states[] = {
2929    "NONE",
2930    "RUNNING",
2931    "STOPPED",
2932    "WAITING",
2933    "UNINTERRUPTIBLE",
2934    "HALTED",
2935};
2936#define THREAD_STATES_MAX (int)(sizeof(thread_states)/sizeof(char *))
2937
2938READ_HANDLER(proc__task__threads__thread__basic_info)
2939{
2940    READ_PROC_TASK_PROLOGUE();
2941    DECL_THREAD_LIST();
2942    INIT_THREAD_LIST(the_task);
2943
2944    thread_t the_thread = MACH_PORT_NULL;
2945    unsigned int i = strtoul(argv[1], NULL, 16);
2946
2947    if (i < thread_count) {
2948        the_thread = thread_list[i];
2949    }
2950    
2951    if (the_thread == MACH_PORT_NULL) {
2952        FINI_THREAD_LIST();
2953        return -ENOENT;
2954    }   
2955        
2956    const char *whichfile = argv[2];
2957
2958    thread_info_data_t thinfo;
2959    mach_msg_type_number_t thread_info_count;
2960    thread_basic_info_t basic_info_th;
2961
2962    thread_info_count = THREAD_INFO_MAX;
2963    kr = thread_info(the_thread, THREAD_BASIC_INFO, (thread_info_t)thinfo,
2964                     &thread_info_count);
2965
2966    if (kr != KERN_SUCCESS) {
2967        FINI_THREAD_LIST();
2968        return -EIO;
2969    }
2970
2971    basic_info_th = (thread_basic_info_t)thinfo;
2972
2973    if (strcmp(whichfile, "cpu_usage") == 0) {
2974        len = snprintf(tmpbuf, 4096, "%u\n", basic_info_th->cpu_usage);
2975        goto gotdata;
2976    }
2977
2978    if (strcmp(whichfile, "flags") == 0) {
2979        len = 0;
2980        len += snprintf(tmpbuf + len, 4096 - len, "%x", basic_info_th->flags);
2981        len += snprintf(tmpbuf + len, 4096 - len, "%s",
2982                 (basic_info_th->flags & TH_FLAGS_IDLE) ? " (IDLE)" : "");
2983        len += snprintf(tmpbuf + len, 4096 - len, "%s",
2984                 (basic_info_th->flags & TH_FLAGS_SWAPPED) ? " (SWAPPED)" : "");
2985        len += snprintf(tmpbuf + len, 4096 - len, "\n");
2986        goto gotdata;
2987    }
2988
2989    if (strcmp(whichfile, "policy") == 0) {
2990
2991        len = 0;
2992        boolean_t get_default = FALSE;
2993        thread_extended_policy_data_t        extended_policy;
2994        thread_time_constraint_policy_data_t time_constraint_policy;
2995        thread_precedence_policy_data_t      precedence_policy;
2996
2997        switch (basic_info_th->policy) {
2998
2999        case THREAD_EXTENDED_POLICY:
3000            thread_info_count = THREAD_EXTENDED_POLICY_COUNT;
3001            kr = thread_policy_get(the_thread, THREAD_EXTENDED_POLICY,
3002                                   (thread_policy_t)&extended_policy,
3003                                   &thread_info_count, &get_default);
3004            if (kr != KERN_SUCCESS) {
3005                len += snprintf(tmpbuf + len, 4096 - len,
3006                                "STANDARD/EXTENDED\n");
3007                break;
3008            }
3009            len += snprintf(tmpbuf + len, 4096 - len, "%s\n",
3010                            (extended_policy.timeshare == TRUE) ? \
3011                            "STANDARD" : "EXTENDED");
3012            break;
3013
3014        case THREAD_TIME_CONSTRAINT_POLICY:
3015            len += snprintf(tmpbuf + len, 4096 - len, "TIME_CONSTRAINT");
3016            thread_info_count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
3017            kr = thread_policy_get(the_thread, THREAD_TIME_CONSTRAINT_POLICY,
3018                                   (thread_policy_t)&time_constraint_policy,
3019                                   &thread_info_count, &get_default);
3020            if (kr != KERN_SUCCESS) {
3021                len += snprintf(tmpbuf + len, 4096 - len, "\n");
3022                break;
3023            }
3024            len += snprintf(tmpbuf + len, 4096 - len,
3025                            " (period=%u computation=%u constraint=%u "
3026                            "preemptible=%s)\n",
3027                            time_constraint_policy.period,
3028                            time_constraint_policy.computation,
3029                            time_constraint_policy.constraint,
3030                            (time_constraint_policy.preemptible == TRUE) ? \
3031                            "TRUE" : "FALSE");
3032            break;
3033
3034        case THREAD_PRECEDENCE_POLICY:
3035            len += snprintf(tmpbuf + len, 4096 - len, "PRECEDENCE");
3036            thread_info_count = THREAD_PRECEDENCE_POLICY;
3037            kr = thread_policy_get(the_thread, THREAD_PRECEDENCE_POLICY,
3038                                   (thread_policy_t)&precedence_policy,
3039                                   &thread_info_count, &get_default);
3040            if (kr != KERN_SUCCESS) {
3041                len += snprintf(tmpbuf + len, 4096 - len, "\n");
3042                break;
3043            }
3044            len += snprintf(tmpbuf + len, 4096 - len, " (importance=%u)\n",
3045                            precedence_policy.importance);
3046            break;
3047
3048        default:
3049            len = snprintf(tmpbuf, 4096, "UNKNOWN?\n");
3050            break;
3051        }
3052        goto gotdata;
3053    }
3054
3055    if (strcmp(whichfile, "run_state") == 0) {
3056        len = 0;
3057        len += snprintf(tmpbuf + len, 4096 - len, "%u",
3058                        basic_info_th->run_state);
3059        len += snprintf(tmpbuf + len, 4096 - len, " (%s)\n",
3060                        (basic_info_th->run_state >= THREAD_STATE_MAX) ? \
3061                        "?" : thread_states[basic_info_th->run_state]);
3062        goto gotdata;
3063    }
3064
3065    if (strcmp(whichfile, "sleep_time") == 0) {
3066        len = snprintf(tmpbuf, 4096, "%us\n", basic_info_th->sleep_time);
3067        goto gotdata;
3068    }
3069
3070    if (strcmp(whichfile, "suspend_count") == 0) {
3071        len = snprintf(tmpbuf, 4096, "%u\n", basic_info_th->suspend_count);
3072        goto gotdata;
3073    }
3074
3075    if (strcmp(whichfile, "system_time") == 0) {
3076        len = snprintf(tmpbuf, 4096, "%us %uus\n",
3077                       basic_info_th->system_time.seconds,
3078                       basic_info_th->system_time.microseconds);
3079        goto gotdata;
3080    }
3081
3082    if (strcmp(whichfile, "user_time") == 0) {
3083        len = snprintf(tmpbuf, 4096, "%us %uus\n",
3084                       basic_info_th->user_time.seconds,
3085                       basic_info_th->user_time.microseconds);
3086        goto gotdata;
3087    }
3088
3089gotdata:
3090
3091    FINI_THREAD_LIST();
3092
3093    READ_PROC_TASK_EPILOGUE();
3094}
3095
3096READ_HANDLER(proc__task__threads__thread__states__debug)
3097{
3098    READ_PROC_TASK_PROLOGUE();
3099    len = snprintf(tmpbuf, 4096, "not yet implemented\n");
3100    READ_PROC_TASK_EPILOGUE();
3101}
3102
3103READ_HANDLER(proc__task__threads__thread__states__exception)
3104{
3105    READ_PROC_TASK_PROLOGUE();
3106    len = snprintf(tmpbuf, 4096, "not yet implemented\n");
3107    READ_PROC_TASK_EPILOGUE();
3108}
3109
3110READ_HANDLER(proc__task__threads__thread__states__float)
3111{
3112    READ_PROC_TASK_PROLOGUE();
3113    DECL_THREAD_LIST();
3114    INIT_THREAD_LIST(the_task);
3115
3116    thread_t the_thread = MACH_PORT_NULL;
3117    unsigned int i = strtoul(argv[1], NULL, 16);
3118
3119    if (i < thread_count) {
3120        the_thread = thread_list[i];
3121    }
3122
3123    if (the_thread == MACH_PORT_NULL) {
3124        FINI_THREAD_LIST();
3125        return -ENOENT;
3126    }
3127
3128#if defined(__i386__)
3129    const char *whichfile = argv[2];
3130
3131    x86_float_state_t state = { 0 };
3132    unsigned int count = x86_FLOAT_STATE_COUNT;
3133    kr = thread_get_state(the_thread, x86_FLOAT_STATE, (thread_state_t)&state,
3134                          &count);
3135    if (kr != KERN_SUCCESS) {
3136        FINI_THREAD_LIST();
3137        return -EIO;
3138    }
3139
3140#define HANDLE_x86_FLOAT_STATE_ITEM(item, fmt)                      \
3141    if (strcmp(whichfile, #item) == 0) {                            \
3142        len = snprintf(tmpbuf, 4096, fmt, state.ufs.fs32.__##item); \
3143        goto gotdata;                                               \
3144    }
3145
3146    HANDLE_x86_FLOAT_STATE_ITEM(fpu_cs, "%hx\n");
3147    HANDLE_x86_FLOAT_STATE_ITEM(fpu_dp, "%x\n");
3148    HANDLE_x86_FLOAT_STATE_ITEM(fpu_ds, "%hx\n");
3149    HANDLE_x86_FLOAT_STATE_ITEM(fpu_fop, "%hx\n");
3150    HANDLE_x86_FLOAT_STATE_ITEM(fpu_ftw, "%hhx\n");
3151    HANDLE_x86_FLOAT_STATE_ITEM(fpu_ip, "%x\n");
3152    HANDLE_x86_FLOAT_STATE_ITEM(fpu_mxcsr, "%x\n");
3153    HANDLE_x86_FLOAT_STATE_ITEM(fpu_mxcsrmask, "%x\n");
3154
3155#define HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(bit)            \
3156    if (state.ufs.fs32.__fpu_fcw.__##bit) {                     \
3157        len += snprintf(tmpbuf + len, 4096 - len, "%s ", #bit); \
3158    }
3159
3160    if (strcmp(whichfile, "fpu_fcw") == 0) { /* control */
3161        len = 0;
3162        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(invalid);
3163        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(denorm);
3164        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(zdiv);
3165        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(ovrfl);
3166        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(undfl);
3167        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(precis);
3168        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(pc);
3169        switch (state.ufs.fs32.__fpu_fcw.__pc) {    
3170        case 0:
3171            len += snprintf(tmpbuf + len, 4096 - len, "(24B) ");
3172            break;
3173        case 2:
3174            len += snprintf(tmpbuf + len, 4096 - len, "(53B) ");
3175             break;
3176        case 3:
3177            len += snprintf(tmpbuf + len, 4096 - len, "(64B) ");
3178            break;
3179        }
3180        HANDLE_x86_FLOAT_STATE_ITEM_CONTROL_BIT(rc);
3181        switch (state.ufs.fs32.__fpu_fcw.__rc) {
3182        case 0:
3183            len += snprintf(tmpbuf + len, 4096 - len, "(round near) ");
3184            break;
3185        case 1:
3186            len += snprintf(tmpbuf + len, 4096 - len, "(round down) ");
3187            break;
3188        case 2:
3189            len += snprintf(tmpbuf + len, 4096 - len, "(round up) ");
3190            break;
3191        case 3:
3192            len += snprintf(tmpbuf + len, 4096 - len, "(chop) ");
3193            break;
3194        }
3195        len += snprintf(tmpbuf + len, 4096 - len, "\n");
3196        goto gotdata;
3197    }
3198
3199#define HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(bit)             \
3200    if (state.ufs.fs32.__fpu_fsw.__##bit) {                     \
3201        len += snprintf(tmpbuf + len, 4096 - len, "%s ", #bit); \
3202    }
3203
3204    if (strcmp(whichfile, "fpu_fsw") == 0) { /* status */
3205        len = 0;
3206        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(invalid);
3207        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(denorm);
3208        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(zdiv);
3209        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(ovrfl);
3210        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(undfl);
3211        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(precis);
3212        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(stkflt);
3213        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(errsumm);
3214        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(c0);
3215        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(c1);
3216        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(c2);
3217        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(c3);
3218        HANDLE_x86_FLOAT_STATE_ITEM_STATUS_BIT(busy);
3219        len += snprintf(tmpbuf + len, 4096 - len, "tos=%hhx\n",
3220                        state.ufs.fs32.__fpu_fsw.__tos);
3221        goto gotdata;
3222    }
3223
3224#else
3225    len = -1;
3226    goto gotdata;
3227#endif
3228
3229gotdata:
3230
3231    FINI_THREAD_LIST();
3232
3233    READ_PROC_TASK_EPILOGUE();
3234}
3235
3236READ_HANDLER(proc__task__threads__thread__states__thread)
3237{
3238    READ_PROC_TASK_PROLOGUE();
3239    DECL_THREAD_LIST();
3240    INIT_THREAD_LIST(the_task);
3241
3242    thread_t the_thread = MACH_PORT_NULL;
3243    unsigned int i = strtoul(argv[1], NULL, 16);
3244
3245    if (i < thread_count) {
3246        the_thread = thread_list[i];
3247    }
3248
3249    if (the_thread == MACH_PORT_NULL) {
3250        FINI_THREAD_LIST();
3251        return -ENOENT;
3252    }
3253
3254#if defined(__i386__)
3255
3256    const char *whichfile = argv[2];
3257
3258    x86_thread_state_t state = { 0 };
3259    unsigned int count = x86_THREAD_STATE_COUNT;
3260    kr = thread_get_state(the_thread, x86_THREAD_STATE, (thread_state_t)&state,
3261                          &count);
3262    if (kr != KERN_SUCCESS) {
3263        FINI_THREAD_LIST();
3264        return -EIO;
3265    }
3266
3267#define HANDLE_x86_THREAD_STATE_ITEM(item)                             \
3268    if (strcmp(whichfile, #item) == 0) {                               \
3269        len = snprintf(tmpbuf, 4096, "%x\n", state.uts.ts32.__##item); \
3270        goto gotdata;                                                  \
3271    }
3272
3273    HANDLE_x86_THREAD_STATE_ITEM(eax);
3274    HANDLE_x86_THREAD_STATE_ITEM(ebx);
3275    HANDLE_x86_THREAD_STATE_ITEM(ecx);
3276    HANDLE_x86_THREAD_STATE_ITEM(edx);
3277    HANDLE_x86_THREAD_STATE_ITEM(edi);
3278    HANDLE_x86_THREAD_STATE_ITEM(esi);
3279    HANDLE_x86_THREAD_STATE_ITEM(ebp);
3280    HANDLE_x86_THREAD_STATE_ITEM(esp);
3281    HANDLE_x86_THREAD_STATE_ITEM(ss);
3282    HANDLE_x86_THREAD_STATE_ITEM(eflags);
3283    HANDLE_x86_THREAD_STATE_ITEM(eip);
3284    HANDLE_x86_THREAD_STATE_ITEM(cs);
3285    HANDLE_x86_THREAD_STATE_ITEM(ds);
3286    HANDLE_x86_THREAD_STATE_ITEM(es);
3287    HANDLE_x86_THREAD_STATE_ITEM(fs);
3288    HANDLE_x86_THREAD_STATE_ITEM(gs);
3289
3290#else
3291    len = -1;
3292    goto gotdata;
3293#endif
3294
3295gotdata:
3296
3297    FINI_THREAD_LIST();
3298
3299    READ_PROC_TASK_EPILOGUE();
3300}
3301
3302READ_HANDLER(proc__task__tokens)
3303{
3304    READ_PROC_TASK_PROLOGUE();
3305
3306    unsigned int n;
3307    audit_token_t audit_token;
3308    security_token_t security_token;
3309    mach_msg_type_number_t task_info_count;
3310    const char *whichfile = argv[1];
3311
3312    if (strcmp(whichfile, "audit") == 0) {
3313        task_info_count = TASK_AUDIT_TOKEN_COUNT;
3314        kr = task_info(the_task, TASK_AUDIT_TOKEN,
3315                       (task_info_t)&audit_token, &task_info_count);
3316        len = -1;
3317        if (kr == KERN_SUCCESS) {
3318            len = 0;
3319            for (n = 0; n < sizeof(audit_token)/sizeof(uint32_t); n++) {
3320                len += snprintf(tmpbuf + len, 4096 - len, "%x ",
3321                                audit_token.val[n]);
3322            }
3323            len += snprintf(tmpbuf + len, 4096 - len, "\n");
3324        }
3325        goto gotdata;
3326    }
3327
3328    if (strcmp(whichfile, "security") == 0) {
3329        task_info_count = TASK_SECURITY_TOKEN_COUNT;
3330        kr = task_info(the_task, TASK_SECURITY_TOKEN,
3331                       (task_info_t)&security_token, &task_info_count);
3332        len = -1;
3333        if (kr == KERN_SUCCESS) {
3334            len = 0;
3335            for (n = 0; n < sizeof(security_token)/sizeof(uint32_t); n++) {
3336                len += snprintf(tmpbuf + len, 4096 - len, "%x ",
3337                                security_token.val[n]);
3338            }
3339            len += snprintf(tmpbuf + len, 4096 - len, "\n");
3340        }
3341        goto gotdata;
3342    }
3343
3344    return -ENOENT;
3345
3346gotdata:
3347
3348    READ_PROC_TASK_EPILOGUE();
3349}
3350
3351const char *
3352inheritance_strings[] = {
3353    "SHARE", "COPY", "NONE", "DONATE_COPY",
3354};
3355
3356const char *
3357behavior_strings[] = {
3358    "DEFAULT", "RANDOM", "SEQUENTIAL", "RESQNTL", "WILLNEED", "DONTNEED",
3359};
3360
3361READ_HANDLER(proc__task__vmmap)
3362{
3363    int len = -1;
3364    kern_return_t kr;
3365#define MAX_VMMAP_SIZE 65536 /* XXX */
3366    char tmpbuf[MAX_VMMAP_SIZE];
3367    task_t the_task;
3368    pid_t pid = strtol(argv[0], NULL, 10);
3369
3370    kr = task_for_pid(mach_task_self(), pid, &the_task);
3371    if (kr != KERN_SUCCESS) {
3372        return -EIO;
3373    }
3374
3375    vm_size_t vmsize;
3376    vm_address_t address;
3377    vm_region_basic_info_data_t info;
3378    mach_msg_type_number_t info_count;
3379    vm_region_flavor_t flavor; 
3380    memory_object_name_t object;
3381
3382    kr = KERN_SUCCESS;
3383    address = 0;
3384    len = 0;
3385
3386    do {
3387        flavor = VM_REGION_BASIC_INFO;
3388        info_count = VM_REGION_BASIC_INFO_COUNT;
3389        kr = vm_region(the_task, &address, &vmsize, flavor,
3390                       (vm_region_info_t)&info, &info_count, &object);
3391        if (kr == KERN_SUCCESS) {
3392            if (len >= MAX_VMMAP_SIZE) {
3393                goto gotdata;
3394            }
3395            len += snprintf(tmpbuf + len, MAX_VMMAP_SIZE - len,
3396            "%08x-%08x %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u\n",
3397                            address, (address + vmsize), (vmsize >> 10),
3398                            (info.protection & VM_PROT_READ)        ? 'r' : '-',
3399                            (info.protection & VM_PROT_WRITE)       ? 'w' : '-',
3400                            (info.protection & VM_PROT_EXECUTE)     ? 'x' : '-',
3401                            (info.max_protection & VM_PROT_READ)    ? 'r' : '-',
3402                            (info.max_protection & VM_PROT_WRITE)   ? 'w' : '-',
3403                            (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
3404                            inheritance_strings[info.inheritance],
3405                            (info.shared) ? "shared" : "-",
3406                            behavior_strings[info.behavior],
3407                            info.user_wired_count,
3408                            info.reserved);
3409            address += vmsize;
3410        } else if (kr != KERN_INVALID_ADDRESS) {
3411
3412            if (the_task != MACH_PORT_NULL) {
3413                mach_port_deallocate(mach_task_self(), the_task);
3414            }
3415
3416            return -EIO;
3417        }
3418    } while (kr != KERN_INVALID_ADDRESS);
3419
3420gotdata:
3421
3422    if (the_task != MACH_PORT_NULL) {
3423        mach_port_deallocate(mach_task_self(), the_task);
3424    }
3425
3426    READ_PROC_TASK_EPILOGUE();
3427}
3428
3429static int
3430M_get_vmmap_entries(task_t task)
3431{
3432    kern_return_t kr      = KERN_SUCCESS;
3433    vm_address_t  address = 0;
3434    vm_size_t     size    = 0;
3435    int           n       = 1;
3436
3437    while (1) {
3438        mach_msg_type_number_t count;
3439        struct vm_region_submap_info_64 info;
3440        uint32_t nesting_depth;
3441  
3442        count = VM_REGION_SUBMAP_INFO_COUNT_64;
3443        kr = vm_region_recurse_64(task, &address, &size, &nesting_depth,
3444                                  (vm_region_info_64_t)&info, &count);
3445        if (kr == KERN_INVALID_ADDRESS) {
3446            break;
3447        } else if (kr) {
3448            mach_error("vm_region:", kr);
3449            break; /* last region done */
3450        }
3451
3452        if (info.is_submap) {
3453            nesting_depth++;
3454        } else {
3455            address += size;
3456            n++;
3457        }
3458    }
3459
3460    return n;
3461}
3462
3463#define CAST_DOWN(type, addr) (((type)((uintptr_t)(addr))))
3464
3465static char *
3466get_user_tag_description(unsigned int user_tag)
3467{
3468    char *description = "unknown";
3469
3470    switch (user_tag) {
3471    
3472    case VM_MEMORY_MALLOC:
3473        description = "MALLOC";
3474        break;
3475    case VM_MEMORY_MALLOC_SMALL:
3476        description = "MALLOC_SMALL";
3477        break;
3478    case VM_MEMORY_MALLOC_LARGE:
3479        description = "MALLOC_LARGE";
3480        break;
3481    case VM_MEMORY_MALLOC_HUGE:
3482        description = "MALLOC_HUGE";
3483        break;
3484    case VM_MEMORY_SBRK:
3485        description = "SBRK";
3486        break;
3487    case VM_MEMORY_REALLOC:
3488        description = "REALLOC";
3489        break;
3490    case VM_MEMORY_MALLOC_TINY:
3491        description = "MALLOC_TINY";
3492        break;
3493    case VM_MEMORY_ANALYSIS_TOOL:
3494        description = "ANALYSIS_TOOL";
3495        break;
3496    case VM_MEMORY_MACH_MSG:
3497        description = "MACH_MSG";
3498        break;
3499    case VM_MEMORY_IOKIT:
3500        description = "IOKIT";
3501        break;
3502    case VM_MEMORY_STACK:
3503        description = "STACK";
3504        break;
3505    case VM_MEMORY_GUARD:
3506        description = "MEMORY_GUARD";
3507        break;
3508    case VM_MEMORY_SHARED_PMAP:
3509        description = "SHARED_PMAP";
3510        break;
3511    case VM_MEMORY_DYLIB:
3512        description = "DYLIB";
3513        break;
3514    case VM_MEMORY_APPKIT:
3515        description = "AppKit";
3516        break;
3517    case VM_MEMORY_FOUNDATION:
3518        description = "Foundation";
3519        break;
3520    case VM_MEMORY_COREGRAPHICS:
3521        description = "CoreGraphics";
3522        break;
3523    case VM_MEMORY_CARBON:
3524        description = "Carbon";
3525        break;
3526    case VM_MEMORY_JAVA:
3527        description = "Java";
3528        break;
3529    case VM_MEMORY_ATS:
3530        description = "ATS";
3531        break;
3532    case VM_MEMORY_DYLD:
3533        description = "DYLD";
3534        break;
3535    case VM_MEMORY_DYLD_MALLOC:
3536        description = "DYLD_MALLOC";
3537        break;
3538    case VM_MEMORY_APPLICATION_SPECIFIC_1:
3539        description = "APPLICATION_SPECIFIC_1";
3540        break;
3541    case VM_MEMORY_APPLICATION_SPECIFIC_16:
3542        description = "APPLICATION_SPECIFIC_16";
3543        break;
3544    default:
3545        break;
3546    }
3547
3548    return description;
3549}
3550
3551READ_HANDLER(proc__task__vmmap_r)
3552{ 
3553    int len = -1;
3554    kern_return_t kr;
3555    uint32_t nesting_depth = 0;
3556    struct vm_region_submap_info_64 vbr;
3557    mach_msg_type_number_t vbrcount = 0;
3558#define MAX_VMMAP_R_SIZE 262144 /* XXX */
3559    char tmpbuf[MAX_VMMAP_R_SIZE];
3560    task_t the_task;
3561    int segment_count;
3562    pid_t pid = strtol(argv[0], NULL, 10);
3563
3564    kr = task_for_pid(mach_task_self(), pid, &the_task);
3565    if (kr != KERN_SUCCESS) {
3566        return -EIO;
3567    }
3568
3569    mach_vm_size_t vmsize;
3570    mach_vm_address_t address;
3571
3572    kr = KERN_SUCCESS;
3573    address = 0;
3574    len = 0;
3575
3576    segment_count = M_get_vmmap_entries(the_task);
3577
3578    while (segment_count > 0) {
3579        while (1) { /* next region */
3580            vbrcount = VM_REGION_SUBMAP_INFO_COUNT_64;
3581            if ((kr = mach_vm_region_recurse(the_task, &address, &vmsize,
3582                                             &nesting_depth,
3583                                             (vm_region_recurse_info_t)&vbr,
3584                                             &vbrcount)) != KERN_SUCCESS) {
3585                break;
3586            }
3587            if (address + vmsize > VM_MAX_ADDRESS) {
3588                kr = KERN_INVALID_ADDRESS;
3589                break;
3590            }
3591            if (vbr.is_submap) {
3592                nesting_depth++;
3593                continue;
3594            } else {
3595                break;
3596            }
3597        } /* while (1) */
3598
3599        if (kr != KERN_SUCCESS) {
3600            if (kr != KERN_INVALID_ADDRESS) {
3601                if (the_task != MACH_PORT_NULL) {
3602                    mach_port_deallocate(mach_task_self(), the_task);
3603                }
3604                return -EIO;
3605            }
3606            break;
3607        }
3608
3609        if (len >= MAX_VMMAP_R_SIZE) {
3610            goto gotdata;
3611        }
3612
3613        /* XXX: 32-bit only */
3614
3615        len += snprintf(tmpbuf + len, MAX_VMMAP_R_SIZE - len,
3616            "%08x-%08x %8uK %c%c%c/%c%c%c ",
3617                        CAST_DOWN(uint32_t,address),
3618                        CAST_DOWN(uint32_t,(address + vmsize)),
3619                        CAST_DOWN(uint32_t,(vmsize >> 10)),
3620                        (vbr.protection & VM_PROT_READ)        ? 'r' : '-',
3621                        (vbr.protection & VM_PROT_WRITE)       ? 'w' : '-',
3622                        (vbr.protection & VM_PROT_EXECUTE)     ? 'x' : '-',
3623                        (vbr.max_protection & VM_PROT_READ)    ? 'r' : '-',
3624                        (vbr.max_protection & VM_PROT_WRITE)   ? 'w' : '-',
3625                        (vbr.max_protection & VM_PROT_EXECUTE) ? 'x' : '-');
3626
3627        if (vbr.is_submap) {
3628            len += snprintf(tmpbuf + len, MAX_VMMAP_R_SIZE - len,
3629                            "%20s %s\n", "(submap)",
3630                            get_user_tag_description(vbr.user_tag));
3631        } else {
3632            len += snprintf(tmpbuf + len, MAX_VMMAP_R_SIZE - len,
3633                            "%6d %6d %6d %s\n",
3634                            vbr.pages_resident,
3635                            vbr.pages_swapped_out,
3636                            vbr.pages_dirtied,
3637                            get_user_tag_description(vbr.user_tag));
3638        }
3639
3640        address += vmsize;
3641        segment_count--;
3642
3643    } /* while (segment_count > 0) */
3644
3645gotdata:
3646
3647    if (the_task != MACH_PORT_NULL) {
3648        mach_port_deallocate(mach_task_self(), the_task);
3649    }
3650
3651    READ_PROC_TASK_EPILOGUE();
3652}
3653
3654READ_HANDLER(proc__windows__generic)
3655{
3656    pid_t pid = atoi(argv[0]);
3657    const char *whichfile = argv[1];
3658    ProcessSerialNumber psn;
3659
3660    OSStatus status = GetProcessForPID(pid, &psn);
3661    if (status != noErr) {
3662        return 0; /* technically not an error in this case */
3663    }
3664
3665    CGSConnectionID conn;
3666    CGError err = CGSGetConnectionIDForPSN(0, &psn, &conn);
3667    if (err != kCGErrorSuccess) {
3668        return 0; /* just be nice */
3669    }
3670
3671#define MAX_WINDOWS 256
3672    CGSWindowID windowIDs[MAX_WINDOWS];
3673    int windowCount = 0;
3674
3675    if (strcmp(whichfile, "all") == 0) {
3676        err = CGSGetWindowList(_CGSDefaultConnection(), conn, MAX_WINDOWS,
3677                               windowIDs, &windowCount);
3678    } else if (strcmp(whichfile, "onscreen") == 0) {
3679        err = CGSGetOnScreenWindowList(_CGSDefaultConnection(), conn,
3680                                       MAX_WINDOWS, windowIDs, &windowCount);
3681    }
3682
3683    if (err != kCGErrorSuccess) {
3684        return -EIO;
3685    }
3686
3687    if (windowCount == 0) {
3688        return 0;
3689    }
3690
3691#define MAX_WINDOWDATA 16384
3692    char tmpbuf[MAX_WINDOWDATA];
3693    int i, len = 0;
3694
3695    for (i = 0; i < windowCount; i++) { 
3696
3697        if (len > MAX_WINDOWDATA) {
3698           goto gotdata;
3699        }
3700
3701        CGRect rect;
3702        err = CGSGetScreenRectForWindow(_CGSDefaultConnection(), windowIDs[i],
3703                                        &rect);
3704        CGWindowLevel level;
3705        CGError err2 = CGSGetWindowLevel(_CGSDefaultConnection(), windowIDs[i],
3706                                         &level);
3707        len += snprintf(tmpbuf + len, MAX_WINDOWDATA - len,
3708                        "%-4d %-6x %.0f x %.0f @ (%.0f, %.0f, %d)\n",
3709                        i + 1, windowIDs[i],
3710                        (err == kCGErrorSuccess)  ? rect.size.width  : -1,
3711                        (err == kCGErrorSuccess)  ? rect.size.height : -1,
3712                        (err == kCGErrorSuccess)  ? rect.origin.x    : -1,
3713                        (err == kCGErrorSuccess)  ? rect.origin.y    : -1,
3714                        (err2 == kCGErrorSuccess) ? level            : -1);
3715    }
3716
3717gotdata:
3718
3719    if (offset < len) {
3720        if (offset + size > len)
3721            size = len - offset;
3722        memcpy(buf, tmpbuf + offset, size);
3723    } else
3724        size = 0;
3725
3726    return size;
3727}
3728
3729READ_HANDLER(proc__windows__screenshots__window) 
3730{
3731    if (fi->fh == 0) {
3732        return 0;
3733    }
3734
3735    struct ProcfsWindowData *pwd = (struct ProcfsWindowData *)fi->fh;
3736
3737    CFMutableDataRef window_png = pwd->window_png;
3738    size_t max_len = pwd->max_len;
3739    size_t len = pwd->len;
3740
3741    if (len > max_len) {
3742        return -EIO;
3743    }
3744
3745    CFDataSetLength(window_png, max_len);
3746    len = max_len;
3747
3748    const UInt8 *tmpbuf = CFDataGetBytePtr(window_png);
3749        
3750    if (len < 0) {
3751        return -EIO; 
3752    }
3753
3754    if (offset < len) {
3755        if (offset + size > len)
3756            size = len - offset;
3757        memcpy(buf, tmpbuf + offset, size);
3758    } else
3759        size = 0;
3760
3761    return size;
3762}
3763
3764READ_HANDLER(proc__xcred)
3765{
3766    pid_t pid = atoi(argv[0]);
3767    const char *whichfile = argv[2];
3768    struct kinfo_proc kp;
3769    int len;
3770    char tmpbuf[4096];
3771    struct passwd *p;
3772    struct group *g;
3773
3774    len = procinfo(pid, &kp);
3775    if (len != 0) {
3776        return -EIO;
3777    }
3778
3779    len = -1;
3780
3781    if (strcmp(whichfile, "groups") == 0) {
3782        short n;
3783        len = 0;
3784        for (n = 0; n < kp.kp_eproc.e_ucred.cr_ngroups; n++) {
3785            g = getgrgid(kp.kp_eproc.e_ucred.cr_groups[n]);
3786            len += snprintf(tmpbuf + len, 4096 - len, "%d(%s) ",
3787                            kp.kp_eproc.e_ucred.cr_groups[n],
3788                            (g) ? g->gr_name : "?");
3789        }
3790        len += snprintf(tmpbuf + len, 4096 - len, "\n");
3791        goto gotdata;
3792    }   
3793
3794    if (strcmp(whichfile, "rgid") == 0) {
3795        g = getgrgid(kp.kp_eproc.e_pcred.p_rgid);
3796        len = snprintf(tmpbuf, 4096, "%d(%s)\n", kp.kp_eproc.e_pcred.p_rgid,
3797                       (g) ? g->gr_name : "?");
3798        goto gotdata;
3799    }
3800
3801    if (strcmp(whichfile, "svgid") == 0) {
3802        g = getgrgid(kp.kp_eproc.e_pcred.p_svgid);
3803        len = snprintf(tmpbuf, 4096, "%d(%s)\n", kp.kp_eproc.e_pcred.p_svgid,
3804                       (g) ? g->gr_name : "?");
3805        goto gotdata;
3806    }
3807
3808    if (strcmp(whichfile, "ruid") == 0) {
3809        p = getpwuid(kp.kp_eproc.e_pcred.p_ruid);
3810        len = snprintf(tmpbuf, 4096, "%d(%s)\n", kp.kp_eproc.e_pcred.p_ruid,
3811                       (p) ? p->pw_name : "?");
3812        goto gotdata;
3813    }
3814
3815    if (strcmp(whichfile, "svuid") == 0) {
3816        p = getpwuid(kp.kp_eproc.e_pcred.p_svuid);
3817        len = snprintf(tmpbuf, 4096, "%d(%s)\n", kp.kp_eproc.e_pcred.p_svuid,
3818                       (p) ? p->pw_name : "?");
3819        goto gotdata;
3820    }
3821
3822    if (strcmp(whichfile, "uid") == 0) {
3823        p = getpwuid(kp.kp_eproc.e_ucred.cr_uid);
3824        len = snprintf(tmpbuf, 4096, "%d(%s)\n", kp.kp_eproc.e_ucred.cr_uid,
3825                       (p) ? p->pw_name : "?");
3826        goto gotdata;
3827    }
3828
3829gotdata:
3830    
3831    if (len < 0) {
3832        return -EIO;
3833    }
3834
3835    if (offset < len) {
3836        if (offset + size > len)
3837            size = len - offset;
3838        memcpy(buf, tmpbuf + offset, size);
3839    } else
3840        size = 0;
3841
3842    return size;
3843}
3844
3845// END: READ
3846
3847
3848// BEGIN: READDIR
3849
3850//    int
3851//    procfs_readdir_<handler>(procfs_dispatcher_entry_t *e,
3852//                             const char                *argv[],
3853//                             void                      *buf,
3854//                             fuse_fill_dir_t            filler,
3855//                             off_t                      offset,
3856//                             struct fuse_file_info     *fi)
3857
3858
3859int
3860procfs_populate_directory(const char           **content_files,
3861                          const char           **content_directories,
3862                          void                  *buf,
3863                          fuse_fill_dir_t        filler,
3864                          off_t                  offset,
3865                          struct fuse_file_info *fi)
3866{
3867    int    bufferfull = 0;
3868    struct stat dir_stat;
3869    struct stat file_stat;
3870    const char **name;
3871
3872    memset(&dir_stat, 0, sizeof(dir_stat));
3873    dir_stat.st_mode = S_IFDIR | 0555;
3874    dir_stat.st_size = 0;
3875
3876    memset(&file_stat, 0, sizeof(file_stat));
3877    dir_stat.st_mode = S_IFREG | 0444;
3878    dir_stat.st_size = 0;
3879
3880    if (filler(buf, ".", NULL, 0)) {
3881        bufferfull = 1;
3882        goto out;
3883    }
3884
3885    if (filler(buf, "..", NULL, 0)) {
3886        bufferfull = 1;
3887        goto out;
3888    }
3889
3890    if (!content_files && !content_directories) {
3891        goto out;
3892    }
3893
3894    name = content_directories;
3895    if (name) {
3896        for (; *name; name++) {
3897            if (filler(buf, *name, &dir_stat, 0)) {
3898                bufferfull = 1;
3899                goto out;
3900            }
3901        }
3902    }
3903
3904    name = content_files;
3905    if (name) {
3906        for (; *name; name++) {
3907            if (filler(buf, *name, &file_stat, 0)) {
3908                bufferfull = 1;
3909                goto out;
3910            }
3911        }
3912    }
3913
3914    if (procfs_ui) {
3915        name = content_files;
3916        if (name) {
3917            for (; *name; name++) {
3918                char dot_name[MAXPATHLEN + 1];
3919                snprintf(dot_name, MAXPATHLEN, "._%s", *name);
3920                if (filler(buf, dot_name, &file_stat, 0)) {
3921                    bufferfull = 1;
3922                    goto out;
3923                }
3924            }
3925        }
3926    }
3927
3928out:
3929    return bufferfull;
3930}
3931
3932
3933READDIR_HANDLER(enotdir)
3934{
3935    return -ENOTDIR;
3936}
3937
3938READDIR_HANDLER(default)
3939{
3940    return 0;
3941}
3942
3943READDIR_HANDLER(root)
3944{
3945    unsigned int i;
3946    kern_return_t kr;
3947    char the_name[MAXNAMLEN + 1];  
3948    struct stat dir_stat;
3949    pid_t pid;
3950    DECL_TASK_LIST();
3951
3952    INIT_TASK_LIST();
3953    for (i = 0; i < task_count; i++) {
3954        memset(&dir_stat, 0, sizeof(dir_stat));
3955        dir_stat.st_mode = S_IFDIR | 0755;
3956        dir_stat.st_size = 0;
3957        kr = pid_for_task(task_list[i], &pid);
3958        if (kr != KERN_SUCCESS) {
3959            continue;
3960        }
3961        snprintf(the_name, MAXNAMLEN, "%d", pid);
3962        if (filler(buf, the_name, &dir_stat, 0)) {
3963            break;
3964        }
3965    }
3966    FINI_TASK_LIST();
3967
3968    return 0;
3969}
3970
3971READDIR_HANDLER(byname)
3972{
3973    int len;
3974    char the_name[MAXNAMLEN + 1];  
3975    Boolean strstatus = false;
3976    struct stat the_stat;
3977
3978    ProcessSerialNumber psn;
3979    OSErr osErr = noErr;
3980    OSStatus status;
3981    CFStringRef Pname;
3982    pid_t Pid;
3983
3984    psn.highLongOfPSN = kNoProcess;
3985    psn.lowLongOfPSN  = kNoProcess;
3986    memset(&the_stat, 0, sizeof(the_stat));
3987
3988    while ((osErr = GetNextProcess(&psn)) != procNotFound) {
3989        status = GetProcessPID(&psn, &Pid);
3990        if (status != noErr) {
3991            continue;
3992        }
3993        Pname = (CFStringRef)0;
3994        status = CopyProcessName(&psn, &Pname);
3995        if (status != noErr) {
3996            if (Pname) {
3997                CFRelease(Pname);
3998                Pname = (CFStringRef)0;
3999            }
4000            continue;
4001        }
4002        the_stat.st_mode = S_IFLNK | 0755;
4003        the_stat.st_nlink = 1;
4004        len = snprintf(the_name, MAXNAMLEN, "../%u", Pid);
4005        the_stat.st_size = len;
4006
4007        strstatus = CFStringGetCString(Pname, the_name, MAXNAMLEN,
4008                                       kCFStringEncodingASCII);
4009        if (strstatus == false) {
4010            CFRelease(Pname);
4011            Pname = (CFStringRef)0;
4012            continue;
4013        }
4014
4015        if (filler(buf, the_name, &the_stat, 0)) {
4016            CFRelease(Pname);
4017            break;
4018        }
4019        CFRelease(Pname);
4020    }
4021
4022    return 0;
4023}
4024
4025READDIR_HANDLER(system__hardware__cpus)
4026{
4027    int len;
4028    unsigned int i;
4029    char the_name[MAXNAMLEN + 1];  
4030    struct stat the_stat;
4031
4032    memset(&the_stat, 0, sizeof(the_stat));
4033
4034    for (i = 0; i < processor_count; i++) {
4035        the_stat.st_mode = S_IFDIR | 0555;
4036        the_stat.st_nlink = 1;
4037        len = snprintf(the_name, MAXNAMLEN, "%d", i);
4038        if (filler(buf, the_name, &the_stat, 0)) {
4039            break;
4040        }
4041    }
4042
4043    return 0;
4044}
4045
4046READDIR_HANDLER(system__hardware__cpus__cpu)
4047{
4048    return 0;
4049}
4050
4051READDIR_HANDLER(system__hardware__displays)
4052{
4053    int len;
4054    unsigned int i;
4055    char the_name[MAXNAMLEN + 1];
4056    struct stat the_stat;
4057    CGDisplayCount display_count = PROCFS_GetDisplayCount();
4058
4059    memset(&the_stat, 0, sizeof(the_stat));
4060
4061    for (i = 0; i < display_count; i++) {
4062        the_stat.st_mode = S_IFDIR | 0555;
4063        the_stat.st_nlink = 1;
4064        len = snprintf(the_name, MAXNAMLEN, "%d", i);
4065        if (filler(buf, the_name, &the_stat, 0)) {
4066            break;
4067        }
4068    }
4069
4070    return 0;
4071
4072}
4073
4074READDIR_HANDLER(system__hardware__displays__display)
4075{
4076    unsigned long index = strtol(argv[0], NULL, 10);
4077    CGDisplayCount display_count = PROCFS_GetDisplayCount();
4078
4079    if (index >= display_count) {
4080        return -ENOENT;
4081    }
4082
4083    return 0;
4084}
4085
4086READDIR_HANDLER(system__hardware__tpm__keyslots)
4087{
4088#if MACFUSE_PROCFS_ENABLE_TPM
4089    unsigned int i, len;
4090    char the_name[MAXNAMLEN + 1];  
4091    struct stat the_stat;
4092    uint32_t keys[256];
4093
4094    uint16_t slots_used = 0;
4095    uint32_t slots_free = 0;
4096    uint32_t slots_total = 0;
4097
4098    if (TPM_GetCapability_Slots(&slots_free)) {
4099        return -ENOENT;
4100    }
4101
4102    if (TPM_GetCapability_Key_Handle(&slots_used, keys)) {
4103        return -ENOENT;
4104    }
4105
4106    slots_total = slots_used + slots_free;
4107
4108    memset(&the_stat, 0, sizeof(the_stat));
4109
4110    for (i = 0; i < slots_total; i++) {
4111        len = snprintf(the_name, MAXNAMLEN, "key%02d", i);
4112        if (i >= slots_used) {
4113            the_stat.st_size = 0;
4114            the_stat.st_mode = S_IFREG | 0000;
4115        } else {
4116            the_stat.st_size = 4096;
4117            the_stat.st_mode = S_IFREG | 0444;
4118        }
4119        if (filler(buf, the_name, &the_stat, 0)) {
4120            break;
4121        }
4122    }
4123#endif
4124
4125    return 0;
4126}
4127
4128READDIR_HANDLER(system__hardware__tpm__pcrs)
4129{
4130#if MACFUSE_PROCFS_ENABLE_TPM
4131    unsigned int i, len;
4132    uint32_t pcrs;
4133    char the_name[MAXNAMLEN + 1];  
4134    struct stat the_stat;
4135
4136    if (TPM_GetCapability_Pcrs(&pcrs)) {
4137        return -ENOENT;
4138    }
4139
4140    memset(&the_stat, 0, sizeof(the_stat));
4141
4142    for (i = 0; i < pcrs; i++) {
4143        len = snprintf(the_name, MAXNAMLEN, "pcr%02d", i);
4144        the_stat.st_size = 4096;
4145        the_stat.st_mode = S_IFREG | 0444;
4146        if (filler(buf, the_name, &the_stat, 0)) {
4147            break;
4148        }
4149    }
4150#endif
4151
4152    return 0;
4153}
4154
4155READDIR_HANDLER(proc__task__ports)
4156{
4157    unsigned int i;
4158    kern_return_t kr;
4159    DECL_PORT_LIST();
4160    pid_t pid = strtol(argv[0], NULL, 10);
4161    struct stat dir_stat;
4162    char the_name[MAXNAMLEN + 1];
4163    task_t the_task = MACH_PORT_NULL;
4164
4165    kr = task_for_pid(mach_task_self(), pid, &the_task);
4166    if (kr != KERN_SUCCESS) {
4167        return -ENOENT;
4168    }
4169
4170    memset(&dir_stat, 0, sizeof(dir_stat));
4171    dir_stat.st_mode = S_IFDIR | 0755;
4172    dir_stat.st_size = 0;
4173
4174    INIT_PORT_LIST(the_task);
4175    for (i = 0; i < name_count; i++) {
4176        snprintf(the_name, MAXNAMLEN, "%x", name_list[i]);
4177        if (filler(buf, the_name, &dir_stat, 0)) {
4178            break;
4179        }
4180    }
4181    FINI_PORT_LIST();
4182
4183    if (the_task != MACH_PORT_NULL) {
4184        mach_port_deallocate(mach_task_self(), the_task);
4185    }
4186
4187    return 0;
4188}
4189
4190READDIR_HANDLER(proc__task__threads)
4191{
4192    unsigned int i;
4193    kern_return_t kr;
4194    DECL_THREAD_LIST();
4195    pid_t pid = strtol(argv[0], NULL, 10);
4196    struct stat dir_stat;
4197    char the_name[MAXNAMLEN + 1];
4198    task_t the_task = MACH_PORT_NULL;
4199
4200    kr = task_for_pid(mach_task_self(), pid, &the_task);
4201    if (kr != KERN_SUCCESS) {
4202        return -ENOENT;
4203    }
4204
4205    memset(&dir_stat, 0, sizeof(dir_stat));
4206    dir_stat.st_mode = S_IFDIR | 0755;
4207    dir_stat.st_size = 0;
4208
4209    INIT_THREAD_LIST(the_task);
4210    FINI_THREAD_LIST();
4211
4212    for (i = 0; i < thread_count; i++) {
4213        snprintf(the_name, MAXNAMLEN, "%x", i);
4214        if (filler(buf, the_name, &dir_stat, 0)) {
4215            break;
4216        }
4217    }
4218
4219    if (the_task != MACH_PORT_NULL) {
4220        mach_port_deallocate(mach_task_self(), the_task);
4221    }
4222
4223    return 0;
4224}
4225
4226READDIR_HANDLER(proc__windows__screenshots)
4227{
4228    int i;
4229    pid_t pid = strtol(argv[0], NULL, 10);
4230    struct stat dir_stat;
4231    char the_name[MAXNAMLEN + 1];
4232
4233    ProcessSerialNumber psn;
4234
4235    OSStatus status = GetProcessForPID(pid, &psn);
4236    if (status != noErr) {
4237        return 0; /* technically not an error in this case */
4238    }
4239
4240    memset(&dir_stat, 0, sizeof(dir_stat));
4241    dir_stat.st_mode = S_IFDIR | 0755;
4242    dir_stat.st_size = 0;
4243
4244    CGSConnectionID conn;
4245    CGError err = CGSGetConnectionIDForPSN(0, &psn, &conn);
4246    if (err != kCGErrorSuccess) {
4247        return 0; /* just be nice */
4248    }
4249
4250#define MAX_WINDOWS 256
4251    CGSWindowID windowIDs[MAX_WINDOWS];
4252    int windowCount = 0;
4253
4254    err = CGSGetOnScreenWindowList(_CGSDefaultConnection(), conn,
4255                                   MAX_WINDOWS, windowIDs, &windowCount);
4256
4257    if (err != kCGErrorSuccess) {
4258        return -EIO;
4259    }
4260
4261    if (windowCount == 0) {
4262        return 0;
4263    }
4264
4265    for (i = 0; i < windowCount; i++) {
4266        snprintf(the_name, MAXNAMLEN, "%x.png", windowIDs[i]);
4267        dir_stat.st_mode = S_IFREG | 0444;
4268        dir_stat.st_size = PROCFS_GetPNGSizeForWindowAtIndex(windowIDs[i]);
4269        if (filler(buf, the_name, &dir_stat, 0)) {
4270            break;
4271        }
4272    }
4273
4274    return 0;
4275}
4276
4277// END: READDIR
4278
4279
4280// BEGIN: READLINK
4281
4282//    int
4283//    procfs_readlink_<handler>(procfs_dispatcher_entry_t  e,
4284//                              const char                *argv[],
4285//                              char                      *buf,
4286//                              size_t                     size)
4287
4288READLINK_HANDLER(einval)
4289{
4290    return -EINVAL;
4291}
4292
4293READLINK_HANDLER(byname__name)
4294{
4295    const char *target_Pname = argv[0];
4296    char the_name[MAXNAMLEN + 1];  
4297    Boolean strstatus = false;
4298
4299    ProcessSerialNumber psn;
4300    OSErr osErr = noErr;
4301    OSStatus status;
4302    CFStringRef Pname;
4303    pid_t Pid;
4304
4305    psn.highLongOfPSN = kNoProcess;
4306    psn.lowLongOfPSN  = kNoProcess;
4307
4308    while ((osErr = GetNextProcess(&psn)) != procNotFound) {
4309        status = GetProcessPID(&psn, &Pid);
4310        if (status != noErr) {
4311            continue;
4312        }
4313        Pname = (CFStringRef)0;
4314        status = CopyProcessName(&psn, &Pname);
4315        if (status != noErr) {
4316            if (Pname) {
4317                CFRelease(Pname);
4318                Pname = (CFStringRef)0;
4319            }
4320            continue;
4321        }
4322
4323        strstatus = CFStringGetCString(Pname, the_name, MAXNAMLEN,
4324                                       kCFStringEncodingASCII);
4325
4326        if (strcmp(target_Pname, the_name) != 0) {
4327            Pid = 0;
4328        }
4329
4330        CFRelease(Pname);
4331        Pname = (CFStringRef)0;
4332
4333        if (Pid) {
4334            break;
4335        }
4336    }
4337
4338    if (!Pid) {
4339        return -ENOENT;
4340    }
4341
4342    (void)snprintf(the_name, MAXNAMLEN, "../%u", Pid);
4343
4344    strncpy(buf, the_name, size - 1);
4345
4346    return 0;
4347}
4348
4349// END: READLINK
4350
4351
4352#define DEBUG 1
4353#ifdef DEBUG
4354#define TRACEME() { fprintf(stderr, "%s: path=%s\n", __FUNCTION__, path); }
4355#else
4356#define TRACEME() { }
4357#endif
4358
4359#define EXIT_ON_MACH_ERROR(msg, retval) \
4360    if (kr != KERN_SUCCESS) { mach_error(msg ":" , kr); exit((retval)); }
4361
4362static void *
4363procfs_init(struct fuse_conn_info *conn)
4364{
4365    int i;
4366    kern_return_t kr;
4367
4368    kr = processor_set_default(mach_host_self(), &p_default_set);
4369    EXIT_ON_MACH_ERROR("processor_default", 1);
4370   
4371    kr = host_processor_set_priv(mach_host_self(), p_default_set,
4372                                 &p_default_set_control);
4373    EXIT_ON_MACH_ERROR("host_processor_set_priv", 1);
4374
4375    kr = host_get_host_priv_port(mach_host_self(), &host_priv);
4376    EXIT_ON_MACH_ERROR("host_get_host_priv_port", 1);
4377   
4378    processor_list = (processor_port_array_t)0;
4379    kr = host_processors(host_priv, &processor_list, &processor_count);
4380    EXIT_ON_MACH_ERROR("host_processors", 1);
4381
4382    io_service_t serviceObject;
4383
4384    serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault,
4385                        IOServiceMatching("AppleLMUController"));
4386    if (serviceObject) {
4387        kr = IOServiceOpen(serviceObject, mach_task_self(), 0,
4388                           &lightsensor_port);
4389        IOObjectRelease(serviceObject);
4390        if (kr != KERN_SUCCESS) {
4391            lightsensor_port = 0;
4392        }
4393    }
4394
4395    kr = KERN_FAILURE;
4396    CFDictionaryRef classToMatch;
4397    MotionSensorData_t sms_data;
4398
4399    for (i = 0; i <= sms_maxConfigurationID; i++) {
4400
4401        sms_gIndex = SMS_CONFIGURATIONS[i].index;
4402        classToMatch = IOServiceMatching(SMS_CONFIGURATIONS[i].classname);
4403        sms_gStructureInputSize = SMS_CONFIGURATIONS[i].structureInputSize;
4404        sms_gStructureOutputSize = SMS_CONFIGURATIONS[i].structureOutputSize;
4405        sms_configurationID = i;
4406
4407        serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault,
4408                                                    classToMatch);
4409        if (!serviceObject) {
4410            continue;
4411        }
4412
4413        kr = IOServiceOpen(serviceObject, mach_task_self(), 0,
4414                           &motionsensor_port);
4415        IOObjectRelease(serviceObject);
4416        if (kr != KERN_SUCCESS) {
4417            continue;
4418        }
4419
4420        kr = sms_getOrientation_hardware_apple(&sms_data);
4421        if (kr != KERN_SUCCESS) {
4422            IOServiceClose(motionsensor_port);
4423            motionsensor_port = 0;
4424            continue;
4425        } else {
4426            break;
4427        }
4428    }
4429
4430    total_file_patterns =
4431        sizeof(procfs_file_table)/sizeof(struct procfs_dispatcher_entry);
4432    total_directory_patterns =
4433        sizeof(procfs_directory_table)/sizeof(struct procfs_dispatcher_entry);
4434    total_link_patterns =
4435        sizeof(procfs_link_table)/sizeof(struct procfs_dispatcher_entry);
4436   
4437    pthread_mutex_init(&camera_lock, NULL);
4438    pthread_mutex_init(&display_lock, NULL);
4439
4440    camera_tiff = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)0);
4441
4442    return NULL;
4443}
4444
4445static void
4446procfs_destroy(void *arg)
4447{
4448    (void)mach_port_deallocate(mach_task_self(), p_default_set);
4449    (void)mach_port_deallocate(mach_task_self(), p_default_set_control);
4450
4451    pthread_mutex_destroy(&camera_lock);
4452    pthread_mutex_destroy(&display_lock);
4453
4454    CFRelease(camera_tiff);
4455}
4456
4457#define PROCFS_OPEN_RELEASE_COMMON()                                          \
4458    int i;                                                                    \
4459    procfs_dispatcher_entry_t e;                                              \
4460    string arg1, arg2, arg3;                                                  \
4461    const char *real_argv[PROCFS_MAX_ARGS];                                   \
4462                                                                              \
4463    if (valid_process_pattern->PartialMatch(path, &arg1)) {                   \
4464        pid_t check_pid = atoi(arg1.c_str());                                 \
4465        if (getpgid(check_pid) == -1) {                                       \
4466            return -ENOENT;                                                   \
4467        }                                                                     \
4468    }                                                                         \
4469                                                                              \
4470    for (i = 0; i < PROCFS_MAX_ARGS; i++) {                                   \
4471        real_argv[i] = (char *)0;                                             \
4472    }                                                                         \
4473                                                                              \
4474    for (i = 0; i < total_file_patterns; i++) {                               \
4475        e = &procfs_file_table[i];                                            \
4476        if ((e->flag & PROCFS_FLAG_ISDOTFILE) & !procfs_ui) {                 \
4477            continue;                                                         \
4478        }                                                                     \
4479        switch (e->argc) {                                                    \
4480        case 0:                                                               \
4481            if (e->compiled_pattern->FullMatch(path)) {                       \
4482                goto out;                                                     \
4483            }                                                                 \
4484            break;                                                            \
4485                                                                              \
4486        case 1:                                                               \
4487            if (e->compiled_pattern->FullMatch(path, &arg1)) {                \
4488                real_argv[0] = arg1.c_str();                                  \
4489                goto out;                                                     \
4490            }                                                                 \
4491            break;                                                            \
4492                                                                              \
4493        case 2:                                                               \
4494            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {         \
4495                real_argv[0] = arg1.c_str();                                  \
4496                real_argv[1] = arg2.c_str();                                  \
4497                goto out;                                                     \
4498            }                                                                 \
4499            break;                                                            \
4500                                                                              \
4501        case 3:                                                               \
4502            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {  \
4503                real_argv[0] = arg1.c_str();                                  \
4504                real_argv[1] = arg2.c_str();                                  \
4505                real_argv[2] = arg3.c_str();                                  \
4506                goto out;                                                     \
4507            }                                                                 \
4508            break;                                                            \
4509                                                                              \
4510        default:                                                              \
4511            break;                                                            \
4512        }                                                                     \
4513    }                                                                         \
4514                                                                              \
4515    for (i = 0; i < total_link_patterns; i++) {                               \
4516        e = &procfs_link_table[i];                                            \
4517        switch (e->argc) {                                                    \
4518        case 0:                                                               \
4519            if (e->compiled_pattern->FullMatch(path)) {                       \
4520                goto out;                                                     \
4521            }                                                                 \
4522            break;                                                            \
4523                                                                              \
4524        case 1:                                                               \
4525            if (e->compiled_pattern->FullMatch(path, &arg1)) {                \
4526                real_argv[0] = arg1.c_str();                                  \
4527                goto out;                                                     \
4528            }                                                                 \
4529            break;                                                            \
4530                                                                              \
4531        case 2:                                                               \
4532            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {         \
4533                real_argv[0] = arg1.c_str();                                  \
4534                real_argv[1] = arg2.c_str();                                  \
4535                goto out;                                                     \
4536            }                                                                 \
4537            break;                                                            \
4538                                                                              \
4539        case 3:                                                               \
4540            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {  \
4541                real_argv[0] = arg1.c_str();                                  \
4542                real_argv[1] = arg2.c_str();                                  \
4543                real_argv[2] = arg3.c_str();                                  \
4544                goto out;                                                     \
4545            }                                                                 \
4546            break;                                                            \
4547                                                                              \
4548        default:                                                              \
4549            break;                                                            \
4550        }                                                                     \
4551    }                                                                         \
4552                                                                              \
4553    return -ENOENT;                                                           \
4554                                                                              \
4555out:                                                                          \
4556
4557static int
4558procfs_open(const char *path, struct fuse_file_info *fi)
4559{
4560    PROCFS_OPEN_RELEASE_COMMON()
4561
4562    return e->open(e, real_argv, path, fi);
4563}
4564
4565static int
4566procfs_release(const char *path, struct fuse_file_info *fi)
4567{
4568    PROCFS_OPEN_RELEASE_COMMON()
4569
4570    return e->release(e, real_argv, path, fi);
4571}
4572
4573static int
4574procfs_opendir(const char *path, struct fuse_file_info *fi)
4575{
4576    return 0;
4577}
4578
4579static int
4580procfs_releasedir(const char *path, struct fuse_file_info *fi)
4581{
4582    return 0;
4583}
4584
4585static int
4586procfs_getattr(const char *path, struct stat *stbuf)
4587{
4588    int i;
4589    procfs_dispatcher_entry_t e;
4590    string arg1, arg2, arg3;
4591    const char *real_argv[PROCFS_MAX_ARGS];
4592
4593    if (valid_process_pattern->PartialMatch(path, &arg1)) {
4594        pid_t check_pid = atoi(arg1.c_str());
4595        if (getpgid(check_pid) == -1) {
4596            return -ENOENT;
4597        }
4598    }
4599
4600    for (i = 0; i < PROCFS_MAX_ARGS; i++) {
4601        real_argv[i] = (char *)0;
4602    }
4603
4604    for (i = 0; i < total_directory_patterns; i++) {
4605        e = &procfs_directory_table[i];
4606        switch (e->argc) {
4607        case 0:
4608            if (e->compiled_pattern->FullMatch(path)) {
4609                goto out;
4610            }
4611            break;
4612
4613        case 1:
4614            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4615                real_argv[0] = arg1.c_str();
4616                goto out;
4617            }
4618            break;
4619
4620        case 2:
4621            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4622                real_argv[0] = arg1.c_str();
4623                real_argv[1] = arg2.c_str();
4624                goto out;
4625            }
4626            break;
4627
4628        case 3:
4629            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {
4630                real_argv[0] = arg1.c_str();
4631                real_argv[1] = arg2.c_str();
4632                real_argv[2] = arg3.c_str();
4633                goto out;
4634            }
4635            break;
4636
4637        default:
4638            break;
4639        }
4640    }
4641
4642    for (i = 0; i < total_file_patterns; i++) {
4643        e = &procfs_file_table[i];
4644        if ((e->flag & PROCFS_FLAG_ISDOTFILE) & !procfs_ui) {
4645            continue;
4646        }
4647        switch (e->argc) {
4648        case 0:
4649            if (e->compiled_pattern->FullMatch(path)) {
4650                goto out;
4651            }
4652            break;
4653
4654        case 1:
4655            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4656                real_argv[0] = arg1.c_str();
4657                goto out;
4658            }
4659            break;
4660
4661        case 2:
4662            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4663                real_argv[0] = arg1.c_str();
4664                real_argv[1] = arg2.c_str();
4665                goto out;
4666            }
4667            break;
4668
4669        case 3:
4670            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {
4671                real_argv[0] = arg1.c_str();
4672                real_argv[1] = arg2.c_str();
4673                real_argv[2] = arg3.c_str();
4674                goto out;
4675            }
4676            break;
4677
4678        default:
4679            break;
4680        }
4681    }
4682
4683    for (i = 0; i < total_link_patterns; i++) {
4684        e = &procfs_link_table[i];
4685        if ((e->flag & PROCFS_FLAG_ISDOTFILE) & !procfs_ui) {
4686            continue;
4687        }
4688        switch (e->argc) {
4689        case 0:
4690            if (e->compiled_pattern->FullMatch(path)) {
4691                goto out;
4692            }
4693            break;
4694
4695        case 1:
4696            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4697                real_argv[0] = arg1.c_str();
4698                goto out;
4699            }
4700            break;
4701
4702        case 2:
4703            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4704                real_argv[0] = arg1.c_str();
4705                real_argv[1] = arg2.c_str();
4706                goto out;
4707            }
4708            break;
4709
4710        case 3:
4711            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {
4712                real_argv[0] = arg1.c_str();
4713                real_argv[1] = arg2.c_str();
4714                real_argv[2] = arg3.c_str();
4715                goto out;
4716            }
4717            break;
4718
4719        default:
4720            break;
4721        }
4722    }
4723
4724    return -ENOENT;
4725
4726out:
4727    return e->getattr(e, real_argv, stbuf);
4728}
4729
4730
4731static int
4732procfs_readdir(const char             *path,
4733               void                   *buf,
4734               fuse_fill_dir_t        filler,
4735               off_t                  offset,
4736               struct fuse_file_info *fi)
4737{
4738    int i;
4739    procfs_dispatcher_entry_t e;
4740    string arg1, arg2, arg3;
4741    const char *real_argv[PROCFS_MAX_ARGS];
4742
4743    if (valid_process_pattern->PartialMatch(path, &arg1)) {
4744        pid_t check_pid = atoi(arg1.c_str());
4745        if (getpgid(check_pid) == -1) {
4746            return -ENOENT;
4747        }
4748    }
4749
4750    for (i = 0; i < PROCFS_MAX_ARGS; i++) {
4751        real_argv[i] = (char *)0;
4752    }
4753
4754    for (i = 0; i < total_directory_patterns; i++) {
4755
4756        e = &procfs_directory_table[i];
4757
4758        switch (e->argc) {
4759        case 0:
4760            if (e->compiled_pattern->FullMatch(path)) {
4761                goto out;
4762            }
4763            break;
4764
4765        case 1:
4766            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4767                real_argv[0] = arg1.c_str();
4768                goto out;
4769            }
4770            break;
4771
4772        case 2:
4773            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4774                real_argv[0] = arg1.c_str();
4775                real_argv[1] = arg2.c_str();
4776                goto out;
4777            }
4778            break;
4779
4780        case 3:
4781            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {
4782                real_argv[0] = arg1.c_str();
4783                real_argv[1] = arg2.c_str();
4784                real_argv[2] = arg3.c_str();
4785                goto out;
4786            }
4787            break;
4788
4789        default:
4790            return -ENOENT;
4791        }
4792    }
4793
4794    return -ENOENT;
4795
4796out:
4797    (void)e->readdir(e, real_argv, buf, filler, offset, fi);
4798
4799    (void)procfs_populate_directory(e->content_files, e->content_directories,
4800                                    buf, filler, offset, fi);
4801
4802    return 0;
4803}
4804
4805static int
4806procfs_readlink(const char *path, char *buf, size_t size)
4807{
4808    int i;
4809    procfs_dispatcher_entry_t e;
4810    string arg1, arg2, arg3;
4811    const char *real_argv[PROCFS_MAX_ARGS];
4812
4813    for (i = 0; i < PROCFS_MAX_ARGS; i++) {
4814        real_argv[i] = (char *)0;
4815    }
4816
4817    for (i = 0; i < total_link_patterns; i++) {
4818
4819        e = &procfs_link_table[i];
4820
4821        if ((e->flag & PROCFS_FLAG_ISDOTFILE) & !procfs_ui) {
4822            continue;
4823        }
4824
4825        switch (e->argc) {
4826        case 0:
4827            if (e->compiled_pattern->FullMatch(path)) {
4828                goto out;
4829            }
4830            break;
4831        case 1:
4832            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4833                real_argv[0] = arg1.c_str();
4834                goto out;
4835            }
4836            break;
4837        case 2:
4838            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4839                real_argv[0] = arg1.c_str();
4840                real_argv[1] = arg2.c_str();
4841                goto out;
4842            }
4843            break;
4844        }
4845    }
4846
4847    return -ENOENT;
4848
4849out:
4850    return e->readlink(e, real_argv, buf, size);
4851}
4852
4853static int
4854procfs_read(const char *path, char *buf, size_t size, off_t offset,
4855            struct fuse_file_info *fi)
4856{
4857    int i;
4858    procfs_dispatcher_entry_t e;
4859    string arg1, arg2, arg3;
4860    const char *real_argv[PROCFS_MAX_ARGS];
4861
4862    for (i = 0; i < PROCFS_MAX_ARGS; i++) {
4863        real_argv[i] = (char *)0;
4864    }
4865
4866    for (i = 0; i < total_file_patterns; i++) {
4867
4868        e = &procfs_file_table[i];
4869
4870        if ((e->flag & PROCFS_FLAG_ISDOTFILE) & !procfs_ui) {
4871            continue;
4872        }
4873
4874        switch (e->argc) {
4875        case 0:
4876            if (e->compiled_pattern->FullMatch(path)) {
4877                goto out;
4878            }
4879            break;
4880
4881        case 1:
4882            if (e->compiled_pattern->FullMatch(path, &arg1)) {
4883                real_argv[0] = arg1.c_str();
4884                goto out;
4885            }
4886            break;
4887
4888        case 2:
4889            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2)) {
4890                real_argv[0] = arg1.c_str();
4891                real_argv[1] = arg2.c_str();
4892                goto out;
4893            }
4894            break;
4895
4896        case 3:
4897            if (e->compiled_pattern->FullMatch(path, &arg1, &arg2, &arg3)) {
4898                real_argv[0] = arg1.c_str();
4899                real_argv[1] = arg2.c_str();
4900                real_argv[2] = arg3.c_str();
4901                goto out;
4902            }
4903            break;
4904    
4905        default:
4906            return -EIO;
4907        }
4908    }   
4909
4910    return -EIO;
4911    
4912out:    
4913    return e->read(e, real_argv, buf, size, offset, fi);
4914}
4915
4916static int
4917procfs_statfs(const char *path, struct statvfs *buf)
4918{
4919    (void)path;
4920
4921    buf->f_namemax = 255;
4922    buf->f_bsize = 1048576;
4923    buf->f_frsize = 1048576;
4924    buf->f_blocks = buf->f_bfree = buf->f_bavail =
4925        1000ULL * 1024 * 1024 * 1024 / buf->f_frsize;
4926    buf->f_files = buf->f_ffree = 1000000000;
4927    return 0;
4928}
4929
4930static struct fuse_operations procfs_oper;
4931
4932static void
4933procfs_oper_populate(struct fuse_operations *oper)
4934{
4935    oper->init       = procfs_init;
4936    oper->destroy    = procfs_destroy;
4937    oper->statfs     = procfs_statfs;
4938    oper->open       = procfs_open;
4939    oper->release    = procfs_release;
4940    oper->opendir    = procfs_opendir;
4941    oper->releasedir = procfs_releasedir;
4942    oper->getattr    = procfs_getattr;
4943    oper->read       = procfs_read;
4944    oper->readdir    = procfs_readdir;
4945    oper->readlink   = procfs_readlink;
4946}
4947
4948static char *def_opts = "-oallow_other,direct_io,nobrowse,nolocalcaches,ro,iosize=1048576,volname=ProcFS";
4949static char *def_opts_ui = "-oallow_other,local,nolocalcaches,ro,iosize=1048576,volname=ProcFS";
4950
4951int
4952main(int argc, char *argv[])
4953{
4954    int i;
4955    char **new_argv;
4956    char *extra_opts = def_opts;
4957
4958    if (getenv("MACFUSE_PROCFS_UI")) {
4959        procfs_ui = 1;
4960        extra_opts = def_opts_ui;
4961    }
4962
4963    argc++;
4964    new_argv = (char **)malloc(sizeof(char *) * argc);
4965    if (!new_argv)
4966        return -1;
4967    for (i = 0; i < (argc - 1); i++) {
4968        new_argv[i] = argv[i];
4969    }
4970    argv[i] = extra_opts;
4971
4972    procfs_oper_populate(&procfs_oper);
4973
4974    return fuse_main(argc, argv, &procfs_oper, NULL);
4975}