mirror of
https://github.com/GnoConsortium/gno.git
synced 2025-02-24 22:29:12 +00:00
Initial checkin of install(1) for GNO, version 1.0.
This commit is contained in:
parent
6f6fee285e
commit
f8c4d4b6d5
33
usr.bin/install/COPYING
Normal file
33
usr.bin/install/COPYING
Normal file
@ -0,0 +1,33 @@
|
||||
Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution. If the binary form is created using Orca/C, then
|
||||
the following Byteworks' copyright notice must also be included
|
||||
in the same location.
|
||||
3. The name of the developer may not be used to endorse or promote
|
||||
products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE DEVELOPER "AS IS" AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The binary distribution of this program contains material from the Orca/C
|
||||
Run-Time Libraries, copyright 1987-1996 by Byte Works, Inc. Used with
|
||||
permission.
|
70
usr.bin/install/basename.c
Normal file
70
usr.bin/install/basename.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: basename.c,v 1.1 1996/03/31 23:38:30 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "install.h"
|
||||
|
||||
/*
|
||||
* basename
|
||||
*
|
||||
* returns the filename component of <path>. If <path> contains colons,
|
||||
* they are assumed to be the directory separators, otherwise any '/' is
|
||||
* assumed to be a directory separator.
|
||||
*
|
||||
* If no directory separators are found, then the full path is returned.
|
||||
*
|
||||
* No check is done as to whether the pathname is valid on the any
|
||||
* given filesystem.
|
||||
*/
|
||||
|
||||
char *
|
||||
basename (char *path)
|
||||
{
|
||||
char delim, *p;
|
||||
|
||||
delim = strchr(path,':') ? ':' : '/';
|
||||
p = strrchr(path,delim);
|
||||
return p ? p+1 : path;
|
||||
}
|
||||
|
||||
/*
|
||||
* dirname
|
||||
*
|
||||
* Returns a pointer to an internal buffer that contains a string that
|
||||
* matches the directory component
|
||||
* of <path>. If <path> contains at least one ':', then it is assumed
|
||||
* that colons are directory separators, otherwise any '/' character
|
||||
* is treated as a directory separator.
|
||||
*
|
||||
* If <path> contains no pathname separators, then dirname() will
|
||||
* return an empty (zero-length) string.
|
||||
*
|
||||
* No check is done as to whether the pathname is valid on the any
|
||||
* given filesystem.
|
||||
*/
|
||||
|
||||
char *
|
||||
dirname (char *path)
|
||||
{
|
||||
char delim, *p;
|
||||
static char dir[FILENAME_MAX];
|
||||
|
||||
strncpy(dir,path,FILENAME_MAX-1);
|
||||
dir[FILENAME_MAX-1] = '\0';
|
||||
delim = strchr(dir,':') ? ':' : '/';
|
||||
p = strchr(dir,delim);
|
||||
if (p == NULL) {
|
||||
*dir = '\0';
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
return dir;
|
||||
}
|
37
usr.bin/install/c2gs.c
Normal file
37
usr.bin/install/c2gs.c
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: c2gs.c,v 1.1 1996/03/31 23:38:31 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <gsos.h>
|
||||
#include <string.h>
|
||||
#include "install.h"
|
||||
|
||||
/*
|
||||
* __C2GS
|
||||
*
|
||||
* Converts a null-terminated C string into a class 1 GS/OS string.
|
||||
* Space for the GS/OS string must already be allocated, and the
|
||||
* length of s must not be more than 255 chars.
|
||||
*
|
||||
* If the s is too long, __C2GS will return NULL, otherwise it will
|
||||
* return the GS/OS string g.
|
||||
*/
|
||||
|
||||
GSString255Ptr
|
||||
__C2GS(char *s, GSString255Ptr g)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(s);
|
||||
if (len > 255) return NULL; /* the string won't fit */
|
||||
g->length = len;
|
||||
strncpy(g->text,s,255);
|
||||
return g;
|
||||
}
|
284
usr.bin/install/copyfile.c
Normal file
284
usr.bin/install/copyfile.c
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: copyfile.c,v 1.1 1996/03/31 23:38:31 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <gsos.h>
|
||||
#include <orca.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "install.h"
|
||||
|
||||
/* the chunk size in which we copy files */
|
||||
#define COPY_BUFFER_SIZE 1024
|
||||
|
||||
/*
|
||||
* copyfile
|
||||
*
|
||||
* copy a file from the pathname <from> to the location <to>, which
|
||||
* may be a directory. Ensure that file types and other information
|
||||
* (except for the backup bit) is matched.
|
||||
*
|
||||
* Returns NULL and sets errno on failure. On success, returns a
|
||||
* pointer to an internal buffer containing the final pathname.
|
||||
*
|
||||
* +++ THIS ROUTINE IS NOT REENTRANT +++
|
||||
*/
|
||||
|
||||
char *
|
||||
copyfile (char *from, char *to)
|
||||
{
|
||||
static char buffer[COPY_BUFFER_SIZE];
|
||||
static FileInfoRecGS inforec;
|
||||
static OpenRecGS openrec;
|
||||
static ExpandPathRecGS expandrec;
|
||||
static ResultBuf255 resultbuf;
|
||||
static struct {
|
||||
Word pCount;
|
||||
Word refNum;
|
||||
Longword dataBuffer;
|
||||
Longword requestCount;
|
||||
Longword transferCount;
|
||||
Word cachePriority;
|
||||
} iobuf;
|
||||
static struct {
|
||||
Word pCount;
|
||||
Word refNum;
|
||||
} closerec;
|
||||
static GSString255 fromGS, toGS;
|
||||
static char *result = NULL; /* we only use this if our path is */
|
||||
/* exactly 255 chars long */
|
||||
size_t len1, len2;
|
||||
Word refNumIn, refNumOut; /* GS/OS ref numbers for I/O */
|
||||
int isDir, i, j, k, done;
|
||||
char *p, *q, *r;
|
||||
|
||||
/* concheck and convert filenames to GSString255 type */
|
||||
if (!from || !to ||
|
||||
((len1 = strlen(from)) > 254) ||
|
||||
((len2 = strlen(to)) > 254) )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
fromGS.length = len1;
|
||||
toGS.length = len2;
|
||||
strcpy(fromGS.text,from);
|
||||
strcpy(toGS.text,to);
|
||||
|
||||
/* expand the original file name */
|
||||
expandrec.pCount = 3;
|
||||
expandrec.inputPath = &fromGS;
|
||||
expandrec.outputPath = &resultbuf;
|
||||
expandrec.flags = 0x0000;
|
||||
resultbuf.bufSize = 255;
|
||||
ExpandPathGS(&expandrec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
strcpyGSString255(&fromGS,&(resultbuf.bufString));
|
||||
|
||||
/* expand the destination name */
|
||||
expandrec.pCount = 3;
|
||||
expandrec.inputPath = &toGS;
|
||||
expandrec.outputPath = &resultbuf;
|
||||
expandrec.flags = 0x0000;
|
||||
resultbuf.bufSize = 255;
|
||||
ExpandPathGS(&expandrec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
strcpyGSString255(&toGS,&(resultbuf.bufString));
|
||||
|
||||
/* find out if <to> is a directory */
|
||||
inforec.pCount = 5;
|
||||
inforec.pathname = &toGS;
|
||||
GetFileInfoGS(&inforec);
|
||||
i = toolerror();
|
||||
switch(i) {
|
||||
case 0:
|
||||
isDir = ((inforec.storageType == 0x0D) ||
|
||||
(inforec.storageType == 0x0F)) ? 1 : 0;
|
||||
break;
|
||||
case fileNotFound:
|
||||
isDir = 0;
|
||||
break;
|
||||
default:
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* it's a directory? tack on the file name */
|
||||
if (isDir) {
|
||||
|
||||
/* expand the directory name */
|
||||
expandrec.pCount = 3;
|
||||
expandrec.inputPath = &toGS;
|
||||
expandrec.outputPath = &resultbuf;
|
||||
expandrec.flags = 0x0000;
|
||||
resultbuf.bufSize = 255;
|
||||
ExpandPathGS(&expandrec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* tack on the final component */
|
||||
p = basename(from);
|
||||
len1 = strlen(p);
|
||||
if (len1 + toGS.length + 1 > 255) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
q = &(toGS.text[toGS.length]);
|
||||
r = p;
|
||||
*q++ = ':';
|
||||
for (i=0; i<len1; i++) {
|
||||
*q++ = *r++;
|
||||
}
|
||||
toGS.length += len1 + 1;
|
||||
}
|
||||
|
||||
/* check to see it's not the same file */
|
||||
if (strcmpGSString255(&fromGS, &toGS) == 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the file info of the original file */
|
||||
inforec.pCount = 7;
|
||||
inforec.pathname = &fromGS;
|
||||
GetFileInfoGS(&inforec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* destroy the old target file if it exists */
|
||||
inforec.pCount = 1;
|
||||
inforec.pathname = &toGS; DestroyGS(&inforec);
|
||||
i = toolerror();
|
||||
switch(i) {
|
||||
case 0:
|
||||
case fileNotFound:
|
||||
break;
|
||||
default:
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create the new file */
|
||||
inforec.pCount = 5;
|
||||
inforec.pathname = &toGS;
|
||||
CreateGS(&inforec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy both forks, if necessary */
|
||||
for (i=0; i< ((inforec.storageType == extendedFile) ? 2 : 1); i++) {
|
||||
|
||||
/* open the input file */
|
||||
openrec.pCount = 4;
|
||||
openrec.pathname = &fromGS;
|
||||
openrec.requestAccess = readEnable;
|
||||
switch (i) {
|
||||
case 0:
|
||||
openrec.resourceNumber = 0x0000;
|
||||
break;
|
||||
case 1:
|
||||
openrec.resourceNumber = 0x0000;
|
||||
break;
|
||||
}
|
||||
OpenGS(&openrec);
|
||||
if ((j = toolerror()) != 0) {
|
||||
errno = _mapErr(j);
|
||||
return NULL;
|
||||
}
|
||||
refNumIn = openrec.refNum;
|
||||
|
||||
/* open the output file */
|
||||
openrec.pathname = &toGS;
|
||||
openrec.requestAccess = writeEnable;
|
||||
OpenGS(&openrec);
|
||||
if ((j = toolerror()) != 0) {
|
||||
closerec.pCount = 1;
|
||||
closerec.refNum = refNumIn;
|
||||
CloseGS(&closerec);
|
||||
errno = _mapErr(j);
|
||||
return NULL;
|
||||
}
|
||||
refNumOut = openrec.refNum;
|
||||
|
||||
/* transfer the data */
|
||||
done = 0;
|
||||
iobuf.pCount = 5;
|
||||
iobuf.dataBuffer = (Longword) &buffer;
|
||||
iobuf.cachePriority = cacheOn;
|
||||
while (!done) {
|
||||
|
||||
iobuf.refNum = refNumIn;
|
||||
iobuf.requestCount = COPY_BUFFER_SIZE;
|
||||
ReadGS(&iobuf);
|
||||
k = toolerror();
|
||||
switch (k) {
|
||||
case 0:
|
||||
break;
|
||||
case eofEncountered:
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
closerec.pCount = 1;
|
||||
closerec.refNum = refNumIn;
|
||||
CloseGS(&closerec);
|
||||
closerec.refNum = refNumOut;
|
||||
CloseGS(&closerec);
|
||||
errno = _mapErr(k);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iobuf.refNum = refNumOut;
|
||||
iobuf.requestCount = iobuf.transferCount;
|
||||
WriteGS(&iobuf);
|
||||
if ((k = toolerror()) != 0) {
|
||||
closerec.pCount = 1;
|
||||
closerec.refNum = refNumIn;
|
||||
CloseGS(&closerec);
|
||||
closerec.refNum = refNumOut;
|
||||
CloseGS(&closerec);
|
||||
errno = _mapErr(k);
|
||||
return NULL;
|
||||
}
|
||||
} /* end loop over buffering */
|
||||
closerec.pCount = 1;
|
||||
closerec.refNum = refNumIn;
|
||||
CloseGS(&closerec);
|
||||
closerec.refNum = refNumOut;
|
||||
CloseGS(&closerec);
|
||||
} /* end loop over forks */
|
||||
|
||||
/* set file information to match original file */
|
||||
inforec.pCount = 7;
|
||||
inforec.pathname = &toGS;
|
||||
SetFileInfoGS(&inforec);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
if (toGS.length == 255) {
|
||||
if (result) free(result);
|
||||
result = __GS2CMALLOC(&toGS);
|
||||
return result;
|
||||
}
|
||||
toGS.text[toGS.length]='\0';
|
||||
return toGS.text;
|
||||
}
|
125
usr.bin/install/errnoGS.c
Normal file
125
usr.bin/install/errnoGS.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: errnoGS.c,v 1.1 1996/03/31 23:38:31 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <gsos.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "install.h"
|
||||
|
||||
#pragma lint -1
|
||||
#pragma debug 0
|
||||
#pragma optimize -1
|
||||
|
||||
#define NONE "no error"
|
||||
#define UNKNOWN "unknown error"
|
||||
|
||||
segment "errnoGS___";
|
||||
|
||||
typedef struct errEntry {
|
||||
unsigned short num;
|
||||
char *str;
|
||||
} errEntry;
|
||||
|
||||
static errEntry
|
||||
sys_errlistGS[] = {
|
||||
{ badSystemCall, "bad system call number" },
|
||||
{ invalidPcount, "invalid parameter count" },
|
||||
{ gsosActive, "GS/OS already active" },
|
||||
{ devNotFound, "device not found" },
|
||||
{ invalidDevNum, "invalid device number" },
|
||||
{ drvrBadReq, "bad request or command" },
|
||||
{ drvrBadCode, "bad control or status code" },
|
||||
{ drvrBadParm, "bad call parameter" },
|
||||
{ drvrNotOpen, "character device not open" },
|
||||
{ drvrPriorOpen, "character device already open" },
|
||||
{ irqTableFull, "interrupt table full" },
|
||||
{ drvrNoResrc, "resources not available" },
|
||||
{ drvrIOError, "I/O error" },
|
||||
{ drvrNoDevice, "device not connected" },
|
||||
{ drvrBusy, "call aborted; driver is busy" },
|
||||
{ drvrWrtProt, "device is write protected" },
|
||||
{ drvrBadCount, "invalid byte count" },
|
||||
{ drvrBadBlock, "invalid block address" },
|
||||
{ drvrDiskSwitch, "disk has been switched" },
|
||||
{ drvrOffLine, "device off line/ no media present" },
|
||||
{ badPathSyntax, "invalid pathname syntax" },
|
||||
{ tooManyFilesOpen, "too many files open on server volume" },
|
||||
{ invalidRefNum, "invalid reference number" },
|
||||
{ pathNotFound, "subdirectory does not exist" },
|
||||
{ volNotFound, "volume not found" },
|
||||
{ fileNotFound, "file not found" },
|
||||
{ dupPathname, "create or rename with existing name" },
|
||||
{ volumeFull, "volume full error" },
|
||||
{ volDirFull, "volume directory full" },
|
||||
{ badFileFormat, "version error (incompatible file format)" },
|
||||
{ badStoreType, "unsupported (or incorrect) storage type" },
|
||||
{ eofEncountered, "end-of-file encountered" },
|
||||
{ outOfRange, "position out of range" },
|
||||
{ invalidAccess, "access not allowed" },
|
||||
{ buffTooSmall, "buffer too small" },
|
||||
{ fileBusy, "file is already open" },
|
||||
{ dirError, "directory error" },
|
||||
{ unknownVol, "unknown volume type" },
|
||||
{ paramRangeErr, "parameter out of range" },
|
||||
{ outOfMem, "out of memory" },
|
||||
{ dupVolume, "duplicate volume name" },
|
||||
{ notBlockDev, "not a block device" },
|
||||
{ invalidLevel, "specifield level outside legal range" },
|
||||
{ damagedBitMap, "block number too large" },
|
||||
{ badPathNames, "invalid pathnames for ChangePath" },
|
||||
{ notSystemFile, "not an executable file" },
|
||||
{ osUnsupported, "Operating System not supported" },
|
||||
{ stackOverflow, "too many applications on stack" },
|
||||
{ dataUnavail, "data unavailable" },
|
||||
{ endOfDir, "end of directory has been reached" },
|
||||
{ invalidClass, "invalid FST call class" },
|
||||
{ resForkNotFound, "file does not contain required resource" },
|
||||
{ invalidFSTID, "error - FST ID is invalid" },
|
||||
{ invalidFSTop, "invalid FST operation" },
|
||||
{ fstCaution, "FST handled call, but result is weird" },
|
||||
{ devNameErr, "device exists with same name as replacement name" },
|
||||
{ defListFull, "device list is full" },
|
||||
{ supListFull, "supervisor list is full" },
|
||||
{ fstError, "generic FST error" },
|
||||
{ resExistsErr, "cannot expand file, resource already exists" },
|
||||
{ resAddErr, "cannot add resource fork to this type file" },
|
||||
{ networkError, "generic network error" },
|
||||
{ 0, NONE } /* we shouldn't see this */
|
||||
};
|
||||
|
||||
unsigned short errnoGS = 0;
|
||||
|
||||
char *
|
||||
strerrorGS(unsigned short num)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (num == 0) return NONE;
|
||||
i = 0;
|
||||
while (sys_errlistGS[i].num) {
|
||||
if (sys_errlistGS[i].num == num) {
|
||||
return sys_errlistGS[i].str;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
perrorGS(char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap,format);
|
||||
vfprintf(stderr,format,ap);
|
||||
fprintf(stderr,": %s\n",strerrorGS(errnoGS));
|
||||
va_end(ap);
|
||||
return;
|
||||
}
|
53
usr.bin/install/expandpath.c
Normal file
53
usr.bin/install/expandpath.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: expandpath.c,v 1.1 1996/03/31 23:38:32 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <gsos.h>
|
||||
#include <errno.h>
|
||||
#include <orca.h>
|
||||
#include "install.h"
|
||||
|
||||
/*
|
||||
* expandpath
|
||||
*
|
||||
* Uses the GS/OS facilities to expand the pathname <path>. On
|
||||
* success, returns a pointer to the malloc'd expanded path. On
|
||||
* failure it will return NULL and set errno.
|
||||
*
|
||||
* Note that in using this function, all directory separators will
|
||||
* be converted to colons.
|
||||
*
|
||||
* Unfortunately, this routine uses a little over 0.5k of stack space ...
|
||||
*/
|
||||
|
||||
char *
|
||||
expandpath (char *path)
|
||||
{
|
||||
ExpandPathRecGS expand;
|
||||
GSString255 inStr;
|
||||
ResultBuf255 outBuf;
|
||||
int i;
|
||||
|
||||
if (__C2GS(path,&inStr) == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
expand.pCount = 3;
|
||||
expand.inputPath = &inStr;
|
||||
expand.outputPath = &outBuf;
|
||||
expand.flags = 0x0000;
|
||||
outBuf.bufSize = 255;
|
||||
ExpandPathGS(&expand);
|
||||
if ((i = toolerror()) != 0) {
|
||||
errno = _mapErr(i);
|
||||
return NULL;
|
||||
}
|
||||
return __GS2CMALLOC(&(outBuf.bufString));
|
||||
}
|
107
usr.bin/install/inst.1
Normal file
107
usr.bin/install/inst.1
Normal file
@ -0,0 +1,107 @@
|
||||
.\" Copyright 1996 Devin Reade <gdr@myrias.com>
|
||||
.\"
|
||||
.\" $Id: inst.1,v 1.1 1996/03/31 23:38:32 gdr Exp $
|
||||
.\"
|
||||
.TH INSTALL 1 "Commands and Applications" "31 Mar 96" "Version 1.0"
|
||||
.SH NAME
|
||||
install \- copy files and set their attributes
|
||||
.SH SYNOPSIS
|
||||
.BR install
|
||||
[
|
||||
.I options
|
||||
] [
|
||||
.BR -s
|
||||
]
|
||||
.I source
|
||||
.I dest
|
||||
.br
|
||||
.BR install
|
||||
[
|
||||
.I options
|
||||
] [
|
||||
.BR -s
|
||||
]
|
||||
.I source
|
||||
[ ... ]
|
||||
.I directory
|
||||
.br
|
||||
.BR install
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.BR -d
|
||||
]
|
||||
.I directory
|
||||
[ ... ]
|
||||
.SH DESCRIPTION
|
||||
.BR install
|
||||
copies files and sets their permission modes and, if possible, their
|
||||
owner and group. It is used similarily to
|
||||
.BR cp (1);
|
||||
typically used in Makefiles to copy programs into their destination
|
||||
directories. It can also be used to create the destination directories
|
||||
and any leading directories, and to set the directories modes.
|
||||
.LP
|
||||
Some of the options listed below are not implemented or are implemented
|
||||
in a restricted sense. Such options are recognised to maximize
|
||||
.BR install 's
|
||||
compatibility with other Unix versions, in order to minimize problems
|
||||
with ported shell scripts and makefiles. Where options are not fully
|
||||
implemented, it is usually due to differences between Unix and GS/OS.
|
||||
.SH OPTIONS
|
||||
.IP \fB-c\fR
|
||||
Ignored. This option is included for backwards compatibility
|
||||
with old Unix versions of
|
||||
.BR install .
|
||||
.IP \fB-d\fR
|
||||
Create each given directory and its leading directories, if they
|
||||
do not already exist.
|
||||
.IP "\fB-g\fR \fIgroup\fR"
|
||||
Set the group ownership of the installed file or directory to the group
|
||||
ID of
|
||||
.I group
|
||||
(default is the processes current group).
|
||||
.I group
|
||||
may also be a numeric group ID.
|
||||
.sp
|
||||
\fBThis is currently ignored under GNO.\fR
|
||||
.IP \fB-h\fR
|
||||
Show usage information and exit.
|
||||
.IP "\fB-m\fR \fImode\fR"
|
||||
Set the permission mode for the installed file or directory to
|
||||
.IR mode ,
|
||||
which can be either an octal number, or a symbolic mode as in the
|
||||
Unix chmod command,
|
||||
with 0 as the point of departure. The default mode is 0755.
|
||||
.sp
|
||||
Note that currently under GNO, the
|
||||
.I mode
|
||||
is interpreted in the traditional Unix sense in that it only affects
|
||||
read, write, and (to a limited extent) execute permissions.
|
||||
Furthermore, the only bits interpreted are those for the
|
||||
user permissions; the
|
||||
.I mode
|
||||
is effectively bitwise `anded' with the constant 0700.
|
||||
.sp
|
||||
An execute modification is only permitted when the original file
|
||||
is of type TXT or SRC. If the `execute bit' is enabled, then
|
||||
the file type will be changed to SRC and the auxilliary type to EXEC.
|
||||
This is equivalent to making the file an executable shell script.
|
||||
If the `execute bit' is disabled, then the file type will be changed
|
||||
to TXT and the auxilliary type to 0x0000.
|
||||
.IP "\fB-o\fR \fIowner\fR"
|
||||
If run as root, set the ownership of the installed file to the user ID of
|
||||
.IR owner .
|
||||
.I owner
|
||||
may also be numeric user ID.
|
||||
.sp
|
||||
\fBThis is currently ignored under GNO.\fR
|
||||
.IP \fB-s\fR
|
||||
Strip the symbol tables from the installed programs.
|
||||
.sp
|
||||
\fBThis is currently ignored under GNO.\fR
|
||||
.IP \fB-v\fR
|
||||
Show version number.
|
||||
.SH AUTHOR
|
||||
Devin Reade <gdr@eddore.myrias.com>
|
444
usr.bin/install/inst.c
Normal file
444
usr.bin/install/inst.c
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: inst.c,v 1.1 1996/03/31 23:38:33 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <orca.h>
|
||||
#include "install.h"
|
||||
|
||||
/* actions */
|
||||
#define NOCHANGE 0
|
||||
#define ASSIGN 1
|
||||
#define REMOVE 2
|
||||
#define ADD 3
|
||||
|
||||
/* permissions */
|
||||
#define S_USER 0700
|
||||
#define S_GROUP 0070
|
||||
#define S_OTHER 0007
|
||||
#define S_ALL 0777
|
||||
#define S_READ 0444
|
||||
#define S_WRITE 0222
|
||||
#define S_EXECUTE 0111
|
||||
|
||||
#define TYPE_TXT 0x04
|
||||
#define TYPE_SRC 0xB0
|
||||
#define TYPE_EXEC 0x00000006
|
||||
#define TYPE_NONE 0x00000000
|
||||
|
||||
#define VERSION "1.0"
|
||||
#define EMAIL "<gdr@myrias.com>"
|
||||
|
||||
char *versionMsg = "Version %s by Devin Reade %s\n";
|
||||
int dFlag;
|
||||
|
||||
extern int mkdir(const char *);
|
||||
extern int needsgno(void);
|
||||
extern void begin_stack_check(void);
|
||||
extern int end_stack_check(void);
|
||||
|
||||
/*
|
||||
* usage
|
||||
*
|
||||
* display usage information and exit
|
||||
*/
|
||||
|
||||
void
|
||||
usage (void)
|
||||
{
|
||||
fputs("Usage: install [-cdhsv] [-o owner] [-g group] [-m mode] ",stderr);
|
||||
fputs("source [...] dest\n\n",stderr);
|
||||
fputs("Options:\n",stderr);
|
||||
fputs("\t-c Ignored. (Backwards Unix compatibility)\n",stderr);
|
||||
fputs("\t-d Create the specified directories\n",stderr);
|
||||
fputs("\t-g group Specify group id (not implemented)\n",stderr);
|
||||
fputs("\t-h Show usage information and exit.\n",stderr);
|
||||
fputs("\t-m mode Specify (Unix) access mode\n",stderr);
|
||||
fputs("\t-o owner Specify owner id (not implemented)\n",stderr);
|
||||
fputs("\t-s Strip binary (not implemented)\n",stderr);
|
||||
fputs("\t-v Show version number\n\n",stderr);
|
||||
fprintf(stderr,versionMsg,VERSION,EMAIL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* getmode
|
||||
*
|
||||
* set mode to the value corresponding to the permission bit string
|
||||
* <str>. If the first char of <str> is a digit, then it is assumed
|
||||
* to be an octal number. Otherwise it is assumed to be a string of
|
||||
* the form "ug+rx" (in the usual chmod(1) format). Also sets action
|
||||
* to be the type of action to take, whether we're removing, adding,
|
||||
* or assigning the permission bits.
|
||||
*
|
||||
* If these assumptions don't hold, then return non-zero. Returns
|
||||
* zero and sets mode on success.
|
||||
*
|
||||
* Since the IIgs currently doesn't have the concept of "group" and
|
||||
* "other" permissions, we take everything from the user permissions.
|
||||
*/
|
||||
|
||||
int
|
||||
getmode (char *str, unsigned long *mode, int *action)
|
||||
{
|
||||
unsigned long who = 0L;
|
||||
unsigned long perm = 0L;
|
||||
char *p, *q;
|
||||
|
||||
/* octal number? */
|
||||
if (isdigit(*str)) {
|
||||
*action = ASSIGN;
|
||||
errno = 0;
|
||||
*mode = strtoul(str,NULL,8);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* it's not an absolute octal; treat as a string */
|
||||
if (((p = strchr(str,'+')) == NULL) &&
|
||||
((p = strchr(str,'-')) == NULL) &&
|
||||
((p = strchr(str,'=')) == NULL)) {
|
||||
errno = EINVAL;
|
||||
return errno;
|
||||
}
|
||||
switch (*p) {
|
||||
case '+': *action = ADD; break;
|
||||
case '-': *action = REMOVE; break;
|
||||
case '=': *action = ASSIGN; break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* this condition should really be deduced from the umask, if it
|
||||
* were supported.
|
||||
*/
|
||||
if (str == p) who |= S_USER;
|
||||
|
||||
for (q = str; q<p; q++) {
|
||||
switch (*q) {
|
||||
case 'u': who |= S_USER; break;
|
||||
case 'g': who |= S_GROUP; break;
|
||||
case 'o': who |= S_OTHER; break;
|
||||
case 'a': who |= S_ALL; break;
|
||||
default: errno = EINVAL; return errno;
|
||||
}
|
||||
}
|
||||
|
||||
for (q = p+1; *q; q++) {
|
||||
switch (*q) {
|
||||
case 'r': perm |= S_READ; break;
|
||||
case 'w': perm |= S_WRITE; break;
|
||||
case 'x': perm |= S_EXECUTE; break;
|
||||
case 's': /* ignored */ break;
|
||||
default: errno = EINVAL; return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* currently: ignore all but user permissions */
|
||||
if (!(who & S_USER)) {
|
||||
*action = NOCHANGE;
|
||||
}
|
||||
|
||||
*mode = who & perm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mkdirs
|
||||
*
|
||||
* argv is assumed to be an array of argc pathnames. mkdirs will
|
||||
* create all the listed directories, including their parents if
|
||||
* necessary.
|
||||
*
|
||||
* Returns zero on success. Returns non-zero and prints a suitable
|
||||
* error message on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
mkdirs (int argc, char **argv)
|
||||
{
|
||||
static struct stat statbuf; /* reduce stack space */
|
||||
char *path, *p;
|
||||
size_t pathlen;
|
||||
int result = 0;
|
||||
int makeit; /* do we try a mkdir()? */
|
||||
int abortpath; /* we saw an error; don't both with rest of path */
|
||||
int i,j;
|
||||
int coloncount;
|
||||
|
||||
/* loop over each of the pathnames in the array */
|
||||
for (i=0; i<argc; i++) {
|
||||
|
||||
/* expand to a full pathname */
|
||||
if ((path = expandpath(argv[i]))==NULL) {
|
||||
perror(argv[i]);
|
||||
continue;
|
||||
}
|
||||
pathlen = strlen(path);
|
||||
|
||||
/* is this pathname legal? */
|
||||
/* place a call to JudgeName() [custom] here */
|
||||
|
||||
/* find out how many path components there are */
|
||||
coloncount = 0;
|
||||
p = path;
|
||||
while (*p) {
|
||||
if (*p == ':') {
|
||||
coloncount++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p = path + 1;
|
||||
|
||||
/* skip the volume name */
|
||||
assert((p = strchr(p,':'))!=NULL);
|
||||
p++;
|
||||
--coloncount;
|
||||
|
||||
/* create each component in path */
|
||||
abortpath = 0;
|
||||
for (j=0; !abortpath && j<coloncount; j++) {
|
||||
if ((p = strchr(p,':')) == NULL) {
|
||||
p = path + pathlen;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
if (stat(path,&statbuf) != 0) {
|
||||
if (errno == ENOENT) {
|
||||
makeit = 1;
|
||||
} else {
|
||||
perror(path);
|
||||
makeit = 0;
|
||||
abortpath = 1;
|
||||
result = 1;
|
||||
}
|
||||
} else {
|
||||
makeit = 0;
|
||||
if (statbuf.st_mode & S_IFDIR == 0) {
|
||||
fprintf(stderr,"%s exists and is not a directory\n",path);
|
||||
abortpath = 1;
|
||||
result = 1;
|
||||
} /* else it exists and is a directory */
|
||||
}
|
||||
|
||||
/* go ahead and create the directory */
|
||||
if (makeit && mkdir(path)) {
|
||||
perror(path);
|
||||
abortpath = 1;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* reinstate the ':' that we "nulled-out" */
|
||||
if (p != path + pathlen) {
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* copyfiles
|
||||
*
|
||||
* <argv> is assumed to be an array of <argc> filenames.
|
||||
*
|
||||
* This routine copies all but the last specified file to the directory
|
||||
* or filename specified by the last filename. If argc>2, the last element
|
||||
* _must_ be a directory.
|
||||
*
|
||||
* Returns zero on success. On failure, returns the last non-zero errno
|
||||
* and prints error conditions to stderr.
|
||||
*
|
||||
* If action is not NOCHANGE, this routine will also set file permissions
|
||||
* as specified in the install(1) man page. This may involve changing
|
||||
* the file type.
|
||||
*/
|
||||
|
||||
static int
|
||||
copyfiles (int argc, char **argv, int action, unsigned long mode)
|
||||
{
|
||||
static FileInfoRecGS inforec;
|
||||
static GSString255 filenameGS;
|
||||
int i,j;
|
||||
int result=0;
|
||||
char *destination;
|
||||
Word newaccess;
|
||||
|
||||
if (argc < 2) {
|
||||
errno = EINVAL;
|
||||
perror("internal error: not enough arguments to copyfiles()");
|
||||
return errno;
|
||||
}
|
||||
if (argc > 2) {
|
||||
|
||||
/* find out if argv[argc-1] is a directory */
|
||||
|
||||
if (__C2GS(argv[argc-1], &filenameGS) == NULL) {
|
||||
errno = EINVAL;
|
||||
perror("destination path too long");
|
||||
return errno;
|
||||
}
|
||||
inforec.pCount = 5;
|
||||
inforec.pathname = &filenameGS;
|
||||
GetFileInfoGS(&inforec);
|
||||
if ((errnoGS = toolerror()) != 0) {
|
||||
perrorGS("%s",argv[argc-1]);
|
||||
errno = _mapErr(errnoGS);
|
||||
return -1;
|
||||
}
|
||||
if ((inforec.storageType != 0x0D) && (inforec.storageType != 0x0F)) {
|
||||
errno = ENOTDIR;
|
||||
perror(argv[argc-1]);
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
--argc;
|
||||
for (i=0; i<argc; i++) {
|
||||
if ((destination = copyfile (argv[i],argv[argc])) == NULL) {
|
||||
errnoGS = toolerror();
|
||||
perrorGS("install of %s to %s",argv[i],argv[argc]);
|
||||
result = errno = _mapErr(errnoGS);
|
||||
}
|
||||
if (action == NOCHANGE) continue;
|
||||
|
||||
/* get the file info for the source file */
|
||||
assert(__C2GS(argv[i],&filenameGS));
|
||||
inforec.pCount = 7;
|
||||
inforec.pathname = &filenameGS;
|
||||
GetFileInfoGS(&inforec);
|
||||
if ((errnoGS = toolerror()) != 0) {
|
||||
perrorGS("GetFileInfo for %s failed",argv[i]);
|
||||
result = errno = _mapErr(errnoGS);
|
||||
}
|
||||
|
||||
/* modify the permissions as necessary */
|
||||
switch (action) {
|
||||
case ASSIGN:
|
||||
newaccess = 0xFFFF;
|
||||
if (!(mode & S_READ)) newaccess &= ~readEnable;
|
||||
if (!(mode & S_WRITE)) newaccess &= ~writeEnable;
|
||||
inforec.access &= newaccess;
|
||||
|
||||
if ((mode & S_EXECUTE) &&
|
||||
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
|
||||
inforec.fileType = TYPE_SRC;
|
||||
inforec.auxType = TYPE_EXEC;
|
||||
}
|
||||
break;
|
||||
|
||||
case ADD:
|
||||
if (mode & S_READ) inforec.access |= readEnable;
|
||||
if (mode & S_WRITE) inforec.access |= writeEnable;
|
||||
|
||||
if ((mode & S_EXECUTE) &&
|
||||
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
|
||||
inforec.fileType = TYPE_SRC;
|
||||
inforec.auxType = TYPE_EXEC;
|
||||
}
|
||||
break;
|
||||
|
||||
case REMOVE:
|
||||
if (mode & S_READ) inforec.access &= ~readEnable;
|
||||
if (mode & S_WRITE) inforec.access &= ~writeEnable;
|
||||
|
||||
if ((mode & S_EXECUTE) &&
|
||||
(inforec.fileType == TYPE_TXT) || (inforec.fileType == TYPE_SRC)) {
|
||||
inforec.fileType = TYPE_TXT;
|
||||
inforec.auxType = TYPE_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* set the modified file info for the destination file */
|
||||
assert(__C2GS(destination,&filenameGS));
|
||||
SetFileInfoGS(&inforec);
|
||||
if ((errnoGS = toolerror()) != 0) {
|
||||
perrorGS("SetFileInfo for %s failed",destination);
|
||||
result = errno = _mapErr(errnoGS);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* obvious ...
|
||||
*/
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
unsigned long mode;
|
||||
int c, nfiles;
|
||||
int action = NOCHANGE;
|
||||
|
||||
#ifdef CHECK_STACK
|
||||
begin_stack_check();
|
||||
#endif
|
||||
|
||||
if (needsgno()==0) {
|
||||
fprintf(stderr,"Requires GNO/ME\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialize */
|
||||
dFlag = 0;
|
||||
mode = 0L;
|
||||
|
||||
/* parse command line */
|
||||
while ((c = getopt(argc,argv,"cdg:hm:o:sv")) != EOF) {
|
||||
switch (c) {
|
||||
case 'v':
|
||||
fprintf(stderr,versionMsg,VERSION,EMAIL);
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (getmode(optarg,&mode,&action)) usage();
|
||||
break;
|
||||
|
||||
case 'd': dFlag++;
|
||||
case 'c': /* not implemented */
|
||||
case 'g': /* not implemented */
|
||||
case 'o': /* not implemented */
|
||||
case 's': /* not implemented */
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default: usage();
|
||||
}
|
||||
}
|
||||
|
||||
nfiles = argc - optind;
|
||||
|
||||
if (dFlag) {
|
||||
if (nfiles < 1) usage();
|
||||
c = mkdirs(nfiles,&argv[optind]);
|
||||
} else {
|
||||
if (nfiles < 2) usage();
|
||||
c = copyfiles(nfiles, &argv[optind], action, mode);
|
||||
}
|
||||
|
||||
#ifdef CHECK_STACK
|
||||
fprintf(stderr,"stack usage: %d bytes\n",end_stack_check());
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
12
usr.bin/install/inst.desc
Normal file
12
usr.bin/install/inst.desc
Normal file
@ -0,0 +1,12 @@
|
||||
Name: install
|
||||
Version: 1.0 (31 Mar 96)
|
||||
Shell: GNO/ME
|
||||
Author: Devin Reade
|
||||
Contact: gdr@myrias.com
|
||||
Where: /usr/bin
|
||||
FTP: apple2.caltech.edu, ground.isca.uiowa.edu
|
||||
|
||||
Install is similar to cp(1) in that it copies files. It will
|
||||
also create directory hierarchies, and modify some access bits.
|
||||
It is intended for use with Makefiles or other scripts to install
|
||||
files into their destination directories.
|
25
usr.bin/install/inst.rez
Normal file
25
usr.bin/install/inst.rez
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: inst.rez,v 1.1 1996/03/31 23:38:34 gdr Exp $
|
||||
*/
|
||||
|
||||
#include "Types.Rez"
|
||||
|
||||
resource rVersion (0x1, purgeable3, nocrossbank) {
|
||||
|
||||
{ 1, 0, 0, /* version 1.0.0 */
|
||||
release, /* development|alpha|beta|final|release */
|
||||
0 /* non-final release number */
|
||||
},
|
||||
verBritain, /* close enough */
|
||||
"install",
|
||||
"Unix-style install program --\n"
|
||||
" copies files and creates directories\n"
|
||||
"Devin Reade <gdr@myrias.com>\n"
|
||||
"Canada"
|
||||
};
|
43
usr.bin/install/install.h
Normal file
43
usr.bin/install/install.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: install.h,v 1.1 1996/03/31 23:38:33 gdr Exp $
|
||||
*/
|
||||
|
||||
#ifndef __GSOS__
|
||||
#include <gsos.h>
|
||||
#endif
|
||||
|
||||
/* these are from libc */
|
||||
extern GSString255Ptr __C2GSMALLOC (char *s);
|
||||
extern char * __GS2CMALLOC (GSString255Ptr g);
|
||||
extern char * __GS2C (char *s, GSString255Ptr g);
|
||||
extern int _mapErr (int err);
|
||||
|
||||
/* from basename.c */
|
||||
extern char *dirname (char *path);
|
||||
extern char *basename (char *path);
|
||||
|
||||
/* from c2gs.c */
|
||||
extern GSString255Ptr __C2GS(char *s, GSString255Ptr g);
|
||||
|
||||
/* from copyfile.c */
|
||||
extern char *copyfile (char *from, char *to);
|
||||
|
||||
/* from errnoGS.c */
|
||||
extern unsigned short errnoGS;
|
||||
extern char *strerrorGS (unsigned short num);
|
||||
extern void perrorGS (char *format, ...);
|
||||
|
||||
/* from expandpath.c */
|
||||
extern char *expandpath (char *path);
|
||||
|
||||
/* from stringGS.c */
|
||||
extern void strcpyGSString255 (GSString255Ptr to, GSString255Ptr from);
|
||||
extern void strcatGSString255 (GSString255Ptr to, GSString255Ptr from);
|
||||
extern int strcmpGSString255 (GSString255Ptr a, GSString255Ptr b);
|
||||
|
40
usr.bin/install/makefile.mk
Normal file
40
usr.bin/install/makefile.mk
Normal file
@ -0,0 +1,40 @@
|
||||
#
|
||||
# This makefile is for use with dmake(1).
|
||||
#
|
||||
# $Id: makefile.mk,v 1.1 1996/03/31 23:38:34 gdr Exp $
|
||||
#
|
||||
|
||||
DEFINES = -DCHECK_STACK
|
||||
STACK = -s1280
|
||||
MAINFLAGS = $(DEFINES) $(STACK) -w -O
|
||||
CFLAGS = $(DEFINES) $(STACK) -w -O -r
|
||||
LDFLAGS = -v
|
||||
LDLIBS = -l/usr/lib/stack
|
||||
BINDIR = /usr/bin
|
||||
MANDIR = /usr/man
|
||||
|
||||
OBJS = install.o basename.o c2gs.o copyfile.o errnoGS.o \
|
||||
expandpath.o stringGS.o
|
||||
|
||||
install: $(OBJS) install.r
|
||||
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
|
||||
copyfork install.r install -r
|
||||
@echo 'type \"dmake doinstall\" to install this program'
|
||||
|
||||
install.o: install.c install.h
|
||||
$(CC) -c $(MAINFLAGS) install.c -o $@
|
||||
|
||||
doinstall:
|
||||
./install -m755 -obin -gsys ./install $(BINDIR)
|
||||
./install -m644 -obin -gsys ./install.1 $(MANDIR)/man1
|
||||
|
||||
clean clobber:
|
||||
$(RM) $(OBJS) install.root install.r
|
||||
|
||||
basename.o :: install.h
|
||||
c2gs.o :: install.h
|
||||
copyfile.o :: install.h
|
||||
errnoGS.o :: install.h
|
||||
expandpath.o :: install.h
|
||||
stringGS.o :: install.h
|
||||
|
78
usr.bin/install/stringGS.c
Normal file
78
usr.bin/install/stringGS.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 1996 Devin Reade <gdr@myrias.com>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* For copying and distribution information, see the file "COPYING"
|
||||
* accompanying this file.
|
||||
*
|
||||
* $Id: stringGS.c,v 1.1 1996/03/31 23:38:34 gdr Exp $
|
||||
*/
|
||||
|
||||
#include <gsos.h>
|
||||
#include "install.h"
|
||||
|
||||
/*
|
||||
* strcpyGSString255
|
||||
*
|
||||
* copies the GSString255 pointed to by <from> to that pointed
|
||||
* to by <to>
|
||||
*/
|
||||
|
||||
void
|
||||
strcpyGSString255 (GSString255Ptr to, GSString255Ptr from)
|
||||
{
|
||||
int i;
|
||||
|
||||
char *p = from->text;
|
||||
char *q = to->text;
|
||||
for (i=0; i<from->length; i++) *q++ = *p++;
|
||||
to->length = from->length;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* strcatGSString255
|
||||
*
|
||||
* concatenates the string <from> onto <to>, to a maximum of 255
|
||||
* chars total in <to>.
|
||||
*/
|
||||
|
||||
void
|
||||
strcatGSString255 (GSString255Ptr to, GSString255Ptr from)
|
||||
{
|
||||
int i, count;
|
||||
|
||||
char *p = from->text;
|
||||
char *q = to->text;
|
||||
q+= to->length;
|
||||
count = from->length;
|
||||
if (count > 255 - to->length) count = 255 - to->length;
|
||||
for (i=0; i<count; i++) {
|
||||
*q++ = *p++;
|
||||
}
|
||||
to->length += count;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* like strcmp(3), but for GSString255Ptr args.
|
||||
*/
|
||||
|
||||
int
|
||||
strcmpGSString255 (GSString255Ptr a, GSString255Ptr b)
|
||||
{
|
||||
int i, count;
|
||||
char *p, *q;
|
||||
|
||||
count = a->length - b->length;
|
||||
if (count) return count;
|
||||
|
||||
p = a->text;
|
||||
q = b->text;
|
||||
for (i=0; i<count; i++, p++, q++) {
|
||||
if (*p == *q) continue;
|
||||
else if (*p > *q) return 1;
|
||||
else return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user