/* OS- and machine-dependent stuff for OSK machines * Written by Bob, Brose, N0QBJ, 974 Hampden Ave, St Paul MN 55114-1108 * Version Log ----------- 012093 - First OSK release. 022493 - Fixed bug in smtp, wasn't doing cr/lf correctly and SOME nos hosts objected. Fixed various FTP bugs (also caused by cr/lf conversions. Fixed problem in ftpserver ls command response which should now allow mgets from a remote host to work correctly (directory access routines in this file altered). 081293 - Fixed bug in rename which was causing an abort on mailbox reads. 081693 - Fixed memory allocation bugs, space used by make_path was not being freed. Added the code for getcwd and cd. */ #include "global.h" #include #include #include #include #include #include #include "osk.h" #include "mbuf.h" #include "internet.h" #include "iface.h" #include "cmdparse.h" #define MAXCMD 80 unsigned nasy; int IORser[ASY_MAX]; struct sgbuf orgsgbufi, orgsgbufo; #ifndef _UCC #define MAXTMP 26 struct FILREC { FILE *filptr; char tmpnam[32]; }; struct FILREC tmpfils[MAXTMP]; #endif restore() { } disable() { } kbread() { unsigned char c; if (getstat(1,0) < 0) return -1; read(0, &c, 1); return c; } struct asy asy[ASY_MAX]; /* Interface list header */ struct interface *ifaces = NULL; /* Called at startup time to set up console I/O, memory heap */ ioinit() { char termname[40]; struct sgbuf sbuf; int i; /* tmp file tracking array init, non-ucc */ #ifndef _UCC for (i=0;i (10000/MSPTICK) || offset < 0) clkval = ntime; /* Handle possibility of several missed ticks */ while (ntime != clkval){ fflush(NULL); ++clkval; icmpclk(); tickle(); (void) iss(); } } /* Initialize asynch port "dev" */ int asy_init(dev,arg1,arg2,bufsize) char *arg1,*arg2; int16 dev; unsigned bufsize; { register unsigned base; register struct asy *ap; struct sgbuf sbuf; unsigned i=0; if (dev >= nasy) return -1; ap = &asy[dev]; /* ap->tty = malloc(strlen(arg2)+1);*/ strcpy(ap->tty,arg2); if ( (IORser[dev]=open(ap->tty, S_IREAD+S_IWRITE)) < 0) { printf("asy %s: Open failed.\015\012", ap->tty); fflush(stdout); return -1; } _gs_opt(IORser[dev], &sbuf); sbuf.sg_case = 0; sbuf.sg_backsp = 0; sbuf.sg_delete = 0; sbuf.sg_echo = 0; sbuf.sg_alf = 0; sbuf.sg_nulls = 0; sbuf.sg_pause = 0; sbuf.sg_page = 0; sbuf.sg_bspch = 0; sbuf.sg_dlnch = 0; sbuf.sg_eorch = 0; sbuf.sg_eofch = 0; sbuf.sg_rlnch = 0; sbuf.sg_dulnch = 0; sbuf.sg_psch = 0; sbuf.sg_kbich = 0; sbuf.sg_kbach = 0; sbuf.sg_bsech = 0; sbuf.sg_bellch = 0; sbuf.sg_xon = 0; sbuf.sg_xoff = 0; sbuf.sg_tabcr = 0; sbuf.sg_tabsiz = 0; _ss_opt(IORser[dev], &sbuf); switch(sbuf.sg_baud) { case 0: i = 50; break; case 1: i = 75; break; case 2: i = 110; break; case 3: i = 134; break; case 4: i = 150; break; case 5: i = 300; break; case 6: i = 600; break; case 7: i = 1200; break; case 8: i = 1800; break; case 10: i = 2400; break; case 12: i = 4800; break; case 14: i = 9600; break; case 15: i = 19200; break; case 16: i=38400; break; default: i= 0; } printf("asy %s :Open %i Baud, Ok.\015",ap->tty,i); return 0; } int asy_stop(iface) struct interface *iface; { return 0; } /* Asynchronous line I/O control (speed change not implemented */ asy_ioctl(interface,argc,argv) struct interface *interface; int argc; char *argv[]; { if(argc < 1){ printf("%d\015\012",asy[interface->dev].speed); return 0; } return asy_speed(interface->dev,atoi(argv[0])); } /* Set asynch line speed */ int asy_speed(dev,speed) int dev; int speed; { return 0; } /* Send a buffer to serial transmitter */ asy_output(dev,buf,cnt) unsigned dev; char *buf; unsigned short cnt; { if(dev >= nasy) return 0; write(IORser[dev], buf, cnt); } /* Receive characters from asynch line * Returns count of characters read */ unsigned asy_recv(dev,buf,cnt) int dev; char *buf; unsigned cnt; { register struct asy *ap; register int charpend; ap = &asy[dev]; if ( (charpend=_gs_rdy(IORser[dev])) < 0) return 0; charpend = read(IORser[dev], buf, min(charpend, cnt)); return charpend < 0 ? 0 : charpend; } int stxrdy(dev) int dev; { return 1; } /* dir in temp file (a lot of crap to do this in the 3.2 osk compiler). Short/long listings. For FTP */ char *getenv(); void free(); FILE * dir(path,full) char *path; int full; { FILE *fp, *fpo; char *name = "dirfile", *cp; char cmd[256], *fnamstr=cmd; char disk[256]; FILE *tmpfile(); unsigned char ch; int i,k,fp1; register int j; char *make_path(); char *ep, *np; void filedir(); DIR *dt; int dofree=0; if ((ep=getenv("TMPDIR"))!=NULL) { np=make_path(ep,name,1); dofree=1; } else np=name; strcpy(disk, path); for (cp=disk; *cp && *++cp!='/'; ) ; *cp = '\0'; if(full){ sprintf(cmd,"(dir -de %s; echo; free %s; echo)>-%s",path,disk,np); system(cmd); } else { fp1=creat(np,S_IREAD+S_IWRITE); if ((dt=opendir(path))!=NULL) { closedir(dt); strcat(path,"/*"); } filedir(path,0,fnamstr); if (*fnamstr=='\0') close(fp1); else { write(fp1,fnamstr,strlen(fnamstr)); write(fp1,"\015\012",2); while(1) { filedir(path,1,fnamstr); if (*fnamstr=='\0') { close(fp1); break; } else { write(fp1,fnamstr,strlen(fnamstr)); write(fp1,"\015\012",2); } } } /* NOTE, this ALMOST worked but added the path on a wildcard dir which messed up remote mgets. sprintf(cmd,"(dir -d %s; echo; free %s; echo)>-%s",path,disk,np); system(cmd); */ } fp = fopen(np,"r"); if((fpo = tmpfile())==NULLFILE) return NULLFILE; while ((i=fread(cmd,1,128,fp))) { k=0; for(j=0;jdirname && *--cp != '/'; ) ; strncpy(dname, dirname, cp-dirname); dname[cp-dirname] = '\0'; strcpy(filemask, cp+1); masklen = strlen(filemask); if (times==0) { /* first time */ if ( (d=opendir(dname)) == NULL ) { *ret_str = '\0'; return; } } while (1) { if ( (r=readdir(d)) == NULL ) { *ret_str = '\0'; closedir(d); return; } if (_cmpnam(r->d_name, filemask, masklen) == 0) if (r->d_name[0] != '.') { strcpy(ret_str, r->d_name); strcat(dname,"/"); strcat(dname,ret_str); if ((i=open(dname,S_IREAD))==-1) { if ((d2=opendir(dname))!=NULL) { closedir(d2); strcat(ret_str,"/"); } } else close(i); return; } } } dodir(argc, argv) int argc; char **argv; { int i, stat; char str[MAXCMD]; strcpy(str, "dir -e "); for (i = 1; i < argc; i++) { strcat(str, argv[i]); strcat(str, " "); } stat = system(str); return stat; } sysreset() { printf("\n no system reset function \n"); } doshell(argc,argv) int argc; char **argv; { struct sgbuf sgbufi, sgbufo; _gs_opt(0,&sgbufi); #ifdef STRANGECONS _gs_opt(1,&sgbufo); #endif _ss_opt(0,&orgsgbufi); #ifdef STRANGECONS _ss_opt(1,&orgsgbufo); #endif system(""); _ss_opt(0,&sgbufi); #ifdef STRANGECONS _ss_opt(1,&sgbufo); #endif } /* close a pipe (not different in osk)? */ int pclose(i) FILE *i; { fclose(i); } mkdir(s, m) char *s; int m; { char tmp[MAXCMD]; sprintf(tmp, "makdir %s", s); if (system(tmp)) return -1; /* if (chmod(s, m) < 0) return -1; */ return 0; } rmdir(s) char *s; { char tmp[MAXCMD]; sprintf(tmp, "deldir -f -q %s", s); if (system(tmp)) return -1; return 0; } OpenPty() { return -1; } char *getcwd(tmp,siz) char *tmp; int siz; { static int lock=0; char *name="pdfile"; char *ep, *np, *make_path(); FILE *fil; int dofree=0; while (lock); lock=1; if ((ep=getenv("TMPDIR"))!=NULLCHAR) { dofree=1; np=make_path(ep,name,1); } else np = name; sprintf(tmp,"pd >-%s",np); system(tmp); if ((fil=fopen(np,"r"))==NULL) { lock=0; return NULL; } fgets(tmp,siz,fil); fclose(fil); unlink(np); if (dofree) free(np); lock=0; return name; } /* enabled this command with k28 -- it was incomplete. Tried to do it in most portable way, though in SysV, it would be appropriate to feed getcwd a null pointer and free the memory pointed to by getcwd's return value. This command is used for "pwd" and "cd". - K5JB */ int docd(argc, argv) int argc; char **argv; { static char tmp[MAXCMD]; char *getcwd(); extern char *homedir; if(*argv[0] == 'c') if(chdir(argc > 1 ? argv[1] : homedir) == -1){ printf("Can't change directory\n"); return 1; } if (getcwd(tmp, sizeof(tmp) - 2) != NULL) printf("%s\n", tmp); return 0; } /***************************************************************************/ /* */ /* _secsince70() : Unix library (OS9/68000) */ /* ============= */ /* */ /* Author: K. Schmitt */ /* Compiler: Microware C Vers. 3.0 */ /* OS: OS9/68000 Vers. 2.2 */ /* */ /* Edition History */ /* =============== */ /* */ /* Ed. 0.00 Date 11/16/88 */ /* First version */ /* */ /***************************************************************************/ /* */ /* Description */ /* */ /* returns # of secs past since 01/01/1970 GMT */ time_t _secsince70 (date) char date []; /* yy/mm/dd/hh/mm/ss */ /* 0 1 2 3 4 5 */ { struct tm time70, time_; time_t mktime(); time70.tm_sec = 0; time70.tm_min = 0; time70.tm_hour = 0; time70.tm_mday = 1; time70.tm_mon = 0; time70.tm_year = 70; time70.tm_isdst = -1; time_.tm_sec = (int) date[5]; time_.tm_min = (int) date[4]; time_.tm_hour = (int) date[3]; time_.tm_mday = (int) date[2]; time_.tm_mon = (int) date[1] - 1; time_.tm_year = (int) date[0]; time_.tm_isdst = -1; return (mktime(&time_.tm_sec) - mktime(&time70.tm_sec)); } /* end of _secsince70 */ /***************************************************************************/ /* */ /* stat() : Unix library (OS9/68000) */ /* ====== */ /* */ /* Author: K. Schmitt */ /* Compiler: Microware C Vers. 3.0 */ /* OS: OS9/68000 Vers. 2.2 */ /* */ /* Edition History */ /* =============== */ /* */ /* Ed. 0.00 Date 11/16/88 */ /* First version */ /* */ /***************************************************************************/ /* */ /* Description */ /* */ /* NAME stat, fstat - get file status SYNOPSIS #include int stat (path, buf) char *path; struct stat *buf; int fstat (fildes, buf) int fildes; struct stat *buf; DESCRIPTION Path points to a path name naming a file. Read, write or execute permission of the named file is not required, but all directories listed in the path name leading to the file must be searchable. Stat obtains information about the named file. Fstat obtains information about an open file known by the file descriptor fildes, obtained from a successful open, creat, dup, fcntl, or pipe system call. Buf is a pointer to a stat structure into which information is placed concerning the file. The contents of the structure pointed to by buf include the following members: ushort st_mode; File mode ino_t st_ino; Inode number dev_t st_dev; ID of device containing a directory entry for this file dev_t st_rdev; ID of device. This entry is defined only for character special or block special files short st_nlink; Number of links ushort st_uid; User ID of the file's owner ushort st_gid; Group ID of the file's group off_t st_size; File size in bytes time_t st_atime; Time of last access time_t st_mtime; Time of last data modification time_t st_ctime; Time of last file status change Times measured in seconds since 00:00:00 GMT, Jan. 1, 1970 The following parameters are affected by different system calls: st_atime Time when file data was last accessed. Changed by the following system calls: creat, mknod, pipe, utime, and read. st_mtime Time when data was last modified. Changed by the following system calls: creat, mknod, pipe, utime, and write. st_ctime Time when file status was last changed. Changed by the following system calls: chmod, chown, creat, link, mknod, pipe, unlink, utime, and write. Stat will fail if one or more of the following are true: [ENOTDIR] A component of the path prefix is not a directory. [ENOENT] The named file does not exist. [EACCES] Search permission is denied for a component of the path prefix. [EFAULT] Buf or path points to an invalid address. Fstat will fail if one or more of the following are true: [EBADF] Fildes is not a valid open file descriptor. [EFAULT] Buf points to an invalid address. RETURN VALUE Upon successful completion a value of 0 is returned. Otherwise, a value of -1 is returned and errno is set to indicate the error. */ #include "os9stat.h" #include extern time_t _secsince70 (); int stat (fname, buf) char fname []; struct stat *buf; { int fd, ret; DIR *dirp; if ((fd = open (fname, S_IREAD)) == -1) { if ((dirp = opendir (fname)) == 0) return (-1); fd = dirp -> dd_fd; } else { dirp = 0; } ret = fstat (fd, buf); if (dirp == 0) close (fd); else closedir (dirp); return (ret); } /* end of stat */ int fstat (fd, buf) int fd; register struct stat *buf; { struct fildes fildes; register int i; register char *p; char *malloc(); if (_gs_gfd (fd, &fildes, sizeof (struct fildes)) == -1) return (-1); buf -> st_uid = (unsigned short) (fildes.fd_own [0]); buf -> st_gid = (unsigned short) (fildes.fd_own [1]); buf -> st_mode = (unsigned short) (fildes.fd_att) & 0377; buf -> st_nlink = (unsigned short) (fildes.fd_link); for (i = 0, p = (char *) (&buf -> st_size); i < 4; i++) { *p++ = fildes.fd_fsize [i]; } buf -> st_atime = buf -> st_mtime = _secsince70 (fildes.fd_date); fildes.fd_dcr [3] = 0; fildes.fd_dcr [4] = 0; buf -> st_ctime = _secsince70 (fildes.fd_dcr); if ((buf -> st_rdev = buf -> st_dev = malloc(30)) != (char *) 0) { _gs_devn (fd, buf -> st_dev); } return (0); } /* end of fstat */ #ifndef _UCC /***************************************************************************/ /* */ /* perror() : Unix library (OS9/68000) */ /* ======== */ /* */ /* Author: K. Schmitt / Ch. Engel */ /* Compiler: Microware C Vers. 3.0 */ /* OS: OS9/68000 Vers. 2.2 */ /* */ /* Edition History */ /* =============== */ /* */ /* Ed. 0.00 Date 11/11/88 */ /* First version */ /* */ /***************************************************************************/ /* */ /* Description */ /* */ /* NAME perror, sys_errlist, sys_nerr, errno - system error messages SYNOPSIS perror (s) char *s; int sys_nerr; char *sys_errlist[ ]; int errno; DESCRIPTION Perror produces a short error message on the standard error, describing the last error encountered during a system call from a C program. First the argument string s is printed, then a colon, then the message and a new-line. To be of most use, the argument string should be the name of the program that incurred the error. The error number is taken from the external variable errno, which is set when errors occur and cleared when non-erroneous calls are made. To simplify variant formatting of messages, the vector of message strings sys_errlist is provided; errno can be used as an index in this table to get the message string without the new-line. Sys_nerr is the largest message number provided for in the table; it should be checked because new error codes may be added to the system before they are added to the table. */ #include #define YES 1 #define NO 0 #define OK 0 #define ERR -1 #define ERRFILE "/dd/SYS/errmsg" #define MAXERR 256 extern int errno; int sys_nerr = MAXERR; char *sys_errlist [MAXERR]; static int errstat = OK; char *malloc (); perror (s) char *s; { static int first = YES; FILE *errfile; if (first) { first = NO; if ((errfile = fopen (ERRFILE, "r")) == NULL) { errstat = ERR; } else { _build_errlist (errfile); fclose (errfile); } } if (errstat) fprintf (stderr, "%s: %03d:%03d\n", s, errno >> 8, errno & 0x0ff); else fprintf (stderr, "%s: %s\n", s, sys_errlist [errno&(MAXERR-1)]); } /* end of perror */ #ifdef STATIC static #endif _build_errlist (errfile) FILE *errfile; { char message [1024], line [80]; register unsigned i; register char *p; for (i = 0; i < MAXERR ; i++) sys_errlist [i] = NULL; for (fgets (line, 80, errfile); ! feof (errfile); ) { if (! isdigit (line [0]) || strlen (line) < 7) { fgets (line, 80, errfile); continue; } i = (atoi (line) << 8) | atoi (line + 4); for (p = line + 7; *p && isspace (*p); p++) ; strcpy (message, p); fgets (line, 80, errfile); for ( ; line [0] != '\0' && ! isdigit (line [0]); fgets (line, 80, errfile)) { for (p = line; *p && isspace (*p); p++) ; strcat (message, p); } if (i >= MAXERR) break; if ((sys_errlist [i] = malloc (strlen (message) + 1)) == NULL) { errstat = ERR; return; } else { strcpy (sys_errlist [i], message); } } } /* end of _build_errlist */ FILE *tmpfile() { char *ep; char fname[80]; int done=0; int indx; char *make_path(); char *tmp; extern char *getenv(); FILE *fil, *fopen(); int access(); fname[0]='/'; fname[1]='a'; if ((ep = getenv("TMPDIR")) == NULLCHAR) if ((ep = getenv("NETSPOOL")) == NULLCHAR) perror("must set NETSPOOL env var\n"); done=0; indx=0; while (fname[1]<'z' && !done) { fname[2]='\0'; strcat(fname,".net_tmp"); tmp = make_path(ep,fname,0); if (!access(tmp,0)) { indx=indx+1; fname[1]=fname[1]+1; free(tmp); } else { if ((fil=fopen(tmp,"w+"))!=NULL) { tmpfils[indx].filptr=fil; strcpy(tmpfils[indx].tmpnam,tmp); done=1; } else { indx=indx+1; fname[1]=fname[1]+1; } } } if (done) { free(tmp); return fil; } else return NULLFILE; } int tmpclose(t) FILE *t; { int i=0; while(i<26) { if (tmpfils[i].filptr==t) { fclose(t); unlink(tmpfils[i].tmpnam); tmpfils[i].filptr=NULL; return 0; } i++; } /* printf("attempted to delete non-tempfile\n"); unavoidable but not important */ fclose(t); return 0; } int rename(s,d) char *s; char *d; { char *d2; char tmp[MAXCMD]; int access(); if (!access(d,0)) { if (unlink(d)) { printf("Can't rename file (no permission to unlink dup dest)\n"); return -1; } } else /* strip path from destination */ { d2=d; while (*d != '\0') { if(*d++ == '/') d2=d; } sprintf(tmp,"rename %s %s",s,d2); system(tmp); return 0; } } int fputc(c, fp) int c; FILE *fp; { putc(c,fp); } /***************************************************************************/ /* */ /* strtok() : Unix library (OS9/68000) */ /* ======== */ /* */ /* Author: Henry Spencer (UNIX stringlib from BIX) */ /* Compiler: Microware C Vers. 3.0 */ /* OS: OS9/68000 Vers. 2.2 */ /* */ /* Edition History */ /* =============== */ /* */ /* Ed. 0.00 Date 11/15/88 */ /* First version */ /* */ /***************************************************************************/ /* */ /* Description */ /* */ /* char *strpbrk(s1, s2) char *s1, *s2; Strtok considers the string s1 to consist of a sequence of zero or more text tokens separated by spans of one or more characters from the separator string s2. The first call (with pointer s1 specified) returns a pointer to the first character of the first token, and will have written a NULL character into s1 immediately following the returned token. Subsequent calls with zero for the first argument, will work through the string s1 in this way until no tokens remain. The separator string s2 may be different from call to call. When no token remains in s1, a NULL is returned. */ /*#define NULL 0 */ char *scanpoint = NULL; char * /* NULL if no token left */ strtok(s, delim) char *s; register char *delim; { register char *scan; char *tok; register char *dscan; if ((s == NULL) && (scanpoint == NULL)) return(NULL); if (s != NULL) scan = s; else scan = scanpoint; /* * Scan leading delimiters. */ for (; *scan != '\0'; scan++) { for (dscan = delim; *dscan != '\0'; dscan++) { if (*scan == *dscan) break; } if (*dscan == '\0') break; } if (*scan == '\0') { scanpoint = NULL; return(NULL); } tok = scan; /* * Scan token. */ for (; *scan != '\0'; scan++) { for (dscan = delim; *dscan != '\0';) /* ++ moved down. */ { if (*scan == *dscan++) { scanpoint = scan+1; *scan = '\0'; return(tok); } } } /* * Reached end of string. */ scanpoint = NULL; return(tok); } /* end of strtok */ #endif /* E O F */