|
|
1.1 ! root 1: /* VMS subprocess and command interface. ! 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 1, or (at your option) ! 9: any later version. ! 10: ! 11: GNU Emacs is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU Emacs; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: /* Written by Mukesh Prasad. */ ! 21: ! 22: /* ! 23: * INTERFACE PROVIDED BY EMACS FOR VMS SUBPROCESSES: ! 24: * ! 25: * Emacs provides the following functions: ! 26: * ! 27: * "spawn-subprocess", which takes as arguments: ! 28: * ! 29: * (i) an integer to identify the spawned subprocess in future ! 30: * operations, ! 31: * (ii) A function to process input from the subprocess, and ! 32: * (iii) A function to be called upon subprocess termination. ! 33: * ! 34: * First argument is required. If second argument is missing or nil, ! 35: * the default action is to insert all received messages at the current ! 36: * location in the current buffer. If third argument is missing or nil, ! 37: * no action is taken upon subprocess termination. ! 38: * The input-handler is called as ! 39: * (input-handler num string) ! 40: * where num is the identifying integer for the subprocess and string ! 41: * is a string received from the subprocess. exit-handler is called ! 42: * with the identifying integer as the argument. ! 43: * ! 44: * "send-command-to-subprocess" takes two arguments: ! 45: * ! 46: * (i) Subprocess identifying integer. ! 47: * (ii) String to send as a message to the subprocess. ! 48: * ! 49: * "stop-subprocess" takes the subprocess identifying integer as ! 50: * argument. ! 51: * ! 52: * Implementation is done by spawning an asynchronous subprocess, and ! 53: * communicating to it via mailboxes. ! 54: */ ! 55: ! 56: #ifdef VMS ! 57: ! 58: #include <stdio.h> ! 59: #include <ctype.h> ! 60: #undef NULL ! 61: ! 62: #include "config.h" ! 63: #include "lisp.h" ! 64: #include <descrip.h> ! 65: #include <dvidef.h> ! 66: #include <prvdef.h> ! 67: #include <clidef.h> ! 68: #include <iodef.h> ! 69: #include <ssdef.h> ! 70: #include <errno.h> ! 71: ! 72: /* GCC does not carry this header file. Doesn't matter, we define the symbol ! 73: we need below, if not already defined. */ ! 74: #ifndef __GNUC__ ! 75: #include <syidef.h> ! 76: #endif ! 77: ! 78: #ifdef VMS4_4 /* I am being cautious; perhaps this exists in older versions */ ! 79: #include <jpidef.h> ! 80: #endif ! 81: ! 82: #ifndef CLI$M_NOWAIT ! 83: #define CLI$M_NOWAIT 1 /* clidef.h is missing from C library */ ! 84: #endif ! 85: ! 86: #ifndef SYI$_VERSION ! 87: #define SYI$_VERSION 4096 /* syidef.h is missing from C library */ ! 88: #endif ! 89: ! 90: #ifndef JPI$_CLINAME ! 91: #define JPI$_CLINAME 522 /* JPI$_CLINAME is missing from jpidef.h */ ! 92: #endif ! 93: ! 94: #ifndef JPI$_MASTER_PID ! 95: #define JPI$_MASTER_PID 805 /* JPI$_MASTER_PID missing from jpidef.h */ ! 96: #endif ! 97: #define LIB$_NOSUCHSYM 1409892 /* libclidef.h missing */ ! 98: ! 99: #define MSGSIZE 160 /* Maximum size for mailbox operations */ ! 100: ! 101: #ifndef PRV$V_ACNT ! 102: ! 103: /* these defines added as hack for VMS 5.1-1. SJones, 8-17-89 */ ! 104: /* this is _really_ nasty and needs to be changed ASAP - should see about ! 105: using the union defined in SYS$LIBRARY:PRVDEF.H under v5 */ ! 106: ! 107: #define PRV$V_ACNT 0x09 ! 108: #define PRV$V_ALLSPOOL 0x04 ! 109: #define PRV$V_ALTPRI 0x0D ! 110: #define PRV$V_BUGCHK 0x17 ! 111: #define PRV$V_BYPASS 0x1D ! 112: #define PRV$V_CMEXEC 0x01 ! 113: #define PRV$V_CMKRNL 0x00 ! 114: #define PRV$V_DETACH 0x05 ! 115: #define PRV$V_DIAGNOSE 0x06 ! 116: #define PRV$V_DOWNGRADE 0x21 ! 117: #define PRV$V_EXQUOTA 0x13 ! 118: #define PRV$V_GROUP 0x08 ! 119: #define PRV$V_GRPNAM 0x03 ! 120: #define PRV$V_GRPPRV 0x22 ! 121: #define PRV$V_LOG_IO 0x07 ! 122: #define PRV$V_MOUNT 0x11 ! 123: #define PRV$V_NETMBX 0x14 ! 124: #define PRV$V_NOACNT 0x09 ! 125: #define PRV$V_OPER 0x12 ! 126: #define PRV$V_PFNMAP 0x1A ! 127: #define PRV$V_PHY_IO 0x16 ! 128: #define PRV$V_PRMCEB 0x0A ! 129: #define PRV$V_PRMGBL 0x18 ! 130: #define PRV$V_PRMJNL 0x25 ! 131: #define PRV$V_PRMMBX 0x0B ! 132: #define PRV$V_PSWAPM 0x0C ! 133: #define PRV$V_READALL 0x23 ! 134: #define PRV$V_SECURITY 0x26 ! 135: #define PRV$V_SETPRI 0x0D ! 136: #define PRV$V_SETPRV 0x0E ! 137: #define PRV$V_SHARE 0x1F ! 138: #define PRV$V_SHMEM 0x1B ! 139: #define PRV$V_SYSGBL 0x19 ! 140: #define PRV$V_SYSLCK 0x1E ! 141: #define PRV$V_SYSNAM 0x02 ! 142: #define PRV$V_SYSPRV 0x1C ! 143: #define PRV$V_TMPJNL 0x24 ! 144: #define PRV$V_TMPMBX 0x0F ! 145: #define PRV$V_UPGRADE 0x20 ! 146: #define PRV$V_VOLPRO 0x15 ! 147: #define PRV$V_WORLD 0x10 ! 148: #endif ! 149: ! 150: /* IO status block for mailbox operations. */ ! 151: struct mbx_iosb ! 152: { ! 153: short status; ! 154: short size; ! 155: int pid; ! 156: }; ! 157: ! 158: /* Structure for maintaining linked list of subprocesses. */ ! 159: struct process_list ! 160: { ! 161: int name; /* Numeric identifier for subprocess */ ! 162: int process_id; /* VMS process address */ ! 163: int process_active; /* 1 iff process has not exited yet */ ! 164: int mbx_chan; /* Mailbox channel to write to process */ ! 165: struct mbx_iosb iosb; /* IO status block for write operations */ ! 166: Lisp_Object input_handler; /* Input handler for subprocess */ ! 167: Lisp_Object exit_handler; /* Exit handler for subprocess */ ! 168: struct process_list * next; /* Linked list chain */ ! 169: }; ! 170: ! 171: /* Structure for privilege list. */ ! 172: struct privilege_list ! 173: { ! 174: char * name; ! 175: int mask; ! 176: }; ! 177: ! 178: /* Structure for finding VMS related information. */ ! 179: struct vms_objlist ! 180: { ! 181: char * name; /* Name of object */ ! 182: Lisp_Object (* objfn)(); /* Function to retrieve VMS object */ ! 183: }; ! 184: ! 185: static int exit_ast (); /* Called upon subprocess exit */ ! 186: static int create_mbx (); /* Creates mailbox */ ! 187: static void mbx_msg (); /* Writes null terminated string to mbx */ ! 188: static void write_to_mbx (); /* Writes message to string */ ! 189: static void start_mbx_input (); /* Queues I/O request to mailbox */ ! 190: ! 191: static int input_mbx_chan = 0; /* Channel to read subprocess input on */ ! 192: static char input_mbx_name[20]; ! 193: /* Storage for mailbox device name */ ! 194: static struct dsc$descriptor_s input_mbx_dsc; ! 195: /* Descriptor for mailbox device name */ ! 196: static struct process_list * process_list = 0; ! 197: /* Linked list of subprocesses */ ! 198: static char mbx_buffer[MSGSIZE]; ! 199: /* Buffer to read from subprocesses */ ! 200: static struct mbx_iosb input_iosb; ! 201: /* IO status block for mailbox reads */ ! 202: ! 203: int have_process_input, /* Non-zero iff subprocess input pending */ ! 204: process_exited; /* Non-zero iff suprocess exit pending */ ! 205: ! 206: /* List of privilege names and mask offsets */ ! 207: static struct privilege_list priv_list[] = { ! 208: ! 209: { "ACNT", PRV$V_ACNT }, ! 210: { "ALLSPOOL", PRV$V_ALLSPOOL }, ! 211: { "ALTPRI", PRV$V_ALTPRI }, ! 212: { "BUGCHK", PRV$V_BUGCHK }, ! 213: { "BYPASS", PRV$V_BYPASS }, ! 214: { "CMEXEC", PRV$V_CMEXEC }, ! 215: { "CMKRNL", PRV$V_CMKRNL }, ! 216: { "DETACH", PRV$V_DETACH }, ! 217: { "DIAGNOSE", PRV$V_DIAGNOSE }, ! 218: { "DOWNGRADE", PRV$V_DOWNGRADE }, /* Isn't VMS as low as you can go? */ ! 219: { "EXQUOTA", PRV$V_EXQUOTA }, ! 220: { "GRPPRV", PRV$V_GRPPRV }, ! 221: { "GROUP", PRV$V_GROUP }, ! 222: { "GRPNAM", PRV$V_GRPNAM }, ! 223: { "LOG_IO", PRV$V_LOG_IO }, ! 224: { "MOUNT", PRV$V_MOUNT }, ! 225: { "NETMBX", PRV$V_NETMBX }, ! 226: { "NOACNT", PRV$V_NOACNT }, ! 227: { "OPER", PRV$V_OPER }, ! 228: { "PFNMAP", PRV$V_PFNMAP }, ! 229: { "PHY_IO", PRV$V_PHY_IO }, ! 230: { "PRMCEB", PRV$V_PRMCEB }, ! 231: { "PRMGBL", PRV$V_PRMGBL }, ! 232: { "PRMJNL", PRV$V_PRMJNL }, ! 233: { "PRMMBX", PRV$V_PRMMBX }, ! 234: { "PSWAPM", PRV$V_PSWAPM }, ! 235: { "READALL", PRV$V_READALL }, ! 236: { "SECURITY", PRV$V_SECURITY }, ! 237: { "SETPRI", PRV$V_SETPRI }, ! 238: { "SETPRV", PRV$V_SETPRV }, ! 239: { "SHARE", PRV$V_SHARE }, ! 240: { "SHMEM", PRV$V_SHMEM }, ! 241: { "SYSGBL", PRV$V_SYSGBL }, ! 242: { "SYSLCK", PRV$V_SYSLCK }, ! 243: { "SYSNAM", PRV$V_SYSNAM }, ! 244: { "SYSPRV", PRV$V_SYSPRV }, ! 245: { "TMPJNL", PRV$V_TMPJNL }, ! 246: { "TMPMBX", PRV$V_TMPMBX }, ! 247: { "UPGRADE", PRV$V_UPGRADE }, ! 248: { "VOLPRO", PRV$V_VOLPRO }, ! 249: { "WORLD", PRV$V_WORLD }, ! 250: ! 251: }; ! 252: ! 253: static Lisp_Object ! 254: vms_account(), vms_cliname(), vms_owner(), vms_grp(), vms_image(), ! 255: vms_parent(), vms_pid(), vms_prcnam(), vms_terminal(), vms_uic_int(), ! 256: vms_uic_str(), vms_username(), vms_version_fn(), vms_trnlog(), ! 257: vms_symbol(), vms_proclist(); ! 258: ! 259: /* Table of arguments to Fvms_object, and the handlers that get the data. */ ! 260: ! 261: static struct vms_objlist vms_object [] = { ! 262: { "ACCOUNT", vms_account }, /* Returns account name as a string */ ! 263: { "CLINAME", vms_cliname }, /* Returns CLI name (string) */ ! 264: { "OWNER", vms_owner }, /* Returns owner process's PID (int) */ ! 265: { "GRP", vms_grp }, /* Returns group number of UIC (int) */ ! 266: { "IMAGE", vms_image }, /* Returns executing image (string) */ ! 267: { "PARENT", vms_parent }, /* Returns parent proc's PID (int) */ ! 268: { "PID", vms_pid }, /* Returns process's PID (int) */ ! 269: { "PRCNAM", vms_prcnam }, /* Returns process's name (string) */ ! 270: { "TERMINAL", vms_terminal }, /* Returns terminal name (string) */ ! 271: { "UIC", vms_uic_int }, /* Returns UIC as integer */ ! 272: { "UICGRP", vms_uic_str }, /* Returns UIC as string */ ! 273: { "USERNAME", vms_username }, /* Returns username (string) */ ! 274: { "VERSION", vms_version_fn },/* Returns VMS version (string) */ ! 275: { "LOGICAL", vms_trnlog }, /* Translates VMS logical name */ ! 276: { "DCL-SYMBOL", vms_symbol }, /* Translates DCL symbol */ ! 277: { "PROCLIST", vms_proclist }, /* Returns list of all PIDs on system */ ! 278: }; ! 279: ! 280: Lisp_Object Qdefault_subproc_input_handler; ! 281: ! 282: extern int process_ef; /* Event flag for subprocess operations */ ! 283: ! 284: DEFUN ("default-subprocess-input-handler", ! 285: Fdefault_subproc_input_handler, Sdefault_subproc_input_handler, ! 286: 2, 2, 0, ! 287: "Default input handler for input from spawned subprocesses.") ! 288: (name, input) ! 289: Lisp_Object name, input; ! 290: { ! 291: /* Just insert in current buffer */ ! 292: insert (XSTRING (input)->data, XSTRING (input)->size); ! 293: insert ("\n", 1); ! 294: } ! 295: ! 296: DEFUN ("spawn-subprocess", Fspawn_subprocess, Sspawn_subprocess, 1, 3, 0, ! 297: "Spawns an asynchronous VMS suprocess for command processing.") ! 298: (name, input_handler, exit_handler) ! 299: Lisp_Object name, input_handler, exit_handler; ! 300: { ! 301: int status; ! 302: char output_mbx_name[20]; ! 303: struct dsc$descriptor_s output_mbx_dsc; ! 304: struct process_list *ptr, *p, *prev; ! 305: static int dummy = CLI$M_NOWAIT; ! 306: ! 307: CHECK_NUMBER (name, 0); ! 308: if (! input_mbx_chan) ! 309: { ! 310: if (! create_mbx (&input_mbx_dsc, input_mbx_name, &input_mbx_chan, 1)) ! 311: return Qnil; ! 312: start_mbx_input (); ! 313: } ! 314: ptr = 0; ! 315: prev = 0; ! 316: while (ptr) ! 317: { ! 318: struct process_list *next = ptr->next; ! 319: if (ptr->name == XFASTINT (name)) ! 320: { ! 321: if (ptr->process_active) ! 322: return Qt; ! 323: ! 324: /* Delete this process and run its exit handler. */ ! 325: if (prev) ! 326: prev->next = next; ! 327: else ! 328: process_list = next; ! 329: if (! NULL (ptr->exit_handler)) ! 330: Feval (Fcons (ptr->exit_handler, Fcons (make_number (ptr->name), ! 331: Qnil))); ! 332: sys$dassgn (ptr->mbx_chan); ! 333: break; ! 334: } ! 335: else ! 336: prev = ptr; ! 337: ptr = next; ! 338: } ! 339: if (! ptr) ! 340: ptr = (struct process_list *) xmalloc (sizeof (struct process_list)); ! 341: ! 342: if (! create_mbx (&output_mbx_dsc, output_mbx_name, &ptr->mbx_chan, 2)) ! 343: { ! 344: free (ptr); ! 345: return Qnil; ! 346: } ! 347: if (NULL (input_handler)) ! 348: input_handler = Qdefault_subproc_input_handler; ! 349: ptr->input_handler = input_handler; ! 350: ptr->exit_handler = exit_handler; ! 351: message ("Creating subprocess..."); ! 352: status = lib$spawn (0, &output_mbx_dsc, &input_mbx_dsc, &dummy, 0, ! 353: &ptr->process_id, 0, 0, exit_ast, &ptr->process_active); ! 354: if (! (status & 1)) ! 355: { ! 356: sys$dassgn (ptr->mbx_chan); ! 357: free (ptr); ! 358: error ("Unable to spawn subprocess"); ! 359: return Qnil; ! 360: } ! 361: ptr->name = XFASTINT (name); ! 362: ptr->next = process_list; ! 363: ptr->process_active = 1; ! 364: process_list = ptr; ! 365: message ("Creating subprocess...done"); ! 366: return Qt; ! 367: } ! 368: ! 369: static void ! 370: mbx_msg (ptr, msg) ! 371: struct process_list *ptr; ! 372: char *msg; ! 373: { ! 374: write_to_mbx (ptr, msg, strlen (msg)); ! 375: } ! 376: ! 377: DEFUN ("send-command-to-subprocess", ! 378: Fsend_command_to_subprocess, Ssend_command_to_subprocess, 2, 2, ! 379: "sSend command to subprocess: \nsSend subprocess %s command: ", ! 380: "Send to VMS subprocess named NAME the string COMMAND.") ! 381: (name, command) ! 382: Lisp_Object name, command; ! 383: { ! 384: struct process_list * ptr; ! 385: ! 386: CHECK_NUMBER (name, 0); ! 387: CHECK_STRING (command, 1); ! 388: for (ptr = process_list; ptr; ptr = ptr->next) ! 389: if (XFASTINT (name) == ptr->name) ! 390: { ! 391: write_to_mbx (ptr, XSTRING (command)->data, ! 392: XSTRING (command)->size); ! 393: return Qt; ! 394: } ! 395: return Qnil; ! 396: } ! 397: ! 398: DEFUN ("stop-subprocess", Fstop_subprocess, Sstop_subprocess, 1, 1, ! 399: "sStop subprocess: ", "Stop VMS subprocess named NAME.") ! 400: (name) ! 401: Lisp_Object name; ! 402: { ! 403: struct process_list * ptr; ! 404: ! 405: CHECK_NUMBER (name, 0); ! 406: for (ptr = process_list; ptr; ptr = ptr->next) ! 407: if (XFASTINT (name) == ptr->name) ! 408: { ! 409: ptr->exit_handler = Qnil; ! 410: if (sys$delprc (&ptr->process_id, 0) & 1) ! 411: ptr->process_active = 0; ! 412: return Qt; ! 413: } ! 414: return Qnil; ! 415: } ! 416: ! 417: static int ! 418: exit_ast (active) ! 419: int * active; ! 420: { ! 421: process_exited = 1; ! 422: *active = 0; ! 423: sys$setef (process_ef); ! 424: } ! 425: ! 426: /* Process to handle input on the input mailbox. ! 427: * Searches through the list of processes until the matching PID is found, ! 428: * then calls its input handler. ! 429: */ ! 430: ! 431: process_command_input () ! 432: { ! 433: struct process_list * ptr; ! 434: char * msg; ! 435: int msglen; ! 436: Lisp_Object expr; ! 437: ! 438: msg = mbx_buffer; ! 439: msglen = input_iosb.size; ! 440: /* Hack around VMS oddity of sending extraneous CR/LF characters for ! 441: * some of the commands (but not most). ! 442: */ ! 443: if (msglen > 0 && *msg == '\r') ! 444: { ! 445: msg++; ! 446: msglen--; ! 447: } ! 448: if (msglen > 0 && msg[msglen - 1] == '\n') ! 449: msglen--; ! 450: if (msglen > 0 && msg[msglen - 1] == '\r') ! 451: msglen--; ! 452: /* Search for the subprocess in the linked list. ! 453: */ ! 454: expr = Qnil; ! 455: for (ptr = process_list; ptr; ptr = ptr->next) ! 456: if (ptr->process_id == input_iosb.pid) ! 457: { ! 458: expr = Fcons (ptr->input_handler, ! 459: Fcons (make_number (ptr->name), ! 460: Fcons (make_string (msg, msglen), ! 461: Qnil))); ! 462: break; ! 463: } ! 464: have_process_input = 0; ! 465: start_mbx_input (); ! 466: clear_waiting_for_input (); /* Otherwise Ctl-g will cause crash. JCB */ ! 467: if (! NULL (expr)) ! 468: Feval (expr); ! 469: } ! 470: ! 471: /* Searches process list for any processes which have exited. Calls their ! 472: * exit handlers and removes them from the process list. ! 473: */ ! 474: ! 475: process_exit () ! 476: { ! 477: struct process_list * ptr, * prev, * next; ! 478: ! 479: process_exited = 0; ! 480: prev = 0; ! 481: ptr = process_list; ! 482: while (ptr) ! 483: { ! 484: next = ptr->next; ! 485: if (! ptr->process_active) ! 486: { ! 487: if (prev) ! 488: prev->next = next; ! 489: else ! 490: process_list = next; ! 491: if (! NULL (ptr->exit_handler)) ! 492: Feval (Fcons (ptr->exit_handler, Fcons (make_number (ptr->name), ! 493: Qnil))); ! 494: sys$dassgn (ptr->mbx_chan); ! 495: free (ptr); ! 496: } ! 497: else ! 498: prev = ptr; ! 499: ptr = next; ! 500: } ! 501: } ! 502: ! 503: /* Called at emacs exit. ! 504: */ ! 505: ! 506: kill_vms_processes () ! 507: { ! 508: struct process_list * ptr; ! 509: ! 510: for (ptr = process_list; ptr; ptr = ptr->next) ! 511: if (ptr->process_active) ! 512: { ! 513: sys$dassgn (ptr->mbx_chan); ! 514: sys$delprc (&ptr->process_id, 0); ! 515: } ! 516: sys$dassgn (input_mbx_chan); ! 517: process_list = 0; ! 518: input_mbx_chan = 0; ! 519: } ! 520: ! 521: /* Creates a temporary mailbox and retrieves its device name in 'buf'. ! 522: * Makes the descriptor pointed to by 'dsc' refer to this device. ! 523: * 'buffer_factor' is used to allow sending messages asynchronously ! 524: * till some point. ! 525: */ ! 526: ! 527: static int ! 528: create_mbx (dsc, buf, chan, buffer_factor) ! 529: struct dsc$descriptor_s *dsc; ! 530: char *buf; ! 531: int *chan; ! 532: int buffer_factor; ! 533: { ! 534: int strval[2]; ! 535: int status; ! 536: static int dummy = DVI$_DEVNAM; ! 537: ! 538: status = sys$crembx (0, chan, MSGSIZE, MSGSIZE * buffer_factor, 0, 0, 0); ! 539: if (! (status & 1)) ! 540: { ! 541: message ("Unable to create mailbox. Need TMPMBX privilege."); ! 542: return 0; ! 543: } ! 544: strval[0] = 16; ! 545: strval[1] = (int) buf; ! 546: status = lib$getdvi (&dummy, chan, 0, 0, strval, ! 547: &dsc->dsc$w_length); ! 548: if (! (status & 1)) ! 549: return 0; ! 550: dsc->dsc$b_dtype = DSC$K_DTYPE_T; ! 551: dsc->dsc$b_class = DSC$K_CLASS_S; ! 552: dsc->dsc$a_pointer = buf; ! 553: return 1; ! 554: } /* create_mbx */ ! 555: ! 556: /* AST routine to be called upon receiving mailbox input. ! 557: * Sets flag telling keyboard routines that input is available. ! 558: */ ! 559: ! 560: static int ! 561: mbx_input_ast () ! 562: { ! 563: have_process_input = 1; ! 564: } ! 565: ! 566: /* Issue a QIO request on the input mailbox. ! 567: */ ! 568: static void ! 569: start_mbx_input () ! 570: { ! 571: sys$qio (process_ef, input_mbx_chan, IO$_READVBLK, &input_iosb, ! 572: mbx_input_ast, 0, mbx_buffer, sizeof (mbx_buffer), ! 573: 0, 0, 0, 0); ! 574: } ! 575: ! 576: /* Send a message to the subprocess input mailbox, without blocking if ! 577: * possible. ! 578: */ ! 579: static void ! 580: write_to_mbx (ptr, buf, len) ! 581: struct process_list *ptr; ! 582: char *buf; ! 583: int len; ! 584: { ! 585: sys$qiow (0, ptr->mbx_chan, IO$_WRITEVBLK | IO$M_NOW, &ptr->iosb, ! 586: 0, 0, buf, len, 0, 0, 0, 0); ! 587: } ! 588: ! 589: DEFUN ("setprv", Fsetprv, Ssetprv, 1, 3, 0, ! 590: "Set or reset a VMS privilege. First arg is privilege name.\n\ ! 591: Second arg is t or nil, indicating whether the privilege is to be\n\ ! 592: set or reset. Default is nil. Returns t if success, nil if not.\n\ ! 593: If third arg is non-nil, does not change privilege, but returns t\n\ ! 594: or nil depending upon whether the privilege is already enabled.") ! 595: (priv, value, getprv) ! 596: Lisp_Object priv, value, getprv; ! 597: { ! 598: int prvmask[2], prvlen, newmask[2]; ! 599: unsigned char * prvname; ! 600: int found, i; ! 601: struct privilege_list * ptr; ! 602: ! 603: CHECK_STRING (priv, 0); ! 604: priv = Fupcase (priv); ! 605: prvname = XSTRING (priv)->data; ! 606: prvlen = XSTRING (priv)->size; ! 607: found = 0; ! 608: prvmask[0] = 0; ! 609: prvmask[1] = 0; ! 610: for (i = 0; i < sizeof (priv_list) / sizeof (priv_list[0]); i++) ! 611: { ! 612: ptr = &priv_list[i]; ! 613: if (prvlen == strlen (ptr->name) && ! 614: bcmp (prvname, ptr->name, prvlen) == 0) ! 615: { ! 616: if (ptr->mask >= 32) ! 617: prvmask[1] = 1 << (ptr->mask % 32); ! 618: else ! 619: prvmask[0] = 1 << ptr->mask; ! 620: found = 1; ! 621: break; ! 622: } ! 623: } ! 624: if (! found) ! 625: error ("Unknown privilege name %s", XSTRING (priv)->data); ! 626: if (NULL (getprv)) ! 627: { ! 628: if (sys$setprv (NULL (value) ? 0 : 1, prvmask, 0, 0) == SS$_NORMAL) ! 629: return Qt; ! 630: return Qnil; ! 631: } ! 632: /* Get old priv value */ ! 633: if (sys$setprv (0, 0, 0, newmask) != SS$_NORMAL) ! 634: return Qnil; ! 635: if ((newmask[0] & prvmask[0]) ! 636: || (newmask[1] & prvmask[1])) ! 637: return Qt; ! 638: return Qnil; ! 639: } ! 640: ! 641: /* Retrieves VMS system information. */ ! 642: ! 643: #ifdef VMS4_4 /* I don't know whether these functions work in old versions */ ! 644: ! 645: DEFUN ("vms-system-info", Fvms_system_info, Svms_system_info, 1, 3, 0, ! 646: "Retrieve VMS process and system information.\n\ ! 647: The first argument (a string) specifies the type of information desired.\n\ ! 648: The other arguments depend on the type you select.\n\ ! 649: For information about a process, the second argument is a process ID\n\ ! 650: or a process name, with the current process as a default.\n\ ! 651: These are the possibilities for the first arg (upper or lower case ok):\n\ ! 652: account Returns account name\n\ ! 653: cliname Returns CLI name\n\ ! 654: owner Returns owner process's PID\n\ ! 655: grp Returns group number\n\ ! 656: parent Returns parent process's PID\n\ ! 657: pid Returns process's PID\n\ ! 658: prcnam Returns process's name\n\ ! 659: terminal Returns terminal name\n\ ! 660: uic Returns UIC number\n\ ! 661: uicgrp Returns formatted [UIC,GRP]\n\ ! 662: username Returns username\n\ ! 663: version Returns VMS version\n\ ! 664: logical Translates VMS logical name (second argument)\n\ ! 665: dcl-symbol Translates DCL symbol (second argument)\n\ ! 666: proclist Returns list of all PIDs on system (needs WORLD privilege)." ) ! 667: (type, arg1, arg2) ! 668: Lisp_Object type, arg1, arg2; ! 669: { ! 670: int i, typelen; ! 671: unsigned char * typename; ! 672: struct vms_objlist * ptr; ! 673: ! 674: CHECK_STRING (type, 0); ! 675: type = Fupcase (type); ! 676: typename = XSTRING (type)->data; ! 677: typelen = XSTRING (type)->size; ! 678: for (i = 0; i < sizeof (vms_object) / sizeof (vms_object[0]); i++) ! 679: { ! 680: ptr = &vms_object[i]; ! 681: if (typelen == strlen (ptr->name) ! 682: && bcmp (typename, ptr->name, typelen) == 0) ! 683: return (* ptr->objfn)(arg1, arg2); ! 684: } ! 685: error ("Unknown object type %s", typename); ! 686: } ! 687: ! 688: /* Given a reference to a VMS process, returns its process id. */ ! 689: ! 690: static int ! 691: translate_id (pid, owner) ! 692: Lisp_Object pid; ! 693: int owner; /* if pid is null/0, return owner. If this ! 694: * flag is 0, return self. */ ! 695: { ! 696: int status, code, id, i, numeric, size; ! 697: unsigned char * p; ! 698: int prcnam[2]; ! 699: static int dummy = JPI$_PID; ! 700: ! 701: if (NULL (pid) ! 702: || XTYPE (pid) == Lisp_String && XSTRING (pid)->size == 0 ! 703: || XTYPE (pid) == Lisp_Int && XFASTINT (pid) == 0) ! 704: { ! 705: code = owner ? JPI$_OWNER : JPI$_PID; ! 706: status = lib$getjpi (&code, 0, 0, &id); ! 707: if (! (status & 1)) ! 708: error ("Cannot find %s: %s", ! 709: owner ? "owner process" : "process id", ! 710: vmserrstr (status)); ! 711: return (id); ! 712: } ! 713: if (XTYPE (pid) == Lisp_Int) ! 714: return (XFASTINT (pid)); ! 715: CHECK_STRING (pid, 0); ! 716: pid = Fupcase (pid); ! 717: size = XSTRING (pid)->size; ! 718: p = XSTRING (pid)->data; ! 719: numeric = 1; ! 720: id = 0; ! 721: for (i = 0; i < size; i++, p++) ! 722: if (isxdigit (*p)) ! 723: { ! 724: id *= 16; ! 725: if (*p >= '0' && *p <= '9') ! 726: id += *p - '0'; ! 727: else ! 728: id += *p - 'A' + 10; ! 729: } ! 730: else ! 731: { ! 732: numeric = 0; ! 733: break; ! 734: } ! 735: if (numeric) ! 736: return (id); ! 737: prcnam[0] = XSTRING (pid)->size; ! 738: prcnam[1] = (int) XSTRING (pid)->data; ! 739: status = lib$getjpi (&dummy, 0, prcnam, &id); ! 740: if (! (status & 1)) ! 741: error ("Cannot find process id: %s", ! 742: vmserrstr (status)); ! 743: return (id); ! 744: } /* translate_id */ ! 745: ! 746: /* VMS object retrieval functions. */ ! 747: ! 748: static Lisp_Object ! 749: getjpi (jpicode, arg, numeric) ! 750: int jpicode; /* Type of GETJPI information */ ! 751: Lisp_Object arg; ! 752: int numeric; /* 1 if numeric value expected */ ! 753: { ! 754: int id, status, numval; ! 755: char str[128]; ! 756: int strdsc[2] = { sizeof (str), (int) str }; ! 757: short strlen; ! 758: ! 759: id = translate_id (arg, 0); ! 760: status = lib$getjpi (&jpicode, &id, 0, &numval, strdsc, &strlen); ! 761: if (! (status & 1)) ! 762: error ("Unable to retrieve information: %s", ! 763: vmserrstr (status)); ! 764: if (numeric) ! 765: return (make_number (numval)); ! 766: return (make_string (str, strlen)); ! 767: } ! 768: ! 769: static Lisp_Object ! 770: vms_account (arg1, arg2) ! 771: Lisp_Object arg1, arg2; ! 772: { ! 773: return getjpi (JPI$_ACCOUNT, arg1, 0); ! 774: } ! 775: ! 776: static Lisp_Object ! 777: vms_cliname (arg1, arg2) ! 778: Lisp_Object arg1, arg2; ! 779: { ! 780: return getjpi (JPI$_CLINAME, arg1, 0); ! 781: } ! 782: ! 783: static Lisp_Object ! 784: vms_grp (arg1, arg2) ! 785: Lisp_Object arg1, arg2; ! 786: { ! 787: return getjpi (JPI$_GRP, arg1, 1); ! 788: } ! 789: ! 790: static Lisp_Object ! 791: vms_image (arg1, arg2) ! 792: Lisp_Object arg1, arg2; ! 793: { ! 794: return getjpi (JPI$_IMAGNAME, arg1, 0); ! 795: } ! 796: ! 797: static Lisp_Object ! 798: vms_owner (arg1, arg2) ! 799: Lisp_Object arg1, arg2; ! 800: { ! 801: return getjpi (JPI$_OWNER, arg1, 1); ! 802: } ! 803: ! 804: static Lisp_Object ! 805: vms_parent (arg1, arg2) ! 806: Lisp_Object arg1, arg2; ! 807: { ! 808: return getjpi (JPI$_MASTER_PID, arg1, 1); ! 809: } ! 810: ! 811: static Lisp_Object ! 812: vms_pid (arg1, arg2) ! 813: Lisp_Object arg1, arg2; ! 814: { ! 815: return getjpi (JPI$_PID, arg1, 1); ! 816: } ! 817: ! 818: static Lisp_Object ! 819: vms_prcnam (arg1, arg2) ! 820: Lisp_Object arg1, arg2; ! 821: { ! 822: return getjpi (JPI$_PRCNAM, arg1, 0); ! 823: } ! 824: ! 825: static Lisp_Object ! 826: vms_terminal (arg1, arg2) ! 827: Lisp_Object arg1, arg2; ! 828: { ! 829: return getjpi (JPI$_TERMINAL, arg1, 0); ! 830: } ! 831: ! 832: static Lisp_Object ! 833: vms_uic_int (arg1, arg2) ! 834: Lisp_Object arg1, arg2; ! 835: { ! 836: return getjpi (JPI$_UIC, arg1, 1); ! 837: } ! 838: ! 839: static Lisp_Object ! 840: vms_uic_str (arg1, arg2) ! 841: Lisp_Object arg1, arg2; ! 842: { ! 843: return getjpi (JPI$_UIC, arg1, 0); ! 844: } ! 845: ! 846: static Lisp_Object ! 847: vms_username (arg1, arg2) ! 848: Lisp_Object arg1, arg2; ! 849: { ! 850: return getjpi (JPI$_USERNAME, arg1, 0); ! 851: } ! 852: ! 853: static Lisp_Object ! 854: vms_version_fn (arg1, arg2) ! 855: Lisp_Object arg1, arg2; ! 856: { ! 857: char str[256]; /* Max logical translation is 255 bytes. */ ! 858: int status; ! 859: int strdsc[2] = { sizeof (str), (int) str }; ! 860: short strlen; ! 861: static int dummy = SYI$_VERSION; ! 862: ! 863: status = lib$getsyi (&dummy, 0, strdsc, &strlen, 0, 0); ! 864: if (! (status & 1)) ! 865: error ("Unable to obtain version: %s", vmserrstr (status)); ! 866: return (make_string (str, strlen)); ! 867: } ! 868: ! 869: static Lisp_Object ! 870: vms_trnlog (arg1, arg2) ! 871: Lisp_Object arg1, arg2; ! 872: { ! 873: char str[1025]; /* Max symbol translation is 1024 bytes. */ ! 874: int status, symdsc[2]; ! 875: int strdsc[2] = { sizeof (str), (int) str }; ! 876: short length, level; ! 877: ! 878: CHECK_STRING (arg1, 0); ! 879: symdsc[0] = XSTRING (arg1)->size; ! 880: symdsc[1] = (int) XSTRING (arg1)->data; ! 881: status = lib$sys_trnlog (symdsc, &length, strdsc); ! 882: if (! (status & 1)) ! 883: error ("Unable to translate logical name: %s", vmserrstr (status)); ! 884: if (status == SS$_NOTRAN) ! 885: return (Qnil); ! 886: return (make_string (str, length)); ! 887: } ! 888: ! 889: static Lisp_Object ! 890: vms_symbol (arg1, arg2) ! 891: Lisp_Object arg1, arg2; ! 892: { ! 893: char str[100]; ! 894: int status, symdsc[2]; ! 895: int strdsc[2] = { sizeof (str), (int) str }; ! 896: short length, level; ! 897: ! 898: CHECK_STRING (arg1, 0); ! 899: symdsc[0] = XSTRING (arg1)->size; ! 900: symdsc[1] = (int) XSTRING (arg1)->data; ! 901: status = lib$get_symbol (symdsc, strdsc, &length, &level); ! 902: if (! (status & 1)) { ! 903: if (status == LIB$_NOSUCHSYM) ! 904: return (Qnil); ! 905: else ! 906: error ("Unable to translate symbol: %s", vmserrstr (status)); ! 907: } ! 908: return (make_string (str, length)); ! 909: } ! 910: ! 911: static Lisp_Object ! 912: vms_proclist (arg1, arg2) ! 913: Lisp_Object arg1, arg2; ! 914: { ! 915: Lisp_Object retval; ! 916: int id, status, pid; ! 917: static int dummy = JPI$_PID; ! 918: ! 919: retval = Qnil; ! 920: pid = -1; ! 921: for (;;) ! 922: { ! 923: status = lib$getjpi (&dummy, &pid, 0, &id); ! 924: if (status == SS$_NOMOREPROC) ! 925: break; ! 926: if (! (status & 1)) ! 927: error ("Unable to get process ID: %s", vmserrstr (status)); ! 928: retval = Fcons (make_number (id), retval); ! 929: } ! 930: return (Fsort (retval, intern ("<"))); ! 931: } ! 932: ! 933: DEFUN ("shrink-to-icon", Fshrink_to_icon, Sshrink_to_icon, 0, 0, 0, ! 934: "If emacs is running in a workstation window, shrink to an icon.") ! 935: () ! 936: { ! 937: static char result[128]; ! 938: static $DESCRIPTOR (result_descriptor, result); ! 939: static $DESCRIPTOR (tt_name, "TT:"); ! 940: static int chan = 0; ! 941: static int buf = 0x9d + ('2'<<8) + ('2'<<16) + (0x9c<<24); ! 942: int status; ! 943: static int temp = JPI$_TERMINAL; ! 944: ! 945: status = lib$getjpi (&temp, 0, 0, 0, &result_descriptor, 0); ! 946: if (status != SS$_NORMAL) ! 947: error ("Unable to determine terminal type."); ! 948: if (result[0] != 'W' || result[1] != 'T') /* see if workstation */ ! 949: error ("Can't shrink-to-icon on a non workstation terminal"); ! 950: if (!chan) /* assign channel if not assigned */ ! 951: if ((status = sys$assign (&tt_name, &chan, 0, 0)) != SS$_NORMAL) ! 952: error ("Can't assign terminal, %d", status); ! 953: status = sys$qiow (0, chan, IO$_WRITEVBLK+IO$M_BREAKTHRU, 0, 0, 0, ! 954: &buf, 4, 0, 0, 0, 0); ! 955: if (status != SS$_NORMAL) ! 956: error ("Can't shrink-to-icon, %d", status); ! 957: } ! 958: ! 959: #endif /* VMS4_4 */ ! 960: ! 961: init_vmsfns () ! 962: { ! 963: process_list = 0; ! 964: input_mbx_chan = 0; ! 965: } ! 966: ! 967: syms_of_vmsfns () ! 968: { ! 969: defsubr (&Sdefault_subproc_input_handler); ! 970: defsubr (&Sspawn_subprocess); ! 971: defsubr (&Ssend_command_to_subprocess); ! 972: defsubr (&Sstop_subprocess); ! 973: defsubr (&Ssetprv); ! 974: #ifdef VMS4_4 ! 975: defsubr (&Svms_system_info); ! 976: defsubr (&Sshrink_to_icon); ! 977: #endif /* VMS4_4 */ ! 978: Qdefault_subproc_input_handler = intern ("default-subprocess-input-handler"); ! 979: staticpro (&Qdefault_subproc_input_handler); ! 980: } ! 981: #endif /* VMS */ ! 982:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.