/*
 * dnode2.c - SCO UnixWare node functions for lsof
 *
 * This module must be separate to keep separate the multiple kernel inode
 * structure definitions.
 */

/*
 * Copyright 1998 Purdue Research Foundation, West Lafayette, Indiana
 * 47907.  All rights reserved.
 *
 * Written by Victor A. Abell
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. Neither the authors nor Purdue University are responsible for any
 *    consequences of the use of this software.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Credit to the authors and Purdue
 *    University must appear in documentation and sources.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 4. This notice may not be removed or altered.
 */

#ifndef lint
static char copyright[] =
    "@(#) Copyright 1996 Purdue Research Foundation.\nAll rights reserved.\n";
#endif

#include "common.h"

#include <sys/fs/bfs.h>

#if UNIXWAREV >= 7000
#    if UNIXWAREV >= 70103
#        undef IEXEC
#        undef IREAD
#        undef IWRITE
#    endif /* UNIXWAREV>=70103 */
#    undef ISUID
#    undef ISGID
#    undef ISVTX
#    include <sys/fs/cdfs_fs.h>
#endif /* UNIXWAREV>=7000 */

/*
 * Local definitions
 */

#define DOS_NAME_PFX "(DOS name: "
#define DOS_NAME_SFX ")"

#if UNIXWAREV >= 7000 && !defined(TYPELOGSECSHIFT)
#    define TYPELOGSECSHIFT uint_t /* just in case Configure missed it */
#endif /* UNIXWAREV>=7000 && !defined(TYPELOGSECSHIFT) */

/*
 * Local static variables
 */

static unsigned char Dos2Unix[] = {
    /* derived from tounix[] in
     * /etc/conf/pack.d/ccnv/space.c */
    '_',  '_',  '_',  '_',  '_',  '_',  '_',  '_',  /* 0x01-0x08 */
    '_',  '_',  '_',  '_',  '_',  '_',  '_',  '_',  /* 0x09-0x10 */
    '_',  '_',  '_',  '_',  '_',  '_',  '_',  '_',  /* 0x11-0x18 */
    '_',  '_',  '_',  '_',  '_',  '_',  '_',  ' ',  /* 0x19-0x20 */
    '!',  '"',  '#',  '$',  '%',  '&',  '\'', '(',  /* 0x21-0x28 */
    ')',  '*',  '+',  ',',  '-',  '.',  '/',  '0',  /* 0x29-0x30 */
    '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  /* 0x31-0x38 */
    '9',  ':',  ';',  '<',  '=',  '>',  '?',  '@',  /* 0x39-0x40 */
    'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  /* 0x41-0x48 */
    'i',  'j',  'k',  'l',  'm',  'n',  'o',  'p',  /* 0x49-0x50 */
    'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  /* 0x51-0x58 */
    'y',  'z',  '[',  '\\', ']',  '^',  '_',  '`',  /* 0x59-0x60 */
    'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  /* 0x61-0x68 */
    'i',  'j',  'k',  'l',  'm',  'n',  'o',  'p',  /* 0x69-0x70 */
    'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  /* 0x71-0x78 */
    'y',  'z',  '{',  '|',  '}',  '~',  '_',  0347, /* 0x79-0x80 */
    0374, 0351, 0342, 0344, 0340, 0345, 0347, 0352, /* 0x81-0x88 */
    0353, 0350, 0357, 0356, 0354, 0344, 0345, 0351, /* 0x89-0x90 */
    0346, 0346, 0364, 0366, 0362, 0373, 0371, 0377, /* 0X91-0X98 */
    0366, 0374, 0370, 0243, 0370, 0367, '_',  0341, /* 0x99-0xa0 */
    0355, 0363, 0372, 0361, 0361, 0252, 0272, 0277, /* 0xa1-0xa8 */
    0256, 0254, 0275, 0274, 0241, 0253, 0273, '_',  /* 0xa9-0xb0 */
    '_',  '_',  '_',  '_',  0341, 0342, 0340, 0251, /* 0xb1-0xb8 */
    '_',  '_',  '_',  '_',  0242, 0245, '_',  '_',  /* 0xb9-0xc0 */
    '_',  '_',  '_',  '_',  '_',  0343, 0343, '_',  /* 0xc1-0xc8 */
    '_',  '_',  '_',  '_',  '_',  '_',  0244, 0360, /* 0xc9-0xd0 */
    0320, 0352, 0353, 0350, '_',  0355, 0356, 0357, /* 0xd1-0xd8 */
    '_',  '_',  '_',  '_',  0246, 0354, '_',  0363, /* 0xd9-0xe0 */
    0337, 0364, 0362, 0365, 0365, 0265, 0376, 0376, /* 0xe1-0xe8 */
    0372, 0373, 0371, 0375, 0375, 0257, 0264, 0255, /* 0xe9-0xf0 */
    0261, '_',  0276, 0266, 0247, 0327, 0270, 0260, /* 0xf1-0xf8 */
    0250, 0267, 0271, 0263, 0262, '_',  '_'         /* 0xf9-0xff */
};

/*
 * readbfslino() - read bfs inode's local inode information
 */

int readbfslino(struct lsof_context *ctx, /* context */
                struct vnode *v,          /* containing vnode */
                struct l_ino *i)          /* local inode information */
{
    struct inode b;
    struct vfs kv;

    if (kread(ctx, (KA_T)v->v_data, (char *)&b, sizeof(b)))
        return (1);
    if (!v->v_vfsp || kread(ctx, (KA_T)v->v_vfsp, (char *)&kv, sizeof(kv)))
        return (1);
    i->dev = kv.vfs_dev;
    i->dev_def = 1;
    i->rdev = (dev_t)0;
    i->rdev_def = 0;
    i->nlink = (long)b.i_diskino.d_fattr.va_nlink;
    i->nlink_def = 1;
    i->nm = (char *)NULL;
    i->number = (INODETYPE)b.i_diskino.d_ino;
    i->number_def = 1;
    i->size = (SZOFFTYPE)BFS_FILESIZE(&b.i_diskino);
    i->size_def = 1;
    return (0);
}

#if UNIXWAREV >= 7000
/*
 * reacdfslino() - read cdfs inode's local inode information
 *
 * Adapted from work by Eric Dumazet <edumazet@cosmosbay.com>.
 */

int readcdfslino(struct lsof_context *ctx, /* context */
                 struct vnode *v,          /* containing vnode */
                 struct l_ino *i)          /* local inode information */
{
    cdfs_inode_t ci;
    TYPELOGSECSHIFT lss;
    KA_T ka;
    struct vfs kv;
    /*
     * Read the CDFs node.  Fill in return values from its contents.
     */
    if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&ci, sizeof(ci)))
        return (1);
    if (!v->v_vfsp || kread(ctx, (KA_T)v->v_vfsp, (char *)&kv, sizeof(kv)))
        return (1);
    i->dev = kv.vfs_dev;
    i->dev_def = 1;
    i->rdev = ci.i_DevNum;
    i->rdev_def = 1;
    i->nlink = (long)ci.i_LinkCnt;
    i->nlink_def = 1;
    i->nm = (char *)NULL;
    i->size = (SZOFFTYPE)ci.i_Size;
    i->size_def = 1;
    /*
     * Compute the node number.
     *
     * (See the CDFS_INUM() macro in <sys/fs/cdfs_inode.h>.)
     *
     * It's too wasteful to read the entire cdfs structure for one element,
     * cdfs_LogSecShift, so it's read specially.  Its type, TYPELOGSECSHIFT,
     * should be defined by lsof's Configure script, but for safety's sake
     * has a uint_t default, defined in this source file.
     */
    i->number = (INODETYPE)0;
    if (!(ka = (KA_T)kv.vfs_data))
        return (0);
    ka = (KA_T)((char *)ka + offsetof(struct cdfs, cdfs_LogSecShift));
    if (!kread(ctx, ka, (char *)&lss, sizeof(lss))) {
        i->number =
            (INODETYPE)((ci.i_Fid.fid_SectNum << lss) + ci.i_Fid.fid_Offset);
        i->number_def = 1;
    }
    return (0);
}

/*
 * readdosfslino() - read dosfs inode's local inode information
 *
 * Adapted from work by Eric Dumazet <edumazet@cosmosbay.com>.
 */

int readdosfslino(struct lsof_context *ctx, /* context */
                  struct vnode *v,          /* containing vnode */
                  struct l_ino *i)          /* local inode information */
{
    struct dosfs_inode {
        int pad1[19];
        int device;
        int pad2[21];
        long offset;
        long dirnum;
        int pad3[3];
        unsigned char name[16];
        int pad4[3];
        unsigned long size;
    } di;
    static char *nm = (char *)NULL;
    static MALLOC_S nml = (MALLOC_S)0;
    int sz;
    /*
     * Read the DOSFS node.  Fill in return values from its contents.
     */
    if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&di, sizeof(di)))
        return (1);
    i->dev = (dev_t)di.device;
    i->dev_def = 1;
    i->rdev = (dev_t)0;
    i->rdev_def = 1;
    i->nlink_def = 0;
    i->size = (SZOFFTYPE)di.size;
    i->size_def = 1;
    /*
     * Allocate space for and save the name, prepared as a name column addition.
     */
    i->nm = (char *)NULL;
    if (di.name[0]) {
        if (!nm) {
            nml = (MALLOC_S)(strlen(DOS_NAME_PFX) + sizeof(di.name) +
                             strlen(DOS_NAME_SFX) + 1);
            if (!(nm = (char *)malloc(nml))) {
                (void)fprintf(stderr,
                              "%s: can't allocate %d bytes for DOS name\n", nml,
                              Pn);
                Error(ctx);
            }
        }
        /*
         * Calculate the DOS name length and convert DOS to UNIX characters.
         */
        for (sz = 0; sz < sizeof(di.name); sz++) {
            if (!di.name[sz])
                break;
            di.name[sz] = Dos2Unix[(di.name[sz] & 0xff) - 1];
        }
        if (sz) {
            (void)snpf(nm, nml, "%s%-*.*s%s", DOS_NAME_PFX, sz, sz, di.name,
                       DOS_NAME_SFX);
            i->nm = nm;
        }
    }
    /*
     * Compute the node number.
     */
    i->number = (INODETYPE)((di.dirnum << 16) + di.offset);
    i->number_def = 1;
    return (0);
}
#endif /* UNIXWAREV>=7000 */
