/* * UNG's Not GNU * * Copyright (c) 2020, Jakob Kaivo * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _XOPEN_SOURCE 700 #include #include #include #include #include #include #include #include #include #include #include #include enum { TYPE_WIDTH = 1, ID_WIDTH = 10, KEY_WIDTH = (sizeof(key_t) * 2), MODE_WIDTH = 11, OWNER_WIDTH = 8, GROUP_WIDTH = 8, CREATOR_WIDTH = OWNER_WIDTH, CGROUP_WIDTH = GROUP_WIDTH, CBYTES_WIDTH = 10, QNUM_WIDTH = 5, QBYTES_WIDTH = 10, LSPID_WIDTH = 7, LRPID_WIDTH = 7, STIME_WIDTH = 9, RTIME_WIDTH = 9, NATTCH_WIDTH = 8, SEGSZ_WIDTH = 6, CPID_WIDTH = 7, LPID_WIDTH = 7, ATIME_WIDTH = 9, DTIME_WIDTH = 9, NSEMS_WIDTH = 6, OTIME_WIDTH = 9, CTIME_WIDTH = 9, }; enum { MSG = 'q', SHM = 'm', SEM = 's', }; enum { BYTES = (1<<0), CREATOR = (1<<1), OUTSTANDING = (1<<2), PROCESS = (1<<3), TIME = (1<<4), }; struct ipc { struct ipc *next; struct ipc *prev; /* always */ char type; int id; unsigned int key; char mode[11]; uid_t owner; gid_t group; /* CREATOR */ uid_t creator; gid_t cgroup; /* OUTSTANDING */ int cbytes; /* MSG */ int qnum; /* MSG */ int nattch; /* SHM */ /* BYTES */ int qbytes; /* MSG */ int segsz; /* SHM */ int nsems; /* SEM */ /* PROCESS */ pid_t lspid; /* MSG */ pid_t lrpid; /* MSG */ pid_t cpid; /* SHM */ pid_t lpid; /* SHM */ /* TIME */ time_t stime; /* MSG */ time_t rtime; /* MSG */ time_t atime; /* SHM */ time_t dtime; /* SHM */ time_t otime; /* SEM */ time_t ctime; }; static void print_header(void) { time_t t = time(NULL); struct tm *tm = localtime(&t); char date[128]; strftime(date, sizeof(date), "%a %b %e %H:%M:%S %Z %Y", tm); printf("IPC status from %s as of %s\n", "", date); /* FIXME */ } static void print_user(int width, uid_t uid) { printf(" %-*d", width, uid); } static void print_group(int width, gid_t gid) { printf(" %-*d", width, gid); } static void print_time(int width, time_t t) { if (t == 0) { printf(" %-*s", width, "no-entry"); return; } printf(" %-*s", width, " "); } static void print_record(char type, int opts, struct ipc *entry) { printf("%-*c", TYPE_WIDTH, entry->type); printf(" %-*d", ID_WIDTH, entry->id); printf(" 0x%0*x", KEY_WIDTH - 2, entry->key); printf(" %-*s", MODE_WIDTH, entry->mode); print_user(OWNER_WIDTH, entry->owner); print_group(GROUP_WIDTH, entry->group); if (opts & CREATOR) { print_user(CREATOR_WIDTH, entry->creator); print_group(CGROUP_WIDTH, entry->cgroup); } if (opts & OUTSTANDING) { if (type == MSG) { printf(" %-*d", CBYTES_WIDTH, entry->cbytes); printf(" %-*d", QNUM_WIDTH, entry->qnum); } else if (type == SHM) { printf(" %-*d", NATTCH_WIDTH, entry->nattch); } } if (opts & BYTES) { if (type == MSG) { printf(" %-*d", QBYTES_WIDTH, entry->qbytes); } else if (type == SHM) { printf(" %-*d", SEGSZ_WIDTH, entry->segsz); } else if (type == SEM) { printf(" %-*d", NSEMS_WIDTH, entry->nsems); } } if (opts & PROCESS) { if (type == MSG) { printf(" %-*d", LSPID_WIDTH, entry->lspid); printf(" %-*d", LRPID_WIDTH, entry->lrpid); } else if (type == SHM) { printf(" %-*d", CPID_WIDTH, entry->cpid); printf(" %-*d", LPID_WIDTH, entry->lpid); } } if (opts & TIME) { if (type == MSG) { print_time(STIME_WIDTH, entry->stime); print_time(RTIME_WIDTH, entry->rtime); } else if (type == SHM) { print_time(ATIME_WIDTH, entry->atime); print_time(DTIME_WIDTH, entry->dtime); } else if (type == SEM) { print_time(OTIME_WIDTH, entry->otime); } print_time(CTIME_WIDTH, entry->ctime); } printf("\n"); } static void print_report(char type, int opts, struct ipc *list) { char *facility = NULL; if (type == MSG) { facility = "Message Queues"; } else if (type == SHM) { facility = "Shared Memory"; } else if (type == SEM) { facility = "Semaphores"; } if (list == NULL) { printf("%s facility not in system.\n", facility); return; } printf("%s:\n", facility); printf("%-*c", TYPE_WIDTH, 'T'); printf(" %-*s", ID_WIDTH, "ID"); printf(" %-*s", KEY_WIDTH, "KEY"); printf(" %-*s", MODE_WIDTH, "MODE"); printf(" %-*s", OWNER_WIDTH, "OWNER"); printf(" %-*s", GROUP_WIDTH, "GROUP"); if (opts & CREATOR) { printf(" %-*s", CREATOR_WIDTH, "CREATOR"); printf(" %-*s", CGROUP_WIDTH, "CGROUP"); } if (opts & OUTSTANDING) { if (type == MSG) { printf(" %-*s", CBYTES_WIDTH, "CBYTES"); printf(" %-*s", QNUM_WIDTH, "QNUM"); } else if (type == SHM) { printf(" %-*s", NATTCH_WIDTH, "NATTCH"); } } if (opts & BYTES) { if (type == MSG) { printf(" %-*s", QBYTES_WIDTH, "QBYTES"); } else if (type == SHM) { printf(" %-*s", SEGSZ_WIDTH, "SEGSZ"); } else if (type == SEM) { printf(" %-*s", NSEMS_WIDTH, "NSEMS"); } } if (opts & PROCESS) { if (type == MSG) { printf(" %-*s", LSPID_WIDTH, "LSPID"); printf(" %-*s", LRPID_WIDTH, "LRPID"); } else if (type == SHM) { printf(" %-*s", CPID_WIDTH, "CPID"); printf(" %-*s", LPID_WIDTH, "LPID"); } } if (opts & TIME) { if (type == MSG) { printf(" %-*s", STIME_WIDTH, "STIME"); printf(" %-*s", RTIME_WIDTH, "RTIME"); } else if (type == SHM) { printf(" %-*s", ATIME_WIDTH, "ATIME"); printf(" %-*s", DTIME_WIDTH, "DTIME"); } else if (type == SEM) { printf(" %-*s", OTIME_WIDTH, "OTIME"); } printf(" %-*s", CTIME_WIDTH, "CTIME"); } printf("\n"); while (list) { print_record(type, opts, list); list = list->next; } } static struct ipc *ipcs(char type) { struct ipc *r = calloc(1, sizeof(*r)); r->type = type; memset(r->mode, '-', sizeof(r->mode)); return r; } int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); int c; int msgs = 0; int shms = 0; int sems = 0; unsigned int print = 0; while ((c = getopt(argc, argv, "qmsabcopt")) != -1) { switch(c) { case 'q': msgs = 1; break; case 'm': shms = 1; break; case 's': sems = 1; break; case 'a': print = BYTES | CREATOR | OUTSTANDING | PROCESS | TIME; break; case 'b': print |= BYTES; break; case 'c': print |= CREATOR; break; case 'o': print |= OUTSTANDING; break; case 'p': print |= PROCESS; break; case 't': print |= TIME; break; default: return 1; } } if (msgs == 0 && shms == 0 && sems == 0) { msgs = 1; shms = 1; sems = 1; } struct ipc *msglist = msgs ? ipcs(MSG) : NULL; struct ipc *shmlist = shms ? ipcs(SHM) : NULL; struct ipc *semlist = sems ? ipcs(SEM) : NULL; print_header(); if (msgs) { print_report(MSG, print, msglist); } if (shms) { print_report(SHM, print, shmlist); } if (sems) { print_report(SEM, print, semlist); } return 0; }