/*This takes a single parameter: s = set the ipid in system space to the ipid of this process g = get the ipid from system space and print it out -- doesn't need privs p = queue the print_it routine to the process whose ipid is in system space -- needs CMKRNL The SET option would need CMKRNL if I didn't use the user written system service since it writes into a protected system page. The GET option doesn't need privs since it reads from a world readable location in system space. As such, there are several ways to call it by an unpriviledged user: 1) It could still go through the user written system service anyway (for convenience). 2) Another alternative would be to translate the MY_EXECLET_VECTOR logical name in this routine and then just make a call to the routine specified by the appropriate address, just as is done in the UWSS. 3) A third alternative (which I'm using here) is for the UWSS to export (via a symbol_vector) the address of the routine. This saves the overhead of calling through the system service, doing the CMKRNL, etc. Note that in this case, the symbol vector is of the type DATA rather than PROCEDURE, even though it points to a procedure. The PRINT option also needs CMKRNL. The UWSS grants that implicitly by virtue of it being a system service, and the execlet verifies that its caller has CMKRNL. Graphically, calls from this routine go as follows: CALL_MY_EXECLET.C MY_UWSS.MAR MY_EXECLET.MAR +--------------------------+ +--------------------+ +-------------------+ | | | | | | | set_value(); --+----+--> SET_VALUE --+----+--> SET_VALUE | | | | | | | | print_message(); --+----+--> PRINT_MESSAGE --+----+--> PRINT_MESSAGE | | | | | | | | | +--------------------+ | | | | | | | (*get_value_addr)(); --+------------------------------+--> GET_VALUE | | | | | +--------------------------+ +-------------------+ This shows how the routines SET_VALUE and PRINT_MESSAGE (which require privs to execute) go through the UWSS, while GET_VALUE (which does not require privs) goes directly to the EXECLET. */ #include #include #include /* Declare the routines exported by the user-written system service */ int initialize(); int (*get_value_addr)(long *); int print_message(); int set_value(); main(int argc, char *argv []) { long value; long ipid; int status; if (argc >= 2) { switch (argv[1][0]) { case 'G': case 'g': /* Call the GET routine */ /* First we will probably need to call the initialization routine in the UWSS, which will get the addresses of data and routines which were loaded by the execlet. Note that one of these datum is get_value_addr, which is what we're ultimately calling here and is the address of the routine in the execlet. If the call here had been to get_value instead of to get_value_addr (which is in the UWSS instead of in the execlet), we wouldn't need to call initialize() first. All of the routines in the UWSS will end up calling initialize, so if we already called *any* of the UWSS routines, the address of get_value_addr will not be NULL and we won't need to call the initialize() routine. */ if (*get_value_addr == NULL) { status = initialize(); if ((status & 1) == 0) lib$signal(status); } status = (*get_value_addr)(&value); if ((status & 1) == 0) lib$signal(status); printf("value is %x\n", value); break; case 'P': case 'p': /* Call the QUEUE-AST-TO-PRINT routine */ status = print_message(); if ((status & 1) == 0) lib$signal(status); break; case 'S': case 's': /* Call the SET routine */ status = set_value(); if ((status & 1) == 0) lib$signal(status); break; /* Default -- kindly inform the user that they called the routine incorrectly */ default: printf("Nimwit! You don't know what you're talking about!!!\n"); } } else /* Kindly inform the user that they called the routine incorrectly */ printf("Nimwit! You don't know what you're talking about!!!\n"); }