Date: Fri, 28 Nov 86 11:53:16 est From: David Krowitz Subject: software for Apollo transparent file access to Alliant Below the dashed line you will find the bundled files for the University of Utah's version of the V2 program with some minor bug fixes made by Jim Rees of Apollo and myself. V2 is a demo program originally written by Jim to show how an Apollo network could get transparent file access to any BSD 4.2 system running TCP/IP. The University of Utah (Jim Peterson, I think) fixed it up and expanded the capabilities of the original program and we have since fixed some bugs so that it will compile and run under AEGIS version SR9.2.3 (on the Apollos) and rev 1.0 or rev 2.0 on the Alliant. In a couple of weeks we will have our Sun 3/160 hooked up to our ethernet and I will be able to test this version on that machine. This package should be put in both the Apollo library and the Alliant library at ANL-MCS, although most of the files are for the Apollo end of the connection. -- David Krowitz ---------------------------------------------------------------------------- # To unbundle, sh this file echo Makefile 1>&2 cat >Makefile <<'End of Makefile' # # NOTE: On the Vax side, it only makes sense to build V2D (the deamon) # DESTDIR= CFLAGS= -g DOBJ=v2d.o all: v2d install: install -m 500 v2d ${DESTDIR}/etc/v2d clean: rm -f v2d *.o v2d: $(DOBJ) cc $(CFLAGS) -o v2d $(DOBJ) End of Makefile echo Readme 1>&2 cat >Readme <<'End of Readme' This is the version of the V2 program distributed by the University of Utah with some bug fixes by David Krowitz of MIT and Jim Rees of Apollo. It has been tested under SR9.2.3 running with an Alliant FX/1 (an Apollo DSP9000). -- David Krowitz 11/28/86 mit-erl!mit-kermit!krowitz@eddie.mit.edu mit-erl!mit-kermit!krowitz@mit-eddie.arpa david@mit-mc.arpa (in order of decreasing preference) ----------------------------------------------------------------------------- This is just an example of how one might use the Open System Toolkit to build a simple-minded file system interconnect from your Apollo network to a vanilla bsd4.2 system. NOTE WELL: We have no plans to turn this into a product. It has a lot of deficiencies, like performance and security. You need to be running sr9.2 or later, to get this to run. To build the Apollo side of things, do (to a DOMAIN/IX shell): make types (Makes the types) make install (Makes and install the v2 manager) make crv2 (Makes the program that makes the gateway object) Then edit the file /etc/services on your Apollo Domain/IX node to define which TCP/IP socket will be used by V2 (we use socket # 600 here at MIT) before running CRV2 to create the gateway object. To install the server on your bsd4.2 system, first copy Makefile, attr.h, v2d.h, and v2d.c to your 4.2 machine. Do 'make v2d' on the 4.2 machine. If you have inetd on your 4.2 machine, you can use v2d directly. Otherwise, you will have to start it by hand or from /etc/rc, and give it the '-s' flag. You will need to either add v2d to /etc/services or use the '-p' option to v2d. Use crv2 to make a gateway object: crv2 (Makes the gateway object) You should shut down your node and reboot it in order to install the new type managers. If the node is a partner for diskless nodes (or if lots of people are using files from the node) you can type 'exit' to the DM to bring the node down to the level-2 shell and then 'go' to bring the node back up. This will kill all of the processes running on the node, but will leave disk I/O service intact. If your 4.2 user ids aren't the same as the ones on your Apollo network, you will get strange behavior. There is a translation table at the end of open.c that you can use to partly offset this. If you are security conscious, you may want to just run v2d as a guest rather than as root. Good luck! End of Readme echo attr.c 1>&2 cat >attr.c <<'End of attr.c' #include #include #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "/sys/ins/cal.ins.c" #include "v2.h" #include "v2d.h" #define decade_1970 (3652 * 24 * 3600) extern status_$t unix_fio_$status; v2_$inq_file_attr(hpp, dtcp, dtmp, dtup, blksp, stp) v2_handle_t **hpp; time_$clockh_t *dtcp, *dtmp, *dtup; long *blksp; status_$t *stp; { v2_handle_t *hp; struct attr atb; time_$clock_t clock; stp->all = status_$ok; hp = *hpp; if (v2_$stat(hp, &atb) < 0) { *stp = unix_fio_$status; return; } cal_$sec_to_clock(atb.atime - decade_1970, clock); *dtup = clock.high; cal_$sec_to_clock(atb.mtime - decade_1970, clock); *dtcp = *dtmp = clock.high; *blksp = atb.blocks; } End of attr.c echo attr.h 1>&2 cat >attr.h <<'End of attr.h' struct attr { long mode; long uid; long gid; long atime; long mtime; long size; long blocks; }; End of attr.h echo crv2.c 1>&2 cat >crv2.c <<'End of crv2.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/error.ins.c" #include "/sys/ins/ms.ins.c" #include #include #include #include #include int accept_port; main(ac, av) int ac; char *av[]; { struct servent *sp; struct sockaddr_in saddr; struct hostent *hp; char *p, sbuf[80]; long len; status_$t st; while (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 'p': accept_port = atoi(av[2]); ac--; av++; break; } ac--; av++; } if (ac != 3) { fprintf(stderr, "usage: crv2 \n"); exit(1); } if (accept_port == 0) { if ((sp = getservbyname("v2d", 0)) == NULL) { fprintf(stderr, "can't find port in /etc/services\n"); exit(1); } accept_port = sp->s_port; } if ((hp = gethostbyname(av[1])) == NULL) { fprintf(stderr, "can't find address for host %s\n", av[1]); exit(1); } saddr.sin_family = AF_INET; saddr.sin_port = accept_port; bcopy(hp->h_addr, &saddr.sin_addr, sizeof saddr.sin_addr); p = ms_$crmapl(*(av[2]), (short) strlen(av[2]), 0L, (long) sizeof saddr, ms_$nr_xor_1w, st); if (st.all) { error_$print(st); exit(1); } bcopy(&saddr, p, sizeof saddr); ms_$unmap(p, 1024L, st); sprintf(sbuf, "/com/obty %s v2", av[2]); system(sbuf); exit(0); } End of crv2.c echo dir_open.c 1>&2 cat >dir_open.c <<'End of dir_open.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "/sys/ins/io_traits.ins.c" #include "v2.h" #include "v2d.h" extern io_$epv v2_$io_epv; ios_$id_t v2_dir_$open(hpp, resid, resid_lenp, ooptsp, stp) v2_handle_t **hpp; char *resid; short *resid_lenp; ios_$open_options_t *ooptsp; status_$t *stp; { v2_handle_t *dhp, *hp; char name[1024]; uid_$t tuid; char *epv_ptr; /* not really */ dhp = *hpp; sprintf(name, "%s/%.*s", dhp->name, *resid_lenp, resid); v2_open(&(dhp->xoid), name, strlen(name), ios_$preserve_mode, *ooptsp, &uid_$nil, &hp, &tuid, stp); if (stp->all != status_$ok) return; return ios_$connect("", 0, tuid, hp, &v2_$io_epv, *stp); } End of dir_open.c echo equal.c 1>&2 cat >equal.c <<'End of equal.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "v2.h" #include "v2d.h" boolean v2_$equal(hpp1, hpp2, stp) v2_handle_t **hpp1, **hpp2; status_$t *stp; { v2_handle_t *hp1, *hp2; hp1 = *hpp1; hp2 = *hpp2; stp->all = status_$ok; return (!strcmp(hp1->name, hp2->name) ? true : false); } End of equal.c echo flag.c 1>&2 cat >flag.c <<'End of flag.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "v2.h" #include "v2d.h" ios_$mgr_flag_set v2_$inq_mgr_flags(hpp, stp) v2_handle_t **hpp; status_$t *stp; { stp->all = status_$ok; return (ios_$mgr_flag_set) ( (int) ios_$mf_create_mask | (int) ios_$mf_create_bak_mask | (int) ios_$mf_imex_mask | (int) ios_$mf_fork_mask | (int) ios_$mf_write_mask | (int) ios_$mf_seek_abs_mask | (int) ios_$mf_seek_short_mask | (int) ios_$mf_seek_full_mask | (int) ios_$mf_seek_byte_mask | (int) ios_$mf_seek_rec_mask | (int) ios_$mf_seek_bof_mask | (int) ios_$mf_rec_type_mask | (int) ios_$mf_truncate_mask | (int) ios_$mf_unregulated_mask | (int) ios_$mf_sparse_mask | (int) ios_$mf_read_intend_write_mask); } ios_$conn_flag_set v2_$inq_conn_flags(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; ios_$conn_flag_set flags; hp = *hpp; flags = 0; if (hp->unreg) flags |= ios_$cf_unregulated_mask; if (hp->append_mode) flags |= ios_$cf_append_mask; if (!hp->read_only) flags |= ios_$cf_write_mask; stp->all = status_$ok; return flags; } v2_$set_conn_flag(hpp, fp, boolp, stp) v2_handle_t **hpp; ios_$conn_flag_t *fp; boolean *boolp; status_$t *stp; { v2_handle_t *hp; hp = *hpp; if (hp->inq_only) { stp->all = ios_$inq_only_error; return; } stp->all = status_$ok; switch (*fp) { case ios_$cf_append: hp->append_mode = *boolp; break; case ios_$cf_read_intend_write: case ios_$cf_write: if (*boolp && hp->cant_write) stp->all = ios_$insufficient_rights; else hp->read_only = *boolp ? false : true; break; case ios_$cf_unregulated: hp->unreg = *boolp; break; default: stp->all = ios_$illegal_operation; break; } } ios_$obj_flag_set v2_$inq_obj_flags(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; ios_$obj_flag_set flags; hp = *hpp; flags = ios_$of_sparse_ok_mask; if (hp->delete) flags |= ios_$of_delete_on_close_mask; if (hp->type == v2f_$uid) flags |= ios_$of_ascii_mask; stp->all = status_$ok; return flags; } v2_$set_obj_flag(hpp, fp, boolp, stp) v2_handle_t **hpp; ios_$obj_flag_t *fp; boolean *boolp; status_$t *stp; { v2_handle_t *hp; hp = *hpp; if (hp->inq_only) { stp->all = ios_$inq_only_error; return; } stp->all = status_$ok; switch (*fp) { case ios_$of_delete_on_close: hp->delete = *boolp; break; case ios_$of_ascii: case ios_$of_sparse_ok: if (!(*boolp)) stp->all = ios_$illegal_operation; break; case ios_$of_ftncc: if (*boolp) stp->all = ios_$illegal_operation; break; default: stp->all = ios_$illegal_operation; break; } } End of flag.c echo fork.c 1>&2 cat >fork.c <<'End of fork.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "/sys/ins/rws.ins.c" #include "v2.h" #include "v2d.h" extern short pm_$level; v2_$export(hpp, bp, sizep, lenp, stp) v2_handle_t **hpp; char *bp; short *sizep, *lenp; status_$t *stp; { v2_handle_t *hp; v2_$pre_fork(hpp, stp); if (stp->all != status_$ok) return; *lenp = sizeof (v2_handle_t); if (*lenp > *sizep) return; hp = *hpp; bcopy(hp, bp, sizeof (v2_handle_t)); v2_$post_fork(hpp, stp); } v2_$import(bp, hpp, stp) char *bp; v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; ios_$id_t fd; int n; hp = (v2_handle_t *) rws_$alloc_heap_pool(rws_$stream_tm_pool, (long) sizeof (v2_handle_t)); if (hp == NULL) { stp->all = ios_$insuff_memory; return; } bcopy(bp, hp, sizeof (v2_handle_t)); hp->sock_fd = -1; hp->level = pm_$level; hp->sock_fd = sconnect(&(hp->xoid), stp); if (stp->all != status_$ok) return; putlong(C_OPEN); n = strlen(hp->name); putlong(n); putbytes(hp->name, n); putlong(hp->read_only ? 0 : 2); if ((n = getlong()) < 0) { close(hp->sock_fd); hp->sock_fd = -1; stp->all = v2_tr_errno(-1 - n); return; } fd = ios_$switch((ios_$id_t) hp->sock_fd, ios_$max, *stp); hp->sock_fd = fd; *hpp = hp; stp->all = status_$ok; } v2_$pre_fork(hpp, stp) v2_handle_t **hpp; status_$t *stp; { /* no seek keys yet */ stp->all = status_$ok; } v2_$post_fork(hpp, stp) v2_handle_t **hpp; status_$t *stp; { /* no ref counts yet */ stp->all = status_$ok; } End of fork.c echo get.c 1>&2 cat >get.c <<'End of get.c' #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "v2.h" #include "v2d.h" extern status_$t unix_fio_$status; v2_$get(hpp, optp, bp, buf_lenp, stp) v2_handle_t **hpp; ios_$put_get_opts_t *optp; char *bp; long *buf_lenp; status_$t *stp; { v2_handle_t *hp; int i, n, ret; stp->all = status_$ok; hp = *hpp; if (*optp & ios_$no_rec_bndry_opt) putlong(C_READ); else putlong(C_RDLN); putlong(*buf_lenp); n = getlong(hp->sock_fd); if (n < 0) { *stp = unix_fio_$status; return 0; } if (n == 0) { stp->all = ios_$end_of_file; return 0; } ret = n; while (n > 0) { if ((i = read(hp->sock_fd, bp, n)) < 0) { *stp = unix_fio_$status; return 0; } n -= i; bp += i; } return ret; } v2_$inq_rec_remainder(hpp, stp) v2_handle_t **hpp; status_$t *stp; { stp->all = ios_$illegal_operation; return 0; } End of get.c echo init.c 1>&2 cat >init.c <<'End of init.c' /* Turn this on for SR9.2.BL11 - this is because there is * a bug in the streams library causing it to return a bogus * status code from underneath. Thus we define our own * procedure to clear it out. */ #define FORCE_WRITE_BUG #include "/sys/ins/base.ins.c" #include "/sys/ins/ios.ins.c" #include "/sys/ins/trait.ins.c" #include "/sys/ins/io_traits.ins.c" #include "/sys/ins/ios_dir_trait.ins.c" #include "/sys/ins/pfm.ins.c" #include "v2.h" extern void v2_$openx(), v2_$create(), v2_$change_name(), v2_$inq_name(); extern void v2_$export() ; extern void v2_$import() ; extern void v2_$pre_fork() ; extern void v2_$post_fork() ; extern boolean v2_$close() ; extern void v2_$get_ec(); extern ios_$mgr_flag_set v2_$inq_mgr_flags(); extern ios_$obj_flag_set v2_$inq_obj_flags(); extern void v2_$set_obj_flag(); extern ios_$conn_flag_set v2_$inq_conn_flags(); extern void v2_$set_conn_flag(); extern long int v2_$get(); extern long int v2_$locate(); extern void v2_$put(); extern long int v2_$inq_rec_remainder(); extern void v2_$seek() ; extern void v2_$seek_full_key() ; extern void v2_$seek_short_key() ; extern void v2_$seek_to_bof() ; extern void v2_$seek_to_eof() ; extern unsigned long int v2_$inq_short_key() ; extern void v2_$inq_full_key(); extern long int v2_$inq_rec_pos(); extern long int v2_$inq_byte_pos() ; extern void v2_$truncate() ; extern long int v2_$inq_cur_rec_len() ; extern ios_$rtype_t v2_$inq_rec_type() ; extern void v2_$set_rec_type() ; #ifndef FORCE_WRITE_BUG extern void v2_$force_write_file() ; #endif extern void v2_$inq_file_attr() ; extern boolean v2_$equal() ; extern ios_$id_t v2_dir_$open(); #ifdef FORCE_WRITE_BUG void v2_$force_write_file(hand, st) v2_handle_t **hand; status_$t *st; { st->all = status_$ok; } #endif /* This is a crock. I'll have to speak to the compiler people about this. Meanwhile, ignore the warnings this produces. */ long nilp[2] = {0, 0}; io_xoc_$epv v2_$openx_epv = { v2_$openx, v2_$create, v2_$change_name, v2_$inq_name, }; io_$epv v2_$io_epv = { v2_$export, v2_$import, v2_$pre_fork, v2_$post_fork, v2_$close, v2_$get_ec, v2_$inq_mgr_flags, v2_$inq_obj_flags, v2_$set_obj_flag, v2_$inq_conn_flags, v2_$set_conn_flag, v2_$get, nilp, v2_$put, nilp, v2_$seek, v2_$seek_full_key, v2_$seek_short_key, v2_$seek_to_bof, v2_$seek_to_eof, v2_$inq_short_key, v2_$inq_full_key, nilp, v2_$inq_byte_pos, v2_$truncate, nilp, v2_$inq_rec_type, v2_$set_rec_type, #ifdef FORCE_WRITE_BUG v2_$force_write_file, #else nilp, #endif v2_$inq_file_attr, v2_$equal, }; ios_dir_$epv v2_$dir_epv = { nilp, nilp, v2_dir_$open, }; #define kind(x) (trait_$kind_t) (1 << (int) x) ios_$initialize() { status_$t st; trait_$mgr_dcl(v2_$uid, io_$trait, kind(trait_$kind_local) | kind(trait_$kind_near_remote), &v2_$io_epv, st); if (st.all != status_$ok) pfm_$error_trap(st); trait_$mgr_dcl(v2_$uid, io_xoc_$trait, kind(trait_$kind_local) | kind(trait_$kind_near_remote), &v2_$openx_epv, st); if (st.all != status_$ok) pfm_$error_trap(st); trait_$mgr_dcl(v2f_$uid, io_$trait, kind(trait_$kind_local) | kind(trait_$kind_near_remote), &v2_$io_epv, st); if (st.all != status_$ok) pfm_$error_trap(st); trait_$mgr_dcl(v2f_$uid, io_xoc_$trait, kind(trait_$kind_local) | kind(trait_$kind_near_remote), &v2_$openx_epv, st); if (st.all != status_$ok) pfm_$error_trap(st); trait_$mgr_dcl(v2_$uid, ios_dir_$trait, kind(trait_$kind_local) | kind(trait_$kind_near_remote), &v2_$dir_epv, st); if (st.all != status_$ok) pfm_$error_trap(st); } End of init.c echo ios.ins.c 1>&2 cat >ios.ins.c <<'End of ios.ins.c' /**** WARNING - kludged to have the ios_$xx_mask entries and such * - these were missing from the copy in the sources... * (should get a new copy from Stanzel?) * jwp */ /* IOS.INS.C, /SYS/INS, JAH, 03/28/85 */ /* I/O Switch Calls -- replaces stream.ins.pas */ #define ios_$switch_modc 0x01270000 /* -=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ /* -=-=-=- E R R O R S T A T U S C O D E S -=-=-=-=- */ /* -=-=-=- all st.code components are greater than zero -=-=-=-=- */ /* -=-=-=- (see warning status codes below...) -=-=-=-=- */ /* -=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ #define ios_$not_open (ios_$switch_modc + 1) /* operation attempted on unopened stream */ #define ios_$illegal_operation (ios_$switch_modc + 2) /* this operation illegal on named stream */ #define ios_$from_id_not_open (ios_$switch_modc + 3) /* from stream not open on switch request */ #define ios_$no_avail_target (ios_$switch_modc + 4) /* no available target stream to switch to */ #define ios_$target_inuse (ios_$switch_modc + 5) /* target id already in use on switch */ #define ios_$illegal_obj_type (ios_$switch_modc + 6) /* cannot open a stream for this type of object */ #define ios_$no_more_streams (ios_$switch_modc + 7) /* no more streams */ #define ios_$concurrency_violation (ios_$switch_modc + 8) /* requested access violates concurrency constraints */ #define ios_$end_of_file (ios_$switch_modc + 9) /* end of file */ #define ios_$insuff_memory (ios_$switch_modc + 10) /* not enough virtual memory */ #define ios_$perm_file_needs_name (ios_$switch_modc + 11) /* only temporary files may be unnamed */ #define ios_$put_bad_rec_len (ios_$switch_modc + 12) /* attempted put of wrong length record */ #define ios_$internal_fatal_err (ios_$switch_modc + 13) /* internal fatal error on table re-verification */ #define ios_$already_exists (ios_$switch_modc + 14) /* ios_$no_pre_exist specified on ios_$create */ #define ios_$illegal_w_var_lgth_recs (ios_$switch_modc + 15) /* operation illegal with variable length records is on record boundary */ #define ios_$BOF_err (ios_$switch_modc + 17) /* attempted seek beyond BOF; e.g.,offset= ios_$switch_modc +0 */ #define ios_$bad_char_seek (ios_$switch_modc + 18) /* attempted character seek before start of current (variable length) record */ #define ios_$bad_open_XP (ios_$switch_modc + 19) /* open_XP must reference a stream that is already open in this process */ #define ios_$bad_count_field_in_file (ios_$switch_modc + 20) /* count field for current record is bad */ #define ios_$name_not_found (ios_$switch_modc + 21) /* name not found */ #define ios_$bad_file_hdr (ios_$switch_modc + 22) /* file hdr is no good ( CRC error ) */ #define ios_$bad_location (ios_$switch_modc + 23) /* bad location param in create call */ #define ios_$id_oor (ios_$switch_modc + 26) /* stream id out-of-range (invalid) */ #define ios_$object_not_found (ios_$switch_modc + 28) /* object associated with this name not found (may not exist) */ #define ios_$illegal_name_redefine (ios_$switch_modc + 31) /* attempted name change requires copying file*/ #define ios_$obj_deleted (ios_$switch_modc + 32) /* file has been deleted */ #define ios_$name_reqd (ios_$switch_modc + 33) /* ios_$open with no name illegal */ #define ios_$resource_lock_err (ios_$switch_modc + 36) /* unable to lock resources required to process request */ #define ios_$illegal_pad_create_type (ios_$switch_modc + 37) /* pad_create illegal with this type of object */ #define ios_$internal_mm_err (ios_$switch_modc + 38) /* internal fatal error in stream memory mgmt (windowing) */ #define ios_$read_only_err (ios_$switch_modc + 39) /* attempted write to read-only stream */ #define ios_$something_failed (ios_$switch_modc + 42) /* partial or complete failure of inquire or redefine (err_mask is non-empty) */ #define ios_$device_must_be_local (ios_$switch_modc + 43) /* cannot open stream to remote device */ #define ios_$no_rights (ios_$switch_modc + 44) /* no rights to access object */ #define ios_$insufficient_rights (ios_$switch_modc + 45) /* insufficient rights for requested access to object */ #define ios_$invalid_data (ios_$switch_modc + 46) /* bad data in call to vt_$put */ #define ios_$no_table_space (ios_$switch_modc + 47) /* obsolete */ #define ios_$need_move_mode (ios_$switch_modc + 48) /* locate operation refused -- try get */ #define ios_$out_of_shared_cursors (ios_$switch_modc + 50) /* per-mode shared file cursor pool exhausted */ #define ios_$bad_shared_cursor_refcnt (ios_$switch_modc + 51) /* ref cnt on a shared file cursor went below zero */ #define ios_$xp_buf_too_small (ios_$switch_modc + 52) /* buffer supplied to get_xp too small */ #define ios_$illegal_param_comb (ios_$switch_modc + 53) /* illegal parameter combination for this operation */ #define ios_$dir_not_found (ios_$switch_modc + 54) /* couldn't find directory in pathname */ #define ios_$never_closed (ios_$switch_modc + 55) /* system (or process) crash prevented complete close */ /* actually => header all zero */ #define ios_$sio_not_local (ios_$switch_modc + 57) /* sio object not in /dev */ #define ios_$not_thru_link (ios_$switch_modc + 58) /* can't create file though link */ #define ios_$object_read_only (ios_$switch_modc + 60) /* cannot open this object for writing */ #define ios_$put_conditional_failed (ios_$switch_modc + 61) /* a put conditional operation could not be done now */ #define ios_$get_conditional_failed (ios_$switch_modc + 62) /* a get conditional operation found no data */ #define ios_$not_at_rec_bndry (ios_$switch_modc + 63) /* can't do inq_short_key */ #define ios_$cant_change_type (ios_$switch_modc + 64) /* */ #define ios_$inq_only_error (ios_$switch_modc + 65) /* opened for inquire only */ #define ios_$file_not_empty (ios_$switch_modc + 66) /* type change rejected because file not empty */ #define ios_$buffer_too_big (ios_$switch_modc + 67) /* this manager does not support this operation */ /* for a buffer that is this large */ #define ios_$cant_initialize (ios_$switch_modc + 68) /* can't initialize an object of this type */ #define ios_$flag_not_supported (ios_$switch_modc + 69) /* flag not supported by manager */ #define ios_$cant_set_advisory_lock (ios_$switch_modc + 70) /* advisory lock was already set by someone else */ #define ios_$no_advisory_lock_set (ios_$switch_modc + 71) /* advisory lock was not already set in UNLOCK */ /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ /* -=-=-=-=-= W A R N I N G S T A T U S C O D E S =-=-=-=-=-=- */ /* -=-=-=-=-= all st.code components are less than zero =-=-=-=-=-=- */ /* -=-=-=-=-= (see error status codes above...) =-=-=-=-=-=- */ /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */ #define ios_$part_rec_warn (ios_$switch_modc + 0x0fffc) /* partial record at eof on close -- warning only -4 */ #define ios_$cant_delete_old_name (ios_$switch_modc + 0x0fffb) /* new name added but old can't be deleted -5 */ #define ios_$buffer_too_small (ios_$switch_modc + 0x0fffa) /* buffer too small on get/locate -6 */ #define ios_$full_rec_unavail (ios_$switch_modc + 0x0fff9) /* GET requested a full record, but only part of -7 */ /* the record was available. The part that was */ /* available was returned, but there was */ /* still more room in the buffer. */ #define ios_$max 127 typedef short ios_$id_t; typedef struct { linteger rec_adr; linteger byte_adr; } ios_$seek_key_t; typedef enum { ios_$rec_seek, /* record-oriented seek */ ios_$byte_seek /* byte-oriented seek */ } ios_$seek_type_t; typedef enum { ios_$relative, /* seek is relative to current position */ ios_$absolute /* seek is relative to BOF */ } ios_$abs_rel_t; typedef enum { ios_$current, /* inquiry is for current position */ ios_$bof, /* inquire of key to use for BOF */ ios_$eof /* inquire of key to use for EOF */ } ios_$pos_opt_t; typedef enum { ios_$V1, /* variable lgth records with counts */ ios_$F2, /* fixed lgth records (with counts) */ ios_$UNDEF, /* no record structure in data; file has header, however */ ios_$explicit_F2, /* like F2, but cannot be implicitly changed to V1 by put_rec */ ios_$F1 /* records without count fields -- not currently implemented */ } ios_$rtype_t; /* Key type parameter for ios_$get_ec */ typedef enum { ios_$get_ec_key, ios_$put_ec_key } ios_$ec_key_t; /* options avail at open or create time, through ios_$open or ios_$create */ #define ios_$no_open_options ((ios_$open_options_t) 0x00) #define ios_$no_open_delay_opt ((ios_$open_options_t) 0x01) #define ios_$write_opt ((ios_$open_options_t) 0x02) #define ios_$unregulated_opt ((ios_$open_options_t) 0x04) #define ios_$position_to_eof_opt ((ios_$open_options_t) 0x08) #define ios_$inquire_only_opt ((ios_$open_options_t) 0x10) typedef short ios_$open_options_t; /* creation mode specifies what to do if name already exists; only the loc_name_only_mode is relevant if the name does NOT exist */ typedef enum { ios_$no_pre_exist_mode, /* exists => error */ ios_$preserve_mode, /* exists => preserve old contents */ ios_$recreate_mode, /* exists => completely recreate file */ ios_$truncate_mode, /* exists => open, then truncate */ ios_$make_backup_mode, /* exists => rename to .bak on close */ ios_$loc_name_only_mode /* name is to specify location only */ } ios_$create_mode_t; /* options for data transfer operations */ #define ios_$no_put_get_opts ((ios_$put_get_opts_t) 0x00) #define ios_$cond_opt ((ios_$put_get_opts_t) 0x01) #define ios_$preview_opt ((ios_$put_get_opts_t) 0x02) #define ios_$partial_record_opt ((ios_$put_get_opts_t) 0x04) #define ios_$no_rec_bndry_opt ((ios_$put_get_opts_t) 0x08) typedef short ios_$put_get_opts_t; /* boolean file attributes that can be set/inquired by ios_$inq_flags and ios_$set_flag */ typedef enum { ios_$ascii, /* writer declares data to be ascii */ ios_$append, /* position to EOF on each put */ ios_$writable, /* OK to modify file */ ios_$delete_on_close, /* file will be deleted when closed */ ios_$unregulated, /* concurrent writers OK */ ios_$ftn, /* use fortran carriage control when printing */ ios_$sparse, /* records may be missing */ ios_$is_a_ipc, /* behaves like inter-process communication channel */ ios_$is_a_tty, /* behaves like "terminal" */ ios_$is_a_vt, /* behaves like an Apollo pad */ ios_$no_put_get_delay, /* add ios_$cond to each get/locate */ } ios_$flag_t; typedef enum { ios_$mf_create, /* Create new files */ ios_$mf_create_bak, /* Create ".bak" files */ ios_$mf_imex, /* Export streams to new processes */ ios_$mf_fork, /* Pass streams to forked processes */ ios_$mf_force_write, /* Force files contents to "disk" */ ios_$mf_write, /* Write files */ ios_$mf_seek_abs, /* Seek using absolute positions */ ios_$mf_seek_short, /* Seek using short keys */ ios_$mf_seek_full, /* Seek using full keys */ ios_$mf_seek_byte, /* Seek to byte positions */ ios_$mf_seek_rec, /* Seek to record positions */ ios_$mf_seek_bof, /* Seek to end of file */ ios_$mf_rec_type, /* Support different (or any) type of record */ ios_$mf_truncate, /* Truncate files */ ios_$mf_unregulated, /* Support unregulated (concurrent) access */ ios_$mf_sparse, /* Support sparse files */ ios_$mf_read_intend_write, /* Support read-intend-write locking */ ios_$mf_reserved_18, ios_$mf_reserved_19, ios_$mf_reserved_20, ios_$mf_reserved_21, ios_$mf_reserved_22, ios_$mf_reserved_23, ios_$mf_reserved_24, ios_$mf_reserved_25, ios_$mf_reserved_26, ios_$mf_reserved_27, ios_$mf_reserved_28, ios_$mf_reserved_29, ios_$mf_reserved_30, ios_$mf_reserved_31, ios_$mf_reserved_32 } ios_$mgr_flag_t; typedef enum { ios_$of_delete_on_close,/* Will be deleted when closed */ ios_$of_sparse_ok, /* Can be seeked and written past EOF */ ios_$of_ascii, /* Contains ASCII data */ ios_$of_ftncc, /* Contains Fortran carriage control */ ios_$of_cond, /* Makes get/put implicitly include ios_$cond */ ios_$of_reserved_6, ios_$of_reserved_7, ios_$of_reserved_8, ios_$of_reserved_9, ios_$of_reserved_10, ios_$of_reserved_11, ios_$of_reserved_12, ios_$of_reserved_13, ios_$of_reserved_14, ios_$of_reserved_15, ios_$of_reserved_16, ios_$of_reserved_17, ios_$of_reserved_18, ios_$of_reserved_19, ios_$of_reserved_20, ios_$of_reserved_21, ios_$of_reserved_22, ios_$of_reserved_23, ios_$of_reserved_24, ios_$of_reserved_25, ios_$of_reserved_26, ios_$of_reserved_27, ios_$of_reserved_28, ios_$of_reserved_29, ios_$of_reserved_30, ios_$of_reserved_31, ios_$of_reserved_32 } ios_$obj_flag_t; typedef enum { ios_$cf_tty, /* Behaves like a TTY */ ios_$cf_ipc, /* Behaves like an inter-process channel */ ios_$cf_vt, /* Behaves like a virtual terminal */ ios_$cf_write, /* Can be written to */ ios_$cf_append, /* Will have all writes be appends */ ios_$cf_unregulated, /* Open mode allows unregulated (concurrent) access */ ios_$cf_read_intend_write, /* Open for read-intend-write */ ios_$cf_reserved_8, ios_$cf_reserved_9, ios_$cf_reserved_10, ios_$cf_reserved_11, ios_$cf_reserved_12, ios_$cf_reserved_13, ios_$cf_reserved_14, ios_$cf_reserved_15, ios_$cf_reserved_16, ios_$cf_reserved_17, ios_$cf_reserved_18, ios_$cf_reserved_19, ios_$cf_reserved_20, ios_$cf_reserved_21, ios_$cf_reserved_22, ios_$cf_reserved_23, ios_$cf_reserved_24, ios_$cf_reserved_25, ios_$cf_reserved_26, ios_$cf_reserved_27, ios_$cf_reserved_28, ios_$cf_reserved_29, ios_$cf_reserved_30, ios_$cf_reserved_31, ios_$cf_reserved_32 } ios_$conn_flag_t; #define ios_$ascii_mask ((ios_$flag_set) 0x001) #define ios_$append_mask ((ios_$flag_set) 0x002) #define ios_$writable_mask ((ios_$flag_set) 0x004) #define ios_$delete_on_close_mask ((ios_$flag_set) 0x008) #define ios_$unregulated_mask ((ios_$flag_set) 0x010) #define ios_$ftn_mask ((ios_$flag_set) 0x020) #define ios_$sparse_mask ((ios_$flag_set) 0x040) #define ios_$is_a_ipc_mask ((ios_$flag_set) 0x080) #define ios_$is_a_tty_mask ((ios_$flag_set) 0x100) #define ios_$is_a_vt_mask ((ios_$flag_set) 0x200) #define ios_$no_put_get_delay_mask ((ios_$flag_set) 0x400) #define ios_$mf_create,#define ((ios_$mf_flag_set) 0x001) #define ios_$mf_create_bak ((ios_$mf_flag_set) 0x002) #define ios_$mf_imex ((ios_$mf_flag_set) 0x004) #define ios_$mf_fork ((ios_$mf_flag_set) 0x008) #define ios_$mf_force_write ((ios_$mf_flag_set) 0x010) #define ios_$mf_write ((ios_$mf_flag_set) 0x020) #define ios_$mf_seek_abs ((ios_$mf_flag_set) 0x040) #define ios_$mf_seek_short ((ios_$mf_flag_set) 0x080) #define ios_$mf_seek_full ((ios_$mf_flag_set) 0x100) #define ios_$mf_seek_byte ((ios_$mf_flag_set) 0x200) #define ios_$mf_seek_rec ((ios_$mf_flag_set) 0x400) #define ios_$mf_seek_bof ((ios_$mf_flag_set) 0x800) #define ios_$mf_rec_type ((ios_$mf_flag_set) 0x1000) #define ios_$mf_truncate ((ios_$mf_flag_set) 0x2000) #define ios_$mf_unregulated ((ios_$mf_flag_set) 0x4000) #define ios_$mf_sparse ((ios_$mf_flag_set) 0x8000) #define ios_$mf_read_intend_write ((ios_$mf_flag_set) 0x10000) #define ios_$of_delete_on_close ((ios_$obj_flag_set) 0x001) #define ios_$of_sparse_ok ((ios_$obj_flag_set) 0x002) #define ios_$of_ascii ((ios_$obj_flag_set) 0x004) #define ios_$of_ftncc ((ios_$obj_flag_set) 0x008) #define ios_$of_cond ((ios_$obj_flag_set) 0x010) #define ios_$cf_tty ((ios_$cf_flag_set) 0x001) #define ios_$cf_ipc ((ios_$cf_flag_set) 0x002) #define ios_$cf_vt ((ios_$cf_flag_set) 0x004) #define ios_$cf_write ((ios_$cf_flag_set) 0x008) #define ios_$cf_append ((ios_$cf_flag_set) 0x010) #define ios_$cf_unregulated ((ios_$cf_flag_set) 0x020) #define ios_$cf_read_intend_write ((ios_$cf_flag_set) 0x040) typedef long ios_$flag_set; typedef long ios_$mgr_flag_set; typedef long ios_$obj_flag_set; typedef long ios_$conn_flag_set; std_$call ios_$id_t ios_$open(); std_$call void ios_$close(); std_$call void ios_$get_ec(); std_$call ios_$flag_set ios_$inq_flags(); std_$call void ios_$set_flag(); std_$call void ios_$delete(); std_$call void ios_$truncate(); std_$call long ios_$get(); std_$call long ios_$locate(); std_$call void ios_$put(); std_$call long ios_$inq_rec_remainder(); std_$call void ios_$seek(); std_$call void ios_$seek_full_key(); std_$call void ios_$seek_short_key(); std_$call void ios_$seek_to_bof(); std_$call void ios_$seek_to_eof(); std_$call long ios_$inq_short_key(); std_$call void ios_$inq_full_key(); std_$call long ios_$inq_rec_pos(); std_$call long ios_$inq_byte_pos(); std_$call long ios_$inq_cur_rec_len(); std_$call ios_$rtype_t ios_$inq_rec_type(); std_$call void ios_$set_rec_type(); std_$call void ios_$force_write_file(); std_$call void ios_$inq_file_attr(); std_$call void ios_$create(); std_$call void ios_$set_type(); std_$call void ios_$change_name(); std_$call void ios_$inq_name(); std_$call void ios_$inq_type_uid(); std_$call char *ios_$get_handle(); std_$call void ios_$set_locate_buffer_size(); std_$call ios_$id_t ios_$switch(); std_$call ios_$id_t ios_$replicate(); std_$call ios_$id_t ios_$dup(); std_$call boolean ios_$equal(); std_$call void ios_$set_dir(); std_$call void ios_$get_dir(); End of ios.ins.c echo makefile 1>&2 cat >makefile <<'End of makefile' CFLAGS=-g -O TRAIT=/sys/traits/io_traits /sys/traits/ios_dir_trait ITEST=/com/itest OBJ=init.o fork.o get.o put.o misc.o attr.o open.o seek.o \ dir_open.o flag.o equal.o trunc.o v2_uid.bin v2f_uid.bin sio.o DOBJ=v2d.o all: v2 v2d types: v2_uid.bin v2f_uid.bin # crty blows up if the link exists /com/dll /sys/mgrs/v2f /com/crty v2 -r -l -b v2_uid.bin /com/crty v2f -r -l -b v2f_uid.bin itest: $(OBJ) cc -o itest $(ITEST) $(OBJ) $(TRAIT) install: v2 /com/intm v2 -r -l /com/crl /sys/mgrs/v2f /sys/mgrs/v2 -r v2: $(OBJ) /bin/ld -o v2 -e 'ios_$$initialize' -Tany $(OBJ) $(TRAIT) fork.o: v2.h v2d: $(DOBJ) cc -o v2d $(DOBJ) crv2: crv2.o cc -o crv2 crv2.o End of makefile echo misc.c 1>&2 cat >misc.c <<'End of misc.c' #include "/sys/ins/base.ins.c" #include "ios.ins.c" #include "v2.h" #include "v2d.h" v2_$get_ec(hpp, keyp, ecpp, stp) v2_handle_t **hpp; ios_$ec_key_t *keyp; ec2_$ptr_t *ecpp; status_$t *stp; { v2_handle_t *hp; hp = *hpp; ios_$get_ec((ios_$id_t) hp->sock_fd, *keyp, *ecpp, *stp); } ios_$rtype_t v2_$inq_rec_type(hpp, stp) v2_handle_t **hpp; status_$t *stp; { stp->all = status_$ok; return ios_$UNDEF; } v2_$set_rec_type(hpp, rtp, rlp, stp) v2_handle_t **hpp; ios_$rtype_t *rtp; long *rlp; status_$t *stp; { if (*rtp == ios_$UNDEF) stp->all = status_$ok; else stp->all = ios_$illegal_operation; } End of misc.c echo open.c 1>&2 cat >open.c <<'End of open.c' /* Simple minded remote file system interconnect. This is the type manager. Written by Jim Rees, Apollo Compouter, 1985. */ #include #include #include #include #include #include #include #include "/sys/ins/base.ins.c" #include "ios.ins.c" #include "/sys/ins/io_traits.ins.c" #include "/sys/ins/ms.ins.c" #include "/sys/ins/rws.ins.c" #include "/sys/ins/type_uids.ins.c" #include "v2.h" #include "v2d.h" static struct errtab { int errno; int stcode; } errtab[] = { EPERM, ios_$insufficient_rights, EIO, ios_$object_not_found, ENXIO, ios_$object_not_found, EBADF, ios_$id_oor, ENOMEM, ios_$insuff_memory, EACCES, ios_$insufficient_rights, ENOTBLK, ios_$illegal_obj_type, EBUSY, ios_$resource_lock_err, EEXIST, ios_$already_exists, EXDEV, ios_$illegal_name_redefine, ENODEV, ios_$object_not_found, ENOTDIR, ios_$illegal_obj_type, EISDIR, ios_$illegal_obj_type, ENFILE, ios_$no_table_space, EMFILE, ios_$no_more_streams, ETXTBSY, ios_$concurrency_violation, -1, ios_$name_not_found, }; #ifdef CACHE /* We keep a one-deep cache in v2_sock_fd */ static int v2_sock_fd = -1; static uid_$t v2_gw_uid; #endif CACHE extern short pm_$level; extern status_$t tcp_$iostatus; v2_$openx(xoidp, resid, resid_lenp, ooptsp, hpp, tuidp, stp) xoid_$t *xoidp; char *resid; short *resid_lenp; ios_$open_options_t *ooptsp; v2_handle_t **hpp; uid_$t *tuidp; status_$t *stp; { v2_open(xoidp, resid, *resid_lenp, ios_$preserve_mode, *ooptsp, &uid_$nil, hpp, tuidp, stp); } v2_$create(xoidp, resid, resid_lenp, cmodep, ooptsp, iuidp, hpp, ouidp, stp) xoid_$t *xoidp; char *resid; short *resid_lenp; ios_$create_mode_t *cmodep; ios_$open_options_t *ooptsp; uid_$t *iuidp, *ouidp; v2_handle_t **hpp; status_$t *stp; { if (*iuidp == directory_$uid) { v2_dir_create(xoidp, resid, *resid_lenp, hpp, stp); *ouidp = v2_$uid; } else v2_open(xoidp, resid, *resid_lenp, *cmodep, (*ooptsp | ios_$create_opt), iuidp, hpp, ouidp, stp); } v2_open(xoidp, resid, resid_len, cmode, oopts, iuidp, hpp, ouidp, stp) xoid_$t *xoidp; char *resid; short resid_len; ios_$create_mode_t cmode; ios_$open_options_t oopts; uid_$t *iuidp, *ouidp; v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; char *name, nbuf[256]; short namelen; long flag; int type; *hpp = NULL; handle_init(&hp, resid, resid_len, stp); if (stp->all) return; name = hp->name; namelen = resid_len; hp->xoid = *xoidp; /* if (oopts & (ios_$write_opt | ios_$read_intend_write_opt)) { */ if (oopts & (ios_$write_opt | (ios_$open_options_t) 0x20)) { flag = O_RDWR; hp->read_only = false; } else { flag = O_RDONLY; hp->read_only = true; } hp->inq_only = (oopts & ios_$inquire_only_opt) ? true : false; if (oopts & ios_$position_to_eof_opt) { flag |= XO_APPEND; hp->append_mode = true; } else hp->append_mode = false; if (oopts & ios_$create_opt) flag |= XO_CREAT; switch (cmode) { case ios_$no_pre_exist_mode: flag |= XO_EXCL; break; case ios_$preserve_mode: break; case ios_$recreate_mode: case ios_$truncate_mode: flag |= XO_TRUNC; break; case ios_$make_backup_mode: flag |= XO_TRUNC; /* Gen up a temp file name */ strcpy(nbuf, name); nbuf[namelen++] = '~'; name = nbuf; hp->bak_mode = true; break; default: stp->all = ios_$illegal_param_comb; return; } if ((hp->sock_fd = sconnect(xoidp, stp)) < 0) return; putlong(C_OPEN); putlong(namelen); putbytes(name, namelen); putlong(flag); if ((type = getlong()) < 0) { close(hp->sock_fd); hp->sock_fd = -1; stp->all = v2_tr_errno(-1 - type); return; } hp->cant_write = ((type & T_RW) == T_RO); hp->type = ((type & T_TYPE) == T_FILE) ? v2f_$uid : v2_$uid; *ouidp = hp->type; stp->all = status_$ok; *hpp = hp; } static v2_dir_create(xoidp, name, name_len, hpp, stp) xoid_$t *xoidp; char *name; short name_len; v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; int type; *hpp = NULL; handle_init(&hp, name, name_len, stp); if (stp->all) return; hp->xoid = *xoidp; hp->read_only = true; hp->inq_only = false; hp->append_mode = false; if ((hp->sock_fd = sconnect(xoidp, stp)) < 0) return; putlong(C_MKDIR); putlong(name_len); putbytes(name, name_len); if ((type = getlong()) < 0) { close(hp->sock_fd); hp->sock_fd = -1; stp->all = v2_tr_errno(-1 - type); return; } hp->cant_write = true; hp->type = v2_$uid; stp->all = status_$ok; *hpp = hp; } v2_tr_errno(e) int e; { struct errtab *etp; for (etp = errtab; etp->errno > 0; etp++) if (e == etp->errno) break; return etp->stcode; } static handle_init(hpp, name, name_len, stp) v2_handle_t **hpp; char *name; short name_len; status_$t *stp; { v2_handle_t *hp; char tname[200], *cp, *comp[20]; int i, n; boolean start; hp = (v2_handle_t *) rws_$alloc_heap_pool(rws_$stream_tm_pool, (long) sizeof (v2_handle_t)); if (hp == NULL) { stp->all = ios_$insuff_memory; return; } hp->sock_fd = -1; hp->unreg = true; hp->delete = false; hp->level = pm_$level; hp->bak_mode = false; hp->a_cache_valid = false; /* The file name may contain ../ or ./, so we break it into the constituant parts, put them on a stack, and canonicalize. Note this doesn't help link text. */ /* Put on stack */ strncpy(tname, name, name_len); strcpy(&tname[name_len], "/"); start = true; n = 0; for (cp = tname; *cp; cp++) { if (start && *cp != '/') { start = false; if (n > 0 && !strncmp(cp, "../", 3)) n--; else if (strncmp(cp, "./", 2)) comp[n++] = cp; } else if (!start && *cp == '/') { start = true; *cp = '\0'; } } /* Reconstruct from stack */ hp->name[0] = '\0'; for (i = 0; i < n; i++) { if (i != 0) strcat(hp->name, "/"); strcat(hp->name, comp[i]); } *hpp = hp; stp->all = status_$ok; } v2_$change_name(hpp, name, name_lenp, stp) v2_handle_t **hpp; char *name; short *name_lenp; status_$t *stp; { v2_handle_t *hp; int n; stp->all = status_$ok; hp = *hpp; putlong(C_CHN); n = strlen(hp->name); putlong(n); putbytes(hp->name, n); putlong(*name_lenp); putbytes(name, *name_lenp); if ((n = getlong()) != 0) { stp->all = v2_tr_errno(-1 - n); return; } strncpy(hp->name, name, *name_lenp); hp->name[*name_lenp] = '\0'; } v2_$inq_name(hpp, typep, name, nlp, stp) v2_handle_t **hpp; io_xoc_$name_type_t *typep; char *name; short *nlp; status_$t *stp; { v2_handle_t *hp; char *cp; extern char *rindex(); hp = *hpp; if (*typep == io_xoc_$leaf_name) { cp = rindex(hp->name, '/'); if (cp == NULL) cp = hp->name; else cp++; } else cp = hp->name; *nlp = strlen(cp); strncpy(name, cp, *nlp); stp->all = status_$ok; } boolean v2_$close(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; int n, ok; status_$t stx; stp->all = status_$ok; hp = *hpp; if (hp == NULL || hp->level != pm_$level) return false; if (hp->delete) { putlong(C_UNLINK); n = strlen(hp->name); putlong(n); putbytes(hp->name, n); if (getlong() < 0) stp->all = ios_$insufficient_rights; } else if (hp->bak_mode) make_bak(hp, stp); if (hp->sock_fd >= 0) { putlong(C_CLOSE); #ifdef CACHE /* If there's room, cache this connection. Don't cache connections for the DM. */ if (v2_sock_fd < 0 && getpid() != 1) { v2_sock_fd = hp->sock_fd; v2_gw_uid = hp->xoid.uid; } else close(hp->sock_fd); #else close(hp->sock_fd); #endif CACHE } rws_$release_heap(hp, stx); return false; } static make_bak(hp, stp) v2_handle_t *hp; status_$t *stp; { int n; char buf[256]; /* Delete the old .bak file */ strcpy(buf, hp->name); n = strlen(buf); strcpy(&buf[n], ".bak"); putlong(C_UNLINK); putlong(n + 4); putbytes(buf, n + 4); getlong(); /* Rename the old file to .bak */ putlong(C_CHN); putlong(n); putbytes(buf, n); putlong(n + 4); putbytes(buf, n + 4); getlong(); /* Rename the temp file to the old file name */ buf[n] = '~'; putlong(C_CHN); putlong(n + 1); putbytes(buf, n + 1); putlong(n); putbytes(buf, n); return getlong(); } sconnect(xoidp, stp) xoid_$t *xoidp; status_$t *stp; { struct sockaddr_in saddr; long len_mapped; char *p; int fd; status_$t st; #ifdef CACHE if (v2_sock_fd >= 0 && v2_gw_uid == xoidp->uid) { fd = v2_sock_fd; v2_sock_fd = -1; return fd; } #endif CACHE p = ms_$mapl_stream(*xoidp, 0L, 1024L, ms_$nr_xor_1w, ms_$r, false, len_mapped, *stp); if (stp->all != status_$ok) return -1; bcopy(p, &saddr, sizeof saddr); ms_$unmap(p, 1024L, st); if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { *stp = tcp_$iostatus; close(fd); return -1; } if (connect(fd, &saddr, sizeof saddr) < 0) { *stp = tcp_$iostatus; close(fd); return -1; } fd = ios_$switch((ios_$id_t) fd, ios_$max, *stp); if (stp->all != status_$ok) return -1; senduid(fd); return fd; } static senduid(fd) int fd; { extern int getuid(); struct passwd *getpwuid(); struct passwd *pwd; unix_uid_$set_sid(); pwd = getpwuid(getuid()); _putlong(fd, strlen(pwd->pw_name)); _putbytes(fd, pwd->pw_name, strlen(pwd->pw_name)); } End of open.c echo put.c 1>&2 cat >put.c <<'End of put.c' #include "/sys/ins/base.ins.c" #include "ios.ins.c" #include "v2.h" #include "v2d.h" v2_$put(hpp, optp, buf, buf_lenp, stp) v2_handle_t **hpp; ios_$put_get_opts_t *optp; char *buf; long *buf_lenp; status_$t *stp; { v2_handle_t *hp; stp->all = status_$ok; hp = *hpp; hp->a_cache_valid = false; putlong(C_WRITE); if (*buf_lenp == 0xffff8000) *buf_lenp = 32768; putlong(*buf_lenp); putbytes(buf, *buf_lenp); if (getlong() != *buf_lenp) stp->all = ios_$end_of_file; } End of put.c echo seek.c 1>&2 cat >seek.c <<'End of seek.c' #include #include #include "/sys/ins/base.ins.c" #include "ios.ins.c" #include "v2.h" #include "v2d.h" extern status_$t unix_fio_$status; v2_$inq_byte_pos(hpp, pos_optp, stp) v2_handle_t **hpp; ios_$pos_opt_t *pos_optp; status_$t *stp; { struct attr atb; long key; stp->all = status_$ok; if (*pos_optp == ios_$bof) return 0; if (*pos_optp == ios_$current) return v2_seek(hpp, ios_$relative, 0L, stp); if (*pos_optp == ios_$eof) { if (v2_$stat(*hpp, &atb) < 0) { *stp = unix_fio_$status; return -1; } return atb.size; } stp->all = ios_$illegal_param_comb; return -1; } v2_$seek(hpp, abs_relp, typep, keyp, stp) v2_handle_t **hpp; ios_$abs_rel_t *abs_relp; ios_$seek_type_t *typep; long *keyp; status_$t *stp; { if (*typep != ios_$byte_seek) { stp->all = ios_$illegal_param_comb; return; } v2_seek(hpp, *abs_relp, *keyp, stp); } static long v2_seek(hpp, abs_rel, key, stp) v2_handle_t **hpp; ios_$abs_rel_t abs_rel; long key; status_$t *stp; { v2_handle_t *hp; int how; long ret; stp->all = status_$ok; hp = *hpp; how = (abs_rel == ios_$relative) ? 1 : 0; putlong(C_SEEK); putlong(key); putlong(how); if ((ret = getlong()) < 0) *stp = unix_fio_$status; return ret; } v2_$inq_short_key(hpp, pos_optp, stp) v2_handle_t **hpp; ios_$pos_opt_t *pos_optp; status_$t *stp; { return v2_$inq_byte_pos(hpp, pos_optp, stp) + 1; } v2_$inq_full_key(hpp, pos_optp, keyp, stp) v2_handle_t **hpp; ios_$pos_opt_t *pos_optp; ios_$seek_key_t *keyp; status_$t *stp; { keyp->rec_adr = v2_$inq_byte_pos(hpp, pos_optp, stp) + 1; keyp->byte_adr = 0; } v2_$stat(hp, atp) v2_handle_t *hp; struct attr *atp; { if (!(hp->a_cache_valid)) { putlong(C_FSTAT); if (read(hp->sock_fd, &(hp->a_cache), sizeof (struct attr)) < 0) return -1; hp->a_cache_valid = true; } *atp = hp->a_cache; return 0; } v2_$seek_full_key(hpp, keyp, stp) v2_handle_t **hpp; ios_$seek_key_t *keyp; status_$t *stp; { v2_seek(hpp, ios_$absolute, keyp->rec_adr - 1, stp); } v2_$seek_short_key(hpp, keyp, stp) v2_handle_t **hpp; long *keyp; status_$t *stp; { v2_seek(hpp, ios_$absolute, *keyp - 1, stp); } v2_$seek_to_bof(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_seek(hpp, ios_$absolute, 0L, stp); } v2_$seek_to_eof(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; stp->all = status_$ok; hp = *hpp; putlong(C_SEEK); putlong(0); putlong(2); if (getlong() < 0) *stp = unix_fio_$status; } End of seek.c echo sio.c 1>&2 cat >sio.c <<'End of sio.c' #include #include #include _getlong(fd) int fd; { long n; if (read(fd, &n, sizeof n) != sizeof n) return -1; n = ntohl(n); return n; } _putlong(fd, n) int fd; long n; { n = ntohl(n); write(fd, &n, sizeof n); } _putbytes(fd, bp, n) int fd, n; char *bp; { write(fd, bp, n); } End of sio.c echo trunc.c 1>&2 cat >trunc.c <<'End of trunc.c' #include "/sys/ins/base.ins.c" #include "ios.ins.c" #include "v2.h" #include "v2d.h" v2_$truncate(hpp, stp) v2_handle_t **hpp; status_$t *stp; { v2_handle_t *hp; int e; hp = *hpp; if (hp->read_only) { stp->all = ios_$read_only_err; return; } putlong(C_TRUNC); if ((e = getlong()) < 0) stp->all = v2_tr_errno(-1 - e); else stp->all = status_$ok; } End of trunc.c echo v2.h 1>&2 cat >v2.h <<'End of v2.h' #include "attr.h" #define NULL 0 #define ios_$create_opt ((ios_$open_options_t) 0x1000) #define getlong() _getlong(hp->sock_fd) #define putlong(n) _putlong(hp->sock_fd, n) #define putbytes(bp, n) _putbytes(hp->sock_fd, bp, n) typedef struct { char *sfcb_ptr; int sock_fd; char *key_ptr; boolean seek_key_shared; boolean unreg; boolean read_only; boolean inq_only; boolean append_mode; boolean delete; xoid_$t xoid; int level; char name[80]; boolean bak_mode; boolean cant_write; uid_$t type; struct attr a_cache; boolean a_cache_valid; boolean dirp; char buffer[1024]; int buf_start_key; int buf_pos; int buf_cnt; int last_read; boolean buf_valid; int file_pos; boolean file_pos_valid; } v2_handle_t; extern uid_$t v2_$uid, v2f_$uid; End of v2.h echo v2d.c 1>&2 cat >v2d.c <<'End of v2d.c' /* Simple minded remote file system interconnect. This is the server. It runs on any bsd4.2 system. Written by Jim Rees, Apollo Computer, 1985. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "v2d.h" #include "attr.h" #define AP_SUBNET 0xc00c3800 #define BSD4_3 #ifdef apollo #include "/sys/ins/base.ins.c" #include "/sys/ins/rws.ins.c" #include "/sys/ins/ev.ins.c" static status_$t junk_status; #define malloc(x) rws_$alloc_heap((long) x) #define free(x) rws_$release_heap(x, junk_status) #else extern char *malloc(); #endif extern int errno; char *getstr(), *getbuf(); DIR *fdopendir(); int catch_chld(); char *cmd_names[] = { "open", "close", "read", "write", "stat", "fstat", "seek", "chn", "unlink", "rdln", }; struct connection { int sfd; FILE *sf; int fd; DIR *dirp; int network; }; int debug, fflag, sflag; int accept_port; main (ac, av) int ac; char *av[]; { struct connection conn; while (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 'd': debug = 1; break; case 'f': fflag = 1; break; case 's': sflag = 1; break; case 'p': accept_port = htons(atoi(av[2])); ac--; av++; break; } ac--; av++; } #ifdef apollo ev_$set_var("DOWNCASE", 8, "f", 1); default_acl(2); #endif chdir("/"); if (sflag) do_accept(); conn.sfd = 0; serve(&conn); } /* Do all the stuff that inetd normally does for us. This routine does not return. */ do_accept() { int s, slen; int keep_alive = 1; struct servent *sp; struct sockaddr_in saddr; struct connection conn; if (accept_port == 0) { if ((sp = getservbyname ("v2d", 0)) == 0) { fprintf(stderr, "can't find port for v2d in /etc/services\n"); exit(1); } accept_port = sp->s_port; } saddr.sin_family = AF_INET; saddr.sin_port = accept_port; #ifdef BSD4_3 saddr.sin_addr.s_addr = INADDR_ANY; #else saddr.sin_addr.S_un.S_addr = INADDR_ANY; #endif if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } #ifdef BSD4_3 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof keep_alive) < 0) #else if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) #endif { perror("setsockopt"); exit(1); } if (bind(s, &saddr, sizeof saddr) < 0) { perror("bind"); exit(1); } if (listen(s, 4) < 0) { perror("listen"); exit(1); } if (!debug) { if (fork()) exit(0); signal(SIGHUP, SIG_IGN); close(0); close(1); close(2); } signal(SIGCHLD, catch_chld); slen = sizeof saddr; for (;;) { if ((conn.sfd = accept(s, &saddr, &slen)) < 0) { if (debug) perror("accept"); continue; } #ifdef notyetPARANOID conn.network = ntohl((int) saddr.sin_addr.s_addr) & 0xffffff00; if (debug) printf("host=%x, subnet=%x\n", (int) saddr.sin_addr.s_addr, conn.network); #endif notyetPARANOID if (!fflag) { if (fork() == 0) { close(s); serve(&conn); exit(0); } } else serve(&conn); close(conn.sfd); } } catch_chld() { while (wait3(NULL, WNOHANG, NULL) > 0) ; } serve(cp) struct connection *cp; { int gid; int cmd, uid; char *user; struct passwd *p; cp->sf = fdopen(cp->sfd, "w"); cp->fd = -1; cp->dirp = NULL; #ifndef apollo user = getstr(cp->sfd, NULL); if (debug) { printf("testing user: %s\n", user); } if ((p = (struct passwd *)getpwnam(user)) == NULL) { goto bad; } uid = p->pw_uid; gid = p->pw_gid; /* look for root and uucp, and other invaders */ if (uid == 0 || (user[0] == 'U') || (strcmp(user, "guest") == 0) || (strcmp(user, "uucp") == 0)) goto bad; #ifdef CHECKPW pass = getstr(cp->sfd, NULL); cp = (char *)crypt(pass, p->pw_passwd); if (strcmp(cp, p->pw_passwd) != 0) { goto bad; } #endif CHECKPW #ifdef notyetPARANOID if (cp->network != AP_SUBNET) { if (debug) printf("subnets don't match %x %x\n", cp->network, AP_SUBNET); goto bad; } #endif notyetPARANOID setregid(gid, gid); initgroups(user, gid); setreuid(uid, uid); chdir("/"); #endif apollo for (;;) { errno = 0; cmd = getlong(cp->sfd); if (cmd < 0) { if (errno && debug) perror("serve"); c_close(cp); break; } if (debug) { printf("%s\n", cmd_names[cmd - 1]); } switch (cmd) { case C_OPEN: c_open(cp); break; case C_CLOSE: c_close(cp); break; case C_READ: case C_RDLN: c_read(cp, cmd); break; case C_WRITE: c_write(cp); break; case C_FSTAT: c_fstat(cp); break; case C_SEEK: c_seek(cp); break; case C_CHN: c_chn(cp); break; case C_UNLINK: c_unlink(cp); break; case C_MKDIR: c_mkdir(cp); break; case C_TRUNC: c_trunc(cp); break; default: fprintf(stderr, "bad cmd %d\n", cmd); c_close(cp); break; } } bad: /* used for normal exit as well */ fclose(cp->sf); } c_open(cp) struct connection *cp; { int fd, iflag, flag, type, needwrite; char *name; struct stat stb; static DIR *mydirp; if ((name = getstr(cp->sfd, NULL)) == NULL) return; iflag = getlong(cp->sfd); if (debug) printf("open %s %o\n", name, iflag); needwrite = iflag & 3; flag = O_RDWR; if (iflag & XO_CREAT) flag |= O_CREAT; if (iflag & XO_TRUNC) flag |= O_TRUNC; if (iflag & XO_APPEND) flag |= O_APPEND; if (iflag & XO_EXCL) flag |= O_EXCL; type = T_RW; for (;;) { if ((cp->fd = open(name, flag, 0666)) >= 0) break; if ((flag & O_RDWR) && !needwrite) { /* Try again, but for read only */ flag &= ~3; type = T_RO; } else { putlong(cp->sf, -1 - errno); fflush(cp->sf); return; } } fstat(cp->fd, &stb); if (stb.st_mode & S_IFDIR) { if (mydirp == NULL) { mydirp = opendir("."); close(mydirp->dd_fd); } mydirp->dd_fd = cp->fd; rewinddir(mydirp); cp->dirp = mydirp; type |= T_DIR; } else type |= T_FILE; putlong(cp->sf, type); fflush(cp->sf); } c_close(cp) struct connection *cp; { close(cp->fd); cp->fd = -1; cp->dirp = NULL; } struct odirect { short d_type; /* 1=file, 3=link */ short d_len; /* non-blank chars in name */ char d_name[32]; /* name text */ long d_ino; /* "i-node" # */ long d_dev; /* "dev" # */ }; #define DS (sizeof (struct odirect)) c_read(cp, cmd) struct connection *cp; int cmd; { char *bp; int i, n, key, asked; struct direct *dp; struct odirect *odp; asked = getlong(cp->sfd); if (asked < 0) return; bp = getbuf(asked); if (cp->dirp == NULL) { /* ordinary file */ if (cmd == C_RDLN) key = lseek(cp->fd, 0L, 1); n = read(cp->fd, bp, asked); if (cmd == C_RDLN) { for (i = 0; i < n; ) if (bp[i++] == '\n') break; n = i; lseek(cp->fd, key + i, 0); } } else { n = 0; odp = (struct odirect *) bp; i = asked; while (i >= DS) { dp = readdir(cp->dirp); if (dp == NULL) break; odp->d_type = ntohs(1); odp->d_len = ntohs(dp->d_namlen); strncpy(odp->d_name, dp->d_name, 32); odp->d_ino = ntohl(dp->d_ino); odp->d_dev = ntohl(1); odp++; i -= DS; n += DS; } } if (debug) printf("read %d got %d\n", asked, n); putlong(cp->sf, n); while (n > 0) { i = fwrite(bp, 1, n, cp->sf); n -= i; bp += i; } fflush(cp->sf); } c_write(cp) struct connection *cp; { int n; char *bp; bp = getstr(cp->sfd, &n); if (bp == NULL) return; putlong(cp->sf, write(cp->fd, bp, n)); fflush(cp->sf); } c_fstat(cp) struct connection *cp; { struct stat stb; struct attr atb; fstat(cp->fd, &stb); fixstat(&stb, &atb); fwrite(&atb, sizeof atb, 1, cp->sf); fflush(cp->sf); } fixstat(s, a) struct stat *s; struct attr *a; { /* a->dev = ntohl(s->st_dev); */ /* a->ino = ntohl(s->st_ino); */ a->mode = ntohl(s->st_mode); /* a->nlink = ntohl(s->st_nlink); */ a->uid = ntohl(s->st_uid); a->gid = ntohl(s->st_gid); /* a->rdev = ntohl(s->st_rdev); */ /* On non-apollo 4.2 machines, we correct for the difference between size of 4.2 directory entries and apollo directory entries. */ #ifndef apollo if (s->st_mode & S_IFDIR) a->size = ntohl(s->st_size * 44 / 14); else #endif a->size = ntohl(s->st_size); a->atime = ntohl(s->st_atime); /* a->spare1 = ntohl(s->st_spare1); */ a->mtime = ntohl(s->st_mtime); /* a->spare2 = ntohl(s->st_spare2); */ /* a->ctime = ntohl(s->st_ctime); */ /* a->spare3 = ntohl(s->st_spare3); */ /* a->blksize = ntohl(s->st_blksize); */ a->blocks = ntohl((s->st_blocks + (1024 / DEV_BSIZE) - 1) * DEV_BSIZE / 1024); } c_seek(cp) struct connection *cp; { long key; int how; key = getlong(cp->sfd); how = getlong(cp->sfd); putlong(cp->sf, lseek(cp->fd, key, how)); fflush(cp->sf); } c_chn(cp) struct connection *cp; { char *name, *oldname, *newname; int n; struct stat stb; if ((name = getstr(cp->sfd, &n)) == NULL) return; oldname = malloc(n + 1); strcpy(oldname, name); if ((newname = getstr(cp->sfd, &n)) == NULL) return; if (debug) printf("chn %s %s\n", oldname, newname); if (cp->dirp != NULL) { if (rename(oldname, newname) < 0) { putlong(cp->sf, -1 - errno); fflush(cp->sf); free(oldname); return; } } else { if (link(oldname, newname) < 0) { putlong(cp->sf, -1 - errno); fflush(cp->sf); free(oldname); return; } if (unlink(oldname) < 0) { putlong(cp->sf, -1 - errno); fflush(cp->sf); free(oldname); unlink(newname); return; } } free(oldname); putlong(cp->sf, 0); fflush(cp->sf); } c_unlink(cp) struct connection *cp; { char *name; int n; if ((name = getstr(cp->sfd, &n)) == NULL) return; if (debug) printf("unlink %s\n", name); if (cp->dirp == NULL) n = unlink(name); else n = rmdir(name); putlong(cp->sf, n); fflush(cp->sf); } c_mkdir(cp) struct connection *cp; { char *name; int n, e; if ((name = getstr(cp->sfd, &n)) == NULL) return; if (debug) printf("unlink %s\n", name); if ((e = mkdir(name, 0777)) < 0) e = -1 - errno; putlong(cp->sf, e); fflush(cp->sf); cp->dirp = opendir(name); cp->fd = cp->dirp->dd_fd; } c_trunc(cp) struct connection *cp; { if (ftruncate(cp->fd, lseek(cp->fd, 0L, 1)) < 0) putlong(cp->sf, -1 - errno); else putlong(cp->sf, 0); fflush(cp->sf); } char * getstr(fd, lenp) int fd, *lenp; { int i, n; char *bp, *ret; if ((n = getlong(fd)) < 0) return NULL; ret = bp = getbuf(n + 1); if (lenp != NULL) *lenp = n; while (n > 0) { if ((i = read(fd, bp, n)) <= 0) return NULL; n -= i; bp += i; } *bp = '\0'; return ret; } char * getbuf(n) int n; { static char *bufp; static int size; if (n > size) { if (bufp != NULL) free(bufp); size = n; bufp = malloc(n); } return bufp; } getlong(fd) int fd; { long n; if (read(fd, &n, sizeof n) != sizeof n) return -1; n = ntohl(n); return n; } putlong(f, n) FILE *f; long n; { n = ntohl(n); fwrite(&n, sizeof n, 1, f); } putshort(f, n) FILE *f; short n; { n = ntohs(n); fwrite(&n, sizeof n, 1, f); } End of v2d.c echo v2d.h 1>&2 cat >v2d.h <<'End of v2d.h' /* Commands */ #define C_OPEN 1 #define C_CLOSE 2 #define C_READ 3 #define C_WRITE 4 #define C_STAT 5 #define C_FSTAT 6 #define C_SEEK 7 #define C_CHN 8 #define C_UNLINK 9 #define C_RDLN 10 #define C_MKDIR 11 #define C_TRUNC 12 /* File types */ #define T_TYPE 0xf #define T_FILE 0x1 #define T_DIR 0x2 #define T_RW 0xf0 #define T_RO 0x10 /* substitutes for O_ flags (they may be different on the remote machine) */ #define XO_CREAT 0x100 #define XO_TRUNC 0x200 #define XO_APPEND 0x8 #define XO_EXCL 0x400 End of v2d.h