1697 lines
48 KiB
C
1697 lines
48 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/***************************************************************************
|
|
*
|
|
* File: findnewrcs.c
|
|
* RCS: $XConsortium: findnewrcs.c /main/3 1995/10/30 13:42:46 rswiston $
|
|
* Description: The 'findnewrcs' command is used to descend a tree, checking
|
|
* out the newest version of any RCS file which has been updated.
|
|
* It can also be used to create a clone of a source tree using
|
|
* symbolic links.
|
|
* Author: Dave Serisky, Corvallis Workstation Operation
|
|
* Created: Tue Jun 7 09:39:47 1988
|
|
* Modified: Brian Cripe, (bcripe@hpcvlx) bcripe@hpcvxbc
|
|
* Modified: Marc Ayotte, (marca@hpcvlx)
|
|
* Language: C
|
|
* Package: N/A
|
|
* Status: Experimental (Do Not Distribute)
|
|
*
|
|
* (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
|
|
*
|
|
********************************************************************************
|
|
*/
|
|
|
|
static char version[] = "@(#) $XConsortium: findnewrcs.c /main/3 1995/10/30 13:42:46 rswiston $";
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef apollo
|
|
#ifndef S_ISLNK
|
|
#define S_ISLNK(m) (((m) & 0170000) == 0120000)
|
|
#endif
|
|
#ifndef S_ISDIR
|
|
#define S_ISDIR(m) (((m) & 0170000) == 0040000)
|
|
#endif
|
|
#ifndef S_ISREG
|
|
#define S_ISREG(m) (((m) & 0170000) == 0100000)
|
|
#endif
|
|
#define UID_NO_CHANGE -1
|
|
#include <sys/dir.h>
|
|
#else
|
|
# if defined(USL) && !defined(S_ISLNK)
|
|
# define S_ISLNK(m) ((m&0xF000) == S_IFLNK)
|
|
# endif
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
#ifndef __hpux
|
|
#define UID_NO_CHANGE -1
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <grp.h>
|
|
#ifdef apollo
|
|
#include <sys/time.h>
|
|
#else
|
|
#include <utime.h>
|
|
#endif
|
|
|
|
extern char *getcwd();
|
|
extern char *malloc();
|
|
extern DIR *opendir();
|
|
#ifdef apollo
|
|
extern struct direct *readdir();
|
|
#else
|
|
extern struct dirent *readdir();
|
|
#endif
|
|
extern long telldir();
|
|
extern char *mktemp();
|
|
|
|
char Buffer[BUFSIZ];
|
|
char *WorkingDirCmp;
|
|
int WorkingLen;
|
|
char *SourceDirCmp;
|
|
int SourceLen;
|
|
|
|
void GetNew();
|
|
char *ResolveLink();
|
|
|
|
static int Debug = 0;
|
|
static int Quiet = 0;
|
|
static int Verbose = 0;
|
|
static int MakeDirs = 0;
|
|
static int DoDiffs = 0;
|
|
static int SourcePriority = 0;
|
|
static int NoRcsLinks = 0;
|
|
static int NoRealFiles = 0;
|
|
static int LinkFiles = 0;
|
|
static int CloneDotA = 0;
|
|
static int CloneDotO = 0;
|
|
static int CloneMakefile = 0;
|
|
static int CloneExecutables = 0;
|
|
static int Check = 0;
|
|
static int DoExecute = 0;
|
|
static int FollowDirLinks = 0;
|
|
static int ResolveFileLinks = 1;
|
|
static int ProcessSCCSdirs = 0;
|
|
static char *DiffCommand = "diff";
|
|
|
|
static char *OutFile = "/tmp/,outXXXXXX";
|
|
static char *Makefile = "Makefile";
|
|
|
|
typedef struct _flist {
|
|
char *fullname;
|
|
char *keyname;
|
|
int keylen;
|
|
int used;
|
|
struct stat st;
|
|
int st_valid;
|
|
struct stat lst;
|
|
int lst_valid;
|
|
struct _flist *next;
|
|
} flist;
|
|
|
|
void
|
|
Usage(ProgName)
|
|
char *ProgName;
|
|
{
|
|
(void) fprintf(stderr, "\
|
|
usage: %s [options] [-W <working dir>] [-S <RCS dir>] [subdir ...] \n\
|
|
\n\
|
|
options:\n\
|
|
-i[Aaoxm]\n\
|
|
clone: A - all the following\n\
|
|
a - \"*.a\" files\n\
|
|
o - \"*.o\" files\n\
|
|
x - executables ('x' mode bits set)\n\
|
|
m - \"Makefile*\" files\n\
|
|
-v verbose (the more, the verboser)\n\
|
|
source files\n\
|
|
-L take checked out source over RCS regardless of time\n\
|
|
-O don't check out new files, Only create symbolic links to exiting files\n\
|
|
(this option is for cloning build trees from controlled source trees)\n\
|
|
-R don't create any RCS links\n\
|
|
-l symbolicly link files instead of copying them\n\
|
|
-m make any missing directories\n\
|
|
-q quiet\n\
|
|
-d diff new versions of existing files\n\
|
|
-c<cmd> use <cmd> to do diffs (default is diffc)\n\
|
|
-o<out> write diffs to <out> instead of /tmp/,out??????\n\
|
|
-W<dir> use working directory <dir> (default is \".\")\n\
|
|
-S<dir> use RCS/source directory <dir>\n\
|
|
(default is /RCS directories of working tree)\n\
|
|
-f follow source-tree links to non-RCS dirs (old behavior)\n\
|
|
-X execute instead of generating shell script\n\
|
|
-C process SCCS directories if present\n\
|
|
-s do not resolve symbolic links for files. use file name\n\
|
|
", ProgName);
|
|
(void) exit(1);
|
|
}
|
|
|
|
static void do_rm_rf(), do_touch(), do_ln_s(), do_diff(), do_rm_f();
|
|
static void do_cp(), do_chmod(), do_co_q(), do_mkdir(), do_chgrp();
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
char *WorkingDir = (char *) 0;
|
|
char *SourceDir = (char *) 0;
|
|
register int i;
|
|
register char *c;
|
|
int same = 0;
|
|
struct stat st;
|
|
|
|
extern int getopt();
|
|
extern char *optarg;
|
|
extern int optind;
|
|
extern int opterr;
|
|
|
|
(void) setvbuf(stdout, (char *) 0, _IOLBF, BUFSIZ);
|
|
OutFile = mktemp(OutFile);
|
|
|
|
while ((i = getopt(argc, argv, "-S:-W:i:OLRXflsCmqvd~c:o:")) != EOF) {
|
|
switch (i) {
|
|
case 'W' :
|
|
/* Working directory. Default is current directory */
|
|
WorkingDir = optarg;
|
|
break;
|
|
|
|
case 'S' :
|
|
/* Source directory. Default is to use working directories
|
|
** /RCS directories.
|
|
*/
|
|
SourceDir = optarg;
|
|
break;
|
|
|
|
case 'i' :
|
|
/* Parse off no ignore options */
|
|
for (c = optarg; *c; c++) {
|
|
switch (*c) {
|
|
case 'A' :
|
|
/* don't ignore any... */
|
|
(void) CloneDotA++;
|
|
(void) CloneDotO++;
|
|
(void) CloneExecutables++;
|
|
(void) CloneMakefile++;
|
|
break;
|
|
|
|
case 'a' :
|
|
/* don't ignore *.a files */
|
|
(void) CloneDotA++;
|
|
break;
|
|
|
|
case 'o' :
|
|
/* don't ignore *.o files */
|
|
(void) CloneDotO++;
|
|
break;
|
|
|
|
case 'x' :
|
|
/* don't ignore executables */
|
|
(void) CloneExecutables++;
|
|
break;
|
|
|
|
case 'm' :
|
|
/* don't ignore Makefiles */
|
|
(void) CloneMakefile++;
|
|
break;
|
|
|
|
default :
|
|
(void) Usage(argv[0]);
|
|
(void) exit(1);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'R' :
|
|
/* dont create any links for "/RCS" */
|
|
(void) NoRcsLinks++;
|
|
break;
|
|
|
|
case 'L' :
|
|
/* Take existing checked out files even if they are older than
|
|
** the RCS copy.
|
|
*/
|
|
(void) SourcePriority++;
|
|
break;
|
|
|
|
case 'O' :
|
|
/* Don't check out new files, just create sym links to existing files.
|
|
** This is to protect controlled source/build trees from having
|
|
** files bypass the crt process.
|
|
*/
|
|
(void) NoRealFiles++;
|
|
break;
|
|
|
|
case 'f' :
|
|
FollowDirLinks = 1;
|
|
break;
|
|
|
|
case 'C' :
|
|
ProcessSCCSdirs = 1;
|
|
break;
|
|
|
|
case 'X' :
|
|
DoExecute = 1;
|
|
break;
|
|
|
|
case 'l' :
|
|
/* Link files (when possible) instead of creating them. */
|
|
(void) LinkFiles++;
|
|
break;
|
|
|
|
case 'm' :
|
|
/* Make any directories necessary. */
|
|
(void) MakeDirs++;
|
|
break;
|
|
|
|
case 'q' :
|
|
/* Be quiet. */
|
|
(void) Quiet++;
|
|
break;
|
|
|
|
case 'v' :
|
|
/* Increase verbosity. */
|
|
(void) Verbose++;
|
|
break;
|
|
|
|
case 'd' :
|
|
/* Diff out new files. */
|
|
(void) DoDiffs++;
|
|
break;
|
|
|
|
case 'c' :
|
|
/* Alternative diff command. */
|
|
DiffCommand = optarg;
|
|
break;
|
|
|
|
case 'o' :
|
|
/* Output file name for diffs */
|
|
OutFile = optarg;
|
|
break;
|
|
|
|
case 's' :
|
|
/* don't resolve symbolic links for files */
|
|
ResolveFileLinks = 0;
|
|
break;
|
|
|
|
case '~' :
|
|
/* Increment debug switch */
|
|
(void) Debug++;
|
|
break;
|
|
|
|
default:
|
|
(void) Usage(argv[0]);
|
|
(void) exit(1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* no WorkingDir specified or not root relative? */
|
|
if (!WorkingDir || !*WorkingDir || ('/' != *WorkingDir)) {
|
|
/* get the current directory */
|
|
if (NULL == (c = getcwd(Buffer, sizeof(Buffer)))) {
|
|
(void) fprintf(stderr, "%s: can't get current working directory\n",
|
|
argv[0]);
|
|
(void) exit(1);
|
|
}
|
|
|
|
/* did they specify a partial path? */
|
|
if (WorkingDir && *WorkingDir) {
|
|
/* prepend the path to the working dir */
|
|
char *c2;
|
|
|
|
c2 = malloc((unsigned) (strlen(c) + strlen(WorkingDir) + 2));
|
|
(void) sprintf(c2, "%s/%s", c, WorkingDir);
|
|
WorkingDir = c2;
|
|
} else {
|
|
/* working dir is current path */
|
|
WorkingDir = malloc((unsigned) (strlen(c) + 1));
|
|
(void) strcpy(WorkingDir, c);
|
|
}
|
|
}
|
|
|
|
/* SourceDir specified? */
|
|
if (!SourceDir || !*SourceDir) {
|
|
/* Let's see if there is an /RCS dir in WorkingDir */
|
|
SourceDir = malloc((unsigned) (strlen(WorkingDir) + 5));
|
|
(void) strcpy(SourceDir, WorkingDir);
|
|
(void) strcat(SourceDir, "/RCS");
|
|
if (!lstat(SourceDir, &st)) {
|
|
if (S_ISLNK(st.st_mode)) {
|
|
SourceDir = ResolveLink(SourceDir, 1);
|
|
}
|
|
}
|
|
/* strip off the "/RCS" portion of it */
|
|
c = strrchr(SourceDir, '/');
|
|
if (*c && !strcmp(c, "/RCS"))
|
|
*c = '\0';
|
|
(void) fprintf(stderr, "using sourcedir of \"%s\"\n", SourceDir);
|
|
} else {
|
|
/* is it root relative? */
|
|
if ('/' != *SourceDir) {
|
|
/* get the current directory */
|
|
char *c2;
|
|
|
|
if (NULL == (c = getcwd(Buffer, sizeof(Buffer)))) {
|
|
(void) fprintf(stderr,
|
|
"%s: can't get current working directory\n",
|
|
argv[0]);
|
|
(void) exit(1);
|
|
}
|
|
|
|
c2 = malloc((unsigned) (strlen(c) + strlen(SourceDir) + 2));
|
|
(void) sprintf(c2, "%s/%s", c, SourceDir);
|
|
SourceDir = c2;
|
|
}
|
|
}
|
|
|
|
/* are the 2 directories the same name?
|
|
*/
|
|
if (!strcmp(SourceDir, WorkingDir)) {
|
|
(void) same++;
|
|
}
|
|
|
|
WorkingDirCmp = malloc((unsigned) (strlen(WorkingDir) + 2));
|
|
(void) strcpy(WorkingDirCmp, WorkingDir);
|
|
(void) strcat(WorkingDirCmp, "/");
|
|
|
|
SourceDirCmp = malloc((unsigned) (strlen(SourceDir) + 2));
|
|
(void) strcpy(SourceDirCmp, SourceDir);
|
|
(void) strcat(SourceDirCmp, "/");
|
|
|
|
WorkingLen = strlen(WorkingDirCmp);
|
|
SourceLen = strlen(SourceDirCmp);
|
|
|
|
if (DoExecute)
|
|
{
|
|
if (DoDiffs)
|
|
{
|
|
do_rm_rf(OutFile);
|
|
do_touch(OutFile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("#!/bin/sh\n");
|
|
printf("#\n# the following makes things more readeable\n\n");
|
|
printf("w='%s'\t# Working directory\n", WorkingDir);
|
|
printf("s='%s'\t# Source directory\n", SourceDir);
|
|
if (DoDiffs)
|
|
printf("rm -rf %s; touch %s\n", OutFile, OutFile);
|
|
printf("\n");
|
|
}
|
|
|
|
if (optind < argc) {
|
|
char *SubSourceDir;
|
|
char *SubWorkingDir;
|
|
|
|
for (; optind < argc; optind++) {
|
|
SubSourceDir = malloc((unsigned) (strlen(SourceDir) +
|
|
strlen(argv[optind]) + 2));
|
|
(void) sprintf(SubSourceDir, "%s/%s", SourceDir, argv[optind]);
|
|
SubWorkingDir = malloc((unsigned) (strlen(WorkingDir) +
|
|
strlen(argv[optind]) + 2));
|
|
(void) sprintf(SubWorkingDir, "%s/%s", WorkingDir, argv[optind]);
|
|
(void) GetNew(SubWorkingDir, SubSourceDir, same);
|
|
(void) free(SubWorkingDir);
|
|
(void) free(SubSourceDir);
|
|
}
|
|
} else {
|
|
(void) GetNew(WorkingDir, SourceDir, same);
|
|
}
|
|
(void) exit(0);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
void
|
|
GetNew(WorkingDir, SourceDir, same)
|
|
char *WorkingDir;
|
|
char *SourceDir;
|
|
int same;
|
|
{
|
|
FILE *f;
|
|
char *NextSourceDir;
|
|
char *NextWorkingDir;
|
|
char *RcsDir;
|
|
char *SourceFile;
|
|
char *WorkingFile;
|
|
int FreeSourceFile;
|
|
int FreeWorkingFile;
|
|
DIR *D;
|
|
#ifdef apollo
|
|
struct direct *dir;
|
|
#else
|
|
struct dirent *dir;
|
|
#endif
|
|
struct stat st;
|
|
int Tries;
|
|
char *c,*d;
|
|
char buf[BUFSIZ];
|
|
flist *WorkingHead = (flist *) 0;
|
|
flist *SourceHead = (flist *) 0;
|
|
flist *RcsHead = (flist *) 0;
|
|
flist *WorkingPtr;
|
|
flist *SourcePtr;
|
|
flist *RcsPtr;
|
|
int shouldnt_have_source;
|
|
|
|
if (Verbose)
|
|
(void) fprintf(stderr, "Scanning directory \"%s\"\n", SourceDir);
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> GetNew(\"%s\", \"%s\")\n", WorkingDir,
|
|
SourceDir);
|
|
|
|
/* set up the working directory's RCS directory name */
|
|
RcsDir = malloc((unsigned char *) strlen(WorkingDir) + strlen("/RCS") + 1);
|
|
(void) sprintf(RcsDir, "%s/RCS", WorkingDir);
|
|
if (Debug > 0)
|
|
(void) fprintf(stderr, ">> RcsDir=\"%s\"\n", RcsDir);
|
|
|
|
/* check to see if the working dir's RCS directory exists */
|
|
/* if you can't stat it and it is a symlink to nowhere, do not
|
|
* recreate the link. The cde source server works on RCS symlinks
|
|
* to nowhere.
|
|
*/
|
|
if (stat(RcsDir, &st)) {
|
|
/* if not a symlink, create the RCS directory */
|
|
if (readlink(RcsDir, buf, sizeof(buf)) < 0) {
|
|
/* no -- create one off of the SourceDir */
|
|
c = malloc((unsigned char *) strlen(SourceDir) +
|
|
strlen("/RCS") + 1);
|
|
(void) sprintf(c, "%s/RCS", SourceDir);
|
|
d = malloc((unsigned char *) strlen(SourceDir) +
|
|
strlen("/RCS") + 1);
|
|
(void) sprintf(d, "%s/RCS", SourceDir);
|
|
/* resolve out symbolic links */
|
|
c = ResolveLink(c, 1);
|
|
if (Debug > 0)
|
|
(void) fprintf(stderr, ">> RCS RcsDir=\"%s\"\n", c);
|
|
|
|
/* do we want RCS links? */
|
|
/* If Rcsdir points to a symlink, recreate the link
|
|
* even if no destination directory exists.
|
|
*/
|
|
if ((!stat(c, &st) || (readlink(d, buf, sizeof(buf)) > 0))
|
|
&& !NoRcsLinks) {
|
|
/* yes -- since the WorkingDir didn't have an /RCS directory,
|
|
** let's make one.
|
|
*/
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: creating symlink\n",
|
|
RcsDir + WorkingLen);
|
|
/* check and see if the RCS dir is in the SourceDir */
|
|
if (DoExecute)
|
|
{
|
|
do_rm_f(RcsDir);
|
|
do_ln_s(c, RcsDir);
|
|
}
|
|
else
|
|
{
|
|
/* remove the link before linking */
|
|
(void) printf("rm -f ${w}/%s\n",
|
|
RcsDir + WorkingLen);
|
|
if (strncmp(c, SourceDir, SourceLen) ||
|
|
(c[SourceLen] != '/')) {
|
|
/* need full RCS path */
|
|
(void) printf("ln -s %s ${w}/%s\n",
|
|
c, RcsDir + WorkingLen);
|
|
}
|
|
else {
|
|
/* RCS path is relative to SourceDir */
|
|
(void) printf("ln -s ${s}/%s ${w}/%s\n",
|
|
c + SourceLen, RcsDir + WorkingLen);
|
|
}
|
|
}
|
|
}
|
|
(void) free(RcsDir);
|
|
RcsDir = c;
|
|
}
|
|
}
|
|
|
|
/* resolve "fake" symbolic links to get a real directory */
|
|
for (Tries = 10; Tries > 0; Tries--) {
|
|
if (!lstat(RcsDir, &st)) {
|
|
if (S_ISLNK(st.st_mode)) {
|
|
RcsDir = ResolveLink(RcsDir, 1);
|
|
} else if (S_ISREG(st.st_mode)) {
|
|
/* open the file... */
|
|
if (f = fopen(RcsDir, "r")) {
|
|
/* read it... */
|
|
(void) fgets(Buffer, sizeof(Buffer), f);
|
|
Buffer[strlen(Buffer) - 1] = '\0';
|
|
(void) free(RcsDir);
|
|
|
|
/* RcsDir is the contents of the file... */
|
|
RcsDir = malloc((unsigned) strlen(Buffer) + 1);
|
|
(void) strcpy(RcsDir, Buffer);
|
|
if (Debug)
|
|
(void) fprintf(stderr, ">> soft link RcsDir=\"%s\"\n",
|
|
RcsDir);
|
|
|
|
/* we are done, close it... */
|
|
(void) fclose(f);
|
|
}
|
|
} else {
|
|
/* not a symlink or "soft" link */
|
|
break;
|
|
}
|
|
} else {
|
|
/* directory does not exist */
|
|
break;
|
|
}
|
|
}
|
|
if (Tries <= 0) {
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: >10 \"soft\" links\n", RcsDir);
|
|
}
|
|
|
|
/* cd to the RcsDir, and scan it */
|
|
RcsHead = (flist *) 0;
|
|
if (chdir(RcsDir)) {
|
|
if (errno != ENOENT)
|
|
(void) perror(RcsDir);
|
|
} else {
|
|
if (D = opendir(".")) {
|
|
while (dir = readdir(D)) {
|
|
/* all RCS files have a length > 2 */
|
|
#ifndef apollo
|
|
if (strlen(dir->d_name) < 3)
|
|
#else
|
|
if (dir->d_namlen < 3)
|
|
#endif
|
|
continue;
|
|
|
|
/* all RCS files have a name ending in ",v" */
|
|
#ifndef apollo
|
|
if (strcmp(dir->d_name + strlen(dir->d_name) - 2, ",v"))
|
|
#else
|
|
if (strcmp(dir->d_name + dir->d_namlen - 2, ",v"))
|
|
#endif
|
|
continue;
|
|
|
|
/* build the full name of the file */
|
|
(void) strcpy(Buffer, RcsDir);
|
|
(void) strcat(Buffer, "/");
|
|
(void) strcat(Buffer, dir->d_name);
|
|
|
|
/* stat the file */
|
|
if (stat(dir->d_name, &st)) {
|
|
(void) perror(Buffer);
|
|
continue;
|
|
}
|
|
|
|
/* Valid entry. It's time to stuff it away */
|
|
if (RcsHead) {
|
|
RcsPtr->next = (flist *) malloc(sizeof(flist));
|
|
RcsPtr = RcsPtr->next;
|
|
} else {
|
|
RcsHead = (flist *) malloc(sizeof(flist));
|
|
RcsPtr = RcsHead;
|
|
}
|
|
/* null out link */
|
|
RcsPtr->next = (flist *) 0;
|
|
|
|
/* this entry is new */
|
|
RcsPtr->used =0;
|
|
|
|
/* stuff away full path */
|
|
RcsPtr->fullname = malloc((unsigned) (strlen(Buffer) + 1));
|
|
(void) strcpy(RcsPtr->fullname, Buffer);
|
|
|
|
/* drop ",v" of dir->d_name */
|
|
/* stuff away key path */
|
|
#ifndef apollo
|
|
dir->d_name[strlen(dir->d_name) - 2] = '\0';
|
|
RcsPtr->keyname = malloc((unsigned) (strlen(dir->d_name) + 1));
|
|
(void) strcpy(RcsPtr->keyname, dir->d_name);
|
|
RcsPtr->keylen = strlen(dir->d_name);
|
|
#else
|
|
dir->d_name[dir->d_namlen - 2] = '\0';
|
|
dir->d_namlen -= 2;
|
|
RcsPtr->keyname = malloc((unsigned) (dir->d_namlen + 1));
|
|
(void) strcpy(RcsPtr->keyname, dir->d_name);
|
|
RcsPtr->keylen = dir->d_namlen;
|
|
#endif
|
|
/* stuff away stat structure */
|
|
RcsPtr->st = st;
|
|
RcsPtr->st_valid = 1;
|
|
RcsPtr->lst_valid = 0;
|
|
}
|
|
(void) closedir(D);
|
|
}
|
|
}
|
|
|
|
/* cd to the WorkingDir, and scan it */
|
|
WorkingHead = (flist *) 0;
|
|
if (chdir(WorkingDir)) {
|
|
if (errno != ENOENT)
|
|
(void) perror(WorkingDir);
|
|
} else {
|
|
if (D = opendir(".")) {
|
|
while (dir = readdir(D)) {
|
|
/* ignore "." and ".." */
|
|
#ifndef apollo
|
|
if (('.' == *(dir->d_name)) || (!strcmp(dir->d_name, "..")))
|
|
continue;
|
|
#else
|
|
if (((1 == dir->d_namlen) && ('.' == *(dir->d_name))) ||
|
|
((2 == dir->d_namlen) && !strcmp(dir->d_name, "..")))
|
|
continue;
|
|
#endif
|
|
|
|
/* build the full name of the file */
|
|
(void) strcpy(Buffer, WorkingDir);
|
|
(void) strcat(Buffer, "/");
|
|
(void) strcat(Buffer, dir->d_name);
|
|
|
|
/* stat the file */
|
|
if (stat(dir->d_name, &st)) {
|
|
/* don't send error if RCS directory is a
|
|
* symlink to nowhere.
|
|
*/
|
|
if (strcmp("RCS",dir->d_name)) {
|
|
(void) perror(Buffer);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* Valid entry. It's time to stuff it away */
|
|
if (WorkingHead) {
|
|
WorkingPtr->next = (flist *) malloc(sizeof(flist));
|
|
WorkingPtr = WorkingPtr->next;
|
|
} else {
|
|
WorkingHead = (flist *) malloc(sizeof(flist));
|
|
WorkingPtr = WorkingHead;
|
|
}
|
|
/* null out link */
|
|
WorkingPtr->next = (flist *) 0;
|
|
|
|
/* this entry is new */
|
|
WorkingPtr->used =0;
|
|
|
|
/* stuff away full path */
|
|
WorkingPtr->fullname = malloc((unsigned) (strlen(Buffer) + 1));
|
|
(void) strcpy(WorkingPtr->fullname, Buffer);
|
|
/* stuff away key path */
|
|
#ifndef apollo
|
|
WorkingPtr->keyname = malloc((unsigned) (strlen(dir->d_name) + 1));
|
|
(void) strcpy(WorkingPtr->keyname, dir->d_name);
|
|
WorkingPtr->keylen = strlen(dir->d_name);
|
|
#else
|
|
WorkingPtr->keyname = malloc((unsigned) (dir->d_namlen + 1));
|
|
(void) strcpy(WorkingPtr->keyname, dir->d_name);
|
|
WorkingPtr->keylen = dir->d_namlen;
|
|
#endif
|
|
/* stuff away stat structure */
|
|
WorkingPtr->st = st;
|
|
WorkingPtr->st_valid = 1;
|
|
if (S_ISDIR(st.st_mode) && !lstat(dir->d_name, &st))
|
|
{
|
|
WorkingPtr->lst = st;
|
|
WorkingPtr->lst_valid = 1;
|
|
}
|
|
else
|
|
WorkingPtr->lst_valid = 0;
|
|
}
|
|
(void) closedir(D);
|
|
}
|
|
}
|
|
|
|
/* cd to the SourceDir, and scan it. If the dirs are the same, we
|
|
** can just forget this part
|
|
*/
|
|
SourceHead = (flist *) 0;
|
|
if (!same) {
|
|
if (chdir(SourceDir)) {
|
|
if (errno != ENOENT)
|
|
(void) perror(SourceDir);
|
|
} else {
|
|
if (D = opendir(".")) {
|
|
while (dir = readdir(D)) {
|
|
/* ignore "." and ".." */
|
|
#ifndef apollo
|
|
if ((('.' == *(dir->d_name))) ||
|
|
(!strcmp(dir->d_name, "..")))
|
|
continue;
|
|
#else
|
|
if (((1 == dir->d_namlen) && ('.' == *(dir->d_name))) ||
|
|
((2 == dir->d_namlen) &&
|
|
!strcmp(dir->d_name, "..")))
|
|
continue;
|
|
#endif
|
|
|
|
/* build the full name of the file */
|
|
(void) strcpy(Buffer, SourceDir);
|
|
(void) strcat(Buffer, "/");
|
|
(void) strcat(Buffer, dir->d_name);
|
|
|
|
/* lstat the file */
|
|
if (lstat(dir->d_name, &st)) {
|
|
(void) perror(Buffer);
|
|
continue;
|
|
}
|
|
|
|
|
|
/* Valid entry. It's time to stuff it away */
|
|
if (SourceHead) {
|
|
SourcePtr->next = (flist *) malloc(sizeof(flist));
|
|
SourcePtr = SourcePtr->next;
|
|
} else {
|
|
SourceHead = (flist *) malloc(sizeof(flist));
|
|
SourcePtr = SourceHead;
|
|
}
|
|
/* null out link */
|
|
SourcePtr->next = (flist *) 0;
|
|
|
|
/* this entry is new */
|
|
SourcePtr->used =0;
|
|
|
|
/* stuff away full path */
|
|
SourcePtr->fullname =
|
|
malloc((unsigned) (strlen(Buffer) + 1));
|
|
(void) strcpy(SourcePtr->fullname, Buffer);
|
|
/* stuff away key path */
|
|
#ifndef apollo
|
|
SourcePtr->keyname = malloc((unsigned) (strlen(dir->d_name) + 1));
|
|
(void) strcpy(SourcePtr->keyname, dir->d_name);
|
|
SourcePtr->keylen = strlen(dir->d_name);
|
|
#else
|
|
SourcePtr->keyname = malloc((unsigned) (dir->d_namlen + 1));
|
|
(void) strcpy(SourcePtr->keyname, dir->d_name);
|
|
SourcePtr->keylen = dir->d_namlen;
|
|
#endif
|
|
/* stuff away lstat structure */
|
|
SourcePtr->lst = st;
|
|
SourcePtr->lst_valid = 1;
|
|
/* was it a symbolic link? */
|
|
if (S_ISLNK(st.st_mode)) {
|
|
/* do a plain stat on it */
|
|
(void) stat(dir->d_name, &st);
|
|
}
|
|
/* stuff it away */
|
|
SourcePtr->st = st;
|
|
SourcePtr->st_valid = 1;
|
|
}
|
|
(void) closedir(D);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** PASS 1:
|
|
**
|
|
** Check all the files in the working dir.
|
|
*/
|
|
if (Debug)
|
|
(void) fprintf(stderr, ">> Pass 1: scanning WorkingDir \"%s\"\n",
|
|
WorkingDir);
|
|
for (WorkingPtr = WorkingHead; WorkingPtr; WorkingPtr = WorkingPtr->next) {
|
|
/* initialize */
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> keyname=\"%s\", fullname=\"%s\"\n",
|
|
WorkingPtr->keyname, WorkingPtr->fullname);
|
|
shouldnt_have_source = 0;
|
|
|
|
/* ignore .o and .a files */
|
|
c = WorkingPtr->keyname + WorkingPtr->keylen - 2;
|
|
if (WorkingPtr->keylen >= 2) {
|
|
if (!strcmp(c, ".o")) {
|
|
(void) shouldnt_have_source++;
|
|
if (!CloneDotO) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> .o -- ignored\n");
|
|
continue;
|
|
}
|
|
}
|
|
if (!strcmp(c, ".a")) {
|
|
(void) shouldnt_have_source++;
|
|
if (!CloneDotA) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> .a -- ignored\n");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!strncmp(WorkingPtr->keyname, Makefile, strlen(Makefile))) {
|
|
(void) shouldnt_have_source++;
|
|
if (!CloneMakefile) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> Makefile* -- ignored\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* ignore RCS as well */
|
|
if (!strcmp(WorkingPtr->keyname, "RCS")) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> RCS -- ignored\n");
|
|
continue;
|
|
}
|
|
|
|
/* ignore SCCS as well */
|
|
if (!(ProcessSCCSdirs)) {
|
|
if (!strcmp(WorkingPtr->keyname, "SCCS")) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> SCCS -- ignored\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* ignore regular files with x mode */
|
|
if (!CloneExecutables && WorkingPtr->st_valid &&
|
|
(S_ISREG(WorkingPtr->st.st_mode)) &&
|
|
(0111 == (WorkingPtr->st.st_mode & 0111))) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> executable -- ignored\n");
|
|
continue;
|
|
}
|
|
|
|
/* find corresponding sourcefile */
|
|
for (SourcePtr = SourceHead; SourcePtr; SourcePtr = SourcePtr->next) {
|
|
if ((WorkingPtr->keylen == SourcePtr->keylen) &&
|
|
!strcmp(WorkingPtr->keyname, SourcePtr->keyname)) {
|
|
/* mark it as used */
|
|
(void) SourcePtr->used++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Debug > 1)
|
|
if (SourcePtr)
|
|
(void) fprintf(stderr,
|
|
" source: keyname=\"%s\" fullname=\"%s\"\n",
|
|
SourcePtr->keyname, SourcePtr->fullname);
|
|
else
|
|
(void) fprintf(stderr, " no source file\n");
|
|
|
|
/* is the working file actually a directory? */
|
|
if (WorkingPtr->st_valid &&
|
|
(S_ISDIR(WorkingPtr->st.st_mode))) {
|
|
/* yes, go recursive... */
|
|
if (FollowDirLinks ||
|
|
!WorkingPtr->lst_valid ||
|
|
!S_ISLNK(WorkingPtr->lst.st_mode))
|
|
{
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> directory\n");
|
|
(void) GetNew(WorkingPtr->fullname,
|
|
SourcePtr ? SourcePtr->fullname : WorkingPtr->fullname,
|
|
same);
|
|
}
|
|
} else {
|
|
/* find corresponding RCS file */
|
|
for (RcsPtr = RcsHead; RcsPtr; RcsPtr = RcsPtr->next) {
|
|
if ((WorkingPtr->keylen == RcsPtr->keylen) &&
|
|
!strcmp(WorkingPtr->keyname, RcsPtr->keyname)) {
|
|
/* mark it as used */
|
|
(void) RcsPtr->used++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Debug > 1)
|
|
if (RcsPtr)
|
|
(void) fprintf(stderr,
|
|
" rcs: keyname=\"%s\" fullname=\"%s\"\n",
|
|
RcsPtr->keyname, RcsPtr->fullname);
|
|
else
|
|
(void) fprintf(stderr, " no rcs file\n");
|
|
|
|
/* print a message if there is no corresponding source */
|
|
if (!RcsPtr && !SourcePtr) {
|
|
/* don't print a message for .snf files */
|
|
if ((WorkingPtr->keylen > 4) && !strcmp(WorkingPtr->keyname +
|
|
WorkingPtr->keylen - 4, ".snf"))
|
|
(void) shouldnt_have_source++;
|
|
|
|
if (Verbose && !shouldnt_have_source)
|
|
(void) fprintf(stderr, "%s: no source or RCS file\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
}
|
|
|
|
if (!RcsPtr || !RcsPtr->st_valid ||
|
|
(SourcePtr &&
|
|
(SourcePtr->st.st_mtime >= RcsPtr->st.st_mtime)) ||
|
|
(SourcePriority && SourcePtr)) {
|
|
/* no RCS file, or source newer than RCS, or source
|
|
** exists and has priority
|
|
*/
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> source newer than rcs\n");
|
|
if (SourcePtr &&
|
|
(WorkingPtr->st.st_mtime < SourcePtr->st.st_mtime)) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr,
|
|
">> source newer than working\n");
|
|
/* does the WorkingFile have any write mode bits
|
|
** set?
|
|
*/
|
|
if (WorkingPtr->st.st_mode & 0222) {
|
|
if (!Quiet)
|
|
(void) fprintf(stderr,
|
|
"%s: writable -- not updated\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
continue;
|
|
}
|
|
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: newer file\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
|
|
|
|
/* check to see if file symlinks should resolve */
|
|
if (ResolveFileLinks)
|
|
if (SourcePtr->lst_valid &&
|
|
S_ISLNK(SourcePtr->lst.st_mode)) {
|
|
SourceFile = ResolveLink(SourcePtr->fullname, 0);
|
|
FreeSourceFile = 1;
|
|
}
|
|
else {
|
|
SourceFile = SourcePtr->fullname;
|
|
}
|
|
else {
|
|
SourceFile = SourcePtr->fullname;
|
|
}
|
|
|
|
/* do we need to do a diff? */
|
|
if (DoDiffs) {
|
|
if (DoExecute)
|
|
{
|
|
do_diff(NULL,
|
|
DiffCommand,
|
|
WorkingPtr->fullname,
|
|
SourceFile,
|
|
OutFile);
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(SourceFile, SourceDirCmp, SourceLen))
|
|
/* not in SourceDir... */
|
|
(void) printf("%s ${w}/%s %s >>%s 2>&1\n",
|
|
DiffCommand,
|
|
WorkingPtr->fullname + WorkingLen,
|
|
SourceFile, OutFile);
|
|
else
|
|
/* in SourceDir... */
|
|
(void) printf("%s ${w}/%s ${s}/%s >>%s 2>&1\n",
|
|
DiffCommand,
|
|
WorkingPtr->fullname + WorkingLen,
|
|
SourceFile + SourceLen, OutFile);
|
|
}
|
|
}
|
|
if (DoExecute)
|
|
{
|
|
do_rm_f(WorkingPtr->fullname);
|
|
if (LinkFiles)
|
|
do_ln_s(SourceFile, WorkingPtr->fullname);
|
|
else
|
|
do_cp(SourceFile, WorkingPtr->fullname);
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(SourceFile, SourceDirCmp, SourceLen)) {
|
|
/* not in SourceDir... */
|
|
(void) printf("rm -f ${w}/%s\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
(void) printf("\t%s %s ${w}/%s\n",
|
|
LinkFiles ? "ln -s" : "cp",
|
|
SourceFile,
|
|
WorkingPtr->fullname + WorkingLen);
|
|
} else {
|
|
/* in SourceDir... */
|
|
(void) printf("rm -f ${w}/%s\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
(void) printf("\t%s ${s}/%s ${w}/%s\n",
|
|
LinkFiles ? "ln -s" : "cp",
|
|
SourceFile + SourceLen,
|
|
WorkingPtr->fullname + WorkingLen);
|
|
}
|
|
}
|
|
if (!LinkFiles)
|
|
{
|
|
/* don't chmod the file if we did a link... */
|
|
|
|
if (DoExecute)
|
|
{
|
|
do_chmod(WorkingPtr->fullname,
|
|
(SourcePtr->st.st_mode & 07777 & ~0222) | 0444);
|
|
}
|
|
else
|
|
(void) printf("\tchmod 0%03o ${w}/%s\n",
|
|
(SourcePtr->st.st_mode & 07777 & ~0222) | 0444,
|
|
WorkingPtr->fullname + WorkingLen);
|
|
}
|
|
if (FreeSourceFile)
|
|
(void) free(SourceFile);
|
|
} else {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr,
|
|
">> source older than working\n");
|
|
}
|
|
} else {
|
|
/* RCS file is the newest */
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> rcs newer than source\n");
|
|
if (RcsPtr && (WorkingPtr->st.st_mtime < RcsPtr->st.st_mtime)) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr,
|
|
">> rcs newer than working\n");
|
|
/* does the WorkingFile have any write mode bits
|
|
** set?
|
|
*/
|
|
if (WorkingPtr->st.st_mode & 0222) {
|
|
if (!Quiet)
|
|
(void) fprintf(stderr,
|
|
"%s: writable -- not updated\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
continue;
|
|
}
|
|
|
|
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: newer RCS file\n",
|
|
WorkingPtr->fullname + WorkingLen);
|
|
if (DoExecute)
|
|
{
|
|
do_diff(RcsDir, DiffCommand,
|
|
RcsPtr->keyname,
|
|
WorkingPtr->fullname,
|
|
OutFile);
|
|
if (! NoRealFiles)
|
|
{
|
|
do_co_q(RcsDir, WorkingPtr->fullname);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(RcsDir, SourceDir, SourceLen) ||
|
|
(RcsDir[SourceLen] != '/')) {
|
|
/* RcsDir is not in SourceDir */
|
|
|
|
if (DoDiffs) {
|
|
/* diff the file */
|
|
(void) printf("\t (cd %s; %s %s ${w}/%s >>%s 2>&1)\n",
|
|
RcsDir,
|
|
DiffCommand,
|
|
RcsPtr->keyname,
|
|
WorkingPtr->fullname + WorkingLen,
|
|
OutFile);
|
|
}
|
|
if (! NoRealFiles)
|
|
{
|
|
/* check out the file */
|
|
(void) printf("(cd %s; co -q ${w}/%s) \n",
|
|
RcsDir, WorkingPtr->fullname + WorkingLen);
|
|
}
|
|
|
|
} else {
|
|
/* RcsDir is in SourceDir */
|
|
|
|
if (DoDiffs) {
|
|
/* diff the file */
|
|
(void) printf("\t (cd ${s}/%s; %s %s ${w}/%s >>%s 2>&1)\n",
|
|
RcsDir + SourceLen,
|
|
DiffCommand,
|
|
RcsPtr->keyname,
|
|
WorkingPtr->fullname + WorkingLen,
|
|
OutFile);
|
|
}
|
|
|
|
if (! NoRealFiles)
|
|
{
|
|
/* check out the file */
|
|
(void) printf("(cd ${s}/%s; co -q ${w}/%s) \n",
|
|
RcsDir + SourceLen, WorkingPtr->fullname + WorkingLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr,
|
|
">> source older than working\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** PASS 2:
|
|
** Check all the files in the source (checked out) dir.
|
|
*/
|
|
if (Debug)
|
|
(void) fprintf(stderr, ">> Pass 2: scanning SourceDir \"%s\"\n",
|
|
SourceDir);
|
|
for (SourcePtr = SourceHead; SourcePtr; SourcePtr = SourcePtr->next) {
|
|
/* did we get this one already? */
|
|
if (SourcePtr->used)
|
|
continue;
|
|
|
|
/* ignore "RCS" */
|
|
if (!strcmp(SourcePtr->keyname, "RCS"))
|
|
continue;
|
|
|
|
/* ignore SCCS as well */
|
|
if (!(ProcessSCCSdirs)) {
|
|
if (!strcmp(SourcePtr->keyname, "SCCS")) {
|
|
if (Debug > 1)
|
|
(void) fprintf(stderr, ">> SCCS -- ignored\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* find corresponding RCS file */
|
|
for (RcsPtr = RcsHead; RcsPtr; RcsPtr = RcsPtr->next) {
|
|
if ((SourcePtr->keylen == RcsPtr->keylen) &&
|
|
!strcmp(SourcePtr->keyname, RcsPtr->keyname)) {
|
|
/* mark it as used */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* which one do we use, RCS or source? */
|
|
if (RcsPtr) {
|
|
if (!SourcePriority &&
|
|
(SourcePtr->st.st_mtime < RcsPtr->st.st_mtime)) {
|
|
/* we'll catch this on pass 3 */
|
|
continue;
|
|
} else {
|
|
/* mark the RCS file as used */
|
|
(void) RcsPtr->used++;
|
|
}
|
|
}
|
|
|
|
/* ignore .o and .a files */
|
|
c = SourcePtr->keyname + SourcePtr->keylen - 2;
|
|
if (SourcePtr->keylen >= 2) {
|
|
if (!strcmp(c, ".o")) {
|
|
(void) shouldnt_have_source++;
|
|
if (!CloneDotO)
|
|
continue;
|
|
}
|
|
if (!strcmp(c, ".a")) {
|
|
(void) shouldnt_have_source++;
|
|
if (!CloneDotA)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* the files might be Makefile's */
|
|
if (!CloneMakefile && !strncmp(SourcePtr->keyname, Makefile,
|
|
strlen(Makefile)))
|
|
continue;
|
|
|
|
WorkingFile = malloc((unsigned) strlen(WorkingDir) +
|
|
SourcePtr->keylen + 2);
|
|
(void) strcpy(WorkingFile, WorkingDir);
|
|
(void) strcat(WorkingFile, "/");
|
|
(void) strcat(WorkingFile, SourcePtr->keyname);
|
|
|
|
if (S_ISDIR(SourcePtr->st.st_mode)) {
|
|
/* check for directories present in the source tree,
|
|
** but not in this tree. Don't bother if the SourceDir
|
|
** is the same as WorkingDir. If the directory exists
|
|
** in the working tree, we already set the used flag
|
|
** and never got here in the first place.
|
|
*/
|
|
if (!same) {
|
|
if (MakeDirs) {
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: building directory\n",
|
|
WorkingFile + WorkingLen);
|
|
if (!FollowDirLinks &&
|
|
SourcePtr->lst_valid &&
|
|
S_ISLNK(SourcePtr->lst.st_mode))
|
|
{
|
|
|
|
/* check to see if file symlinks should resolve */
|
|
if (ResolveFileLinks)
|
|
SourceFile = ResolveLink(SourcePtr->fullname, 0);
|
|
else
|
|
SourceFile = SourcePtr->fullname;
|
|
|
|
if (DoExecute)
|
|
do_ln_s(SourceFile, WorkingFile);
|
|
else
|
|
{
|
|
if (strncmp(SourceFile, SourceDir, SourceLen))
|
|
(void) printf("ln -s %s ${w}/%s\n",
|
|
SourceFile,
|
|
WorkingFile + WorkingLen);
|
|
else
|
|
(void) printf("ln -s ${s}/%s ${w}/%s\n",
|
|
SourceFile + SourceLen,
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
free(SourceFile);
|
|
}
|
|
else
|
|
{
|
|
if (DoExecute)
|
|
{
|
|
do_rm_rf(WorkingFile);
|
|
do_mkdir(WorkingFile);
|
|
do_chmod(WorkingFile, 0755);
|
|
/* bad for other architectures */
|
|
/* do_chgrp(WorkingFile, "users"); */
|
|
}
|
|
else
|
|
{
|
|
(void) printf("rm -rf ${w}/%s\n",
|
|
WorkingFile + WorkingLen);
|
|
(void) printf("\tmkdir ${w}/%s\n",
|
|
WorkingFile + WorkingLen);
|
|
(void) printf("\tchmod 0755 ${w}/%s\n",
|
|
WorkingFile + WorkingLen);
|
|
/* bad for other architectures */
|
|
/*(void) printf("\tchgrp users ${w}/%s\n",
|
|
WorkingFile + WorkingLen); */
|
|
}
|
|
(void) GetNew(WorkingFile, SourcePtr->fullname, same);
|
|
}
|
|
|
|
} else {
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: missing directory\n",
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
}
|
|
} else {
|
|
/* regular file (probably)... */
|
|
/* check to see if file symlinks should resolve */
|
|
if (ResolveFileLinks)
|
|
if (SourcePtr->lst_valid && S_ISLNK(SourcePtr->lst.st_mode)) {
|
|
SourceFile = ResolveLink(SourcePtr->fullname, 0);
|
|
FreeSourceFile = 1;
|
|
}
|
|
else {
|
|
SourceFile = SourcePtr->fullname;
|
|
FreeSourceFile = 0;
|
|
}
|
|
else {
|
|
SourceFile = SourcePtr->fullname;
|
|
FreeSourceFile = 0;
|
|
}
|
|
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: new file\n",
|
|
WorkingFile + WorkingLen);
|
|
if (DoExecute)
|
|
{
|
|
if (LinkFiles)
|
|
do_ln_s(SourceFile, WorkingFile);
|
|
else
|
|
do_cp(SourceFile, WorkingFile);
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(SourceFile, SourceDir, SourceLen)) {
|
|
(void) printf("%s %s ${w}/%s\n",
|
|
LinkFiles ? "ln -s" : "cp",
|
|
SourceFile,
|
|
WorkingFile + WorkingLen);
|
|
} else {
|
|
(void) printf("%s ${s}/%s ${w}/%s\n",
|
|
LinkFiles ? "ln -s" : "cp",
|
|
SourceFile + SourceLen,
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
}
|
|
if (!LinkFiles)
|
|
{
|
|
if (DoExecute)
|
|
do_chmod(WorkingFile,
|
|
(SourcePtr->st.st_mode & 07777 & ~0222) | 0444);
|
|
else
|
|
(void) printf("\tchmod 0%03o ${w}/%s\n",
|
|
(SourcePtr->st.st_mode & 07777 & ~0222) | 0444,
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
if (FreeSourceFile)
|
|
(void) free(SourceFile);
|
|
}
|
|
(void) free(WorkingFile);
|
|
}
|
|
|
|
/*
|
|
** PASS 3:
|
|
**
|
|
** Check all the files in the RCS dir.
|
|
*/
|
|
if (Debug)
|
|
(void) fprintf(stderr, ">> scanning RcsDir \"%s\"\n", RcsDir);
|
|
for (RcsPtr = RcsHead; RcsPtr; RcsPtr = RcsPtr->next) {
|
|
/* did we get this one already? */
|
|
if (RcsPtr->used)
|
|
continue;
|
|
|
|
/* build the WorkingFile */
|
|
WorkingFile = malloc((unsigned) strlen(WorkingDir) +
|
|
RcsPtr->keylen + 2);
|
|
(void) strcpy(WorkingFile, WorkingDir);
|
|
(void) strcat(WorkingFile, "/");
|
|
(void) strcat(WorkingFile, RcsPtr->keyname);
|
|
|
|
/* New RCS file */
|
|
if (!Quiet)
|
|
(void) fprintf(stderr, "%s: new RCS file\n",
|
|
WorkingFile + WorkingLen);
|
|
if (DoExecute)
|
|
{
|
|
if (! NoRealFiles)
|
|
{
|
|
do_co_q(RcsDir, WorkingFile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(RcsDir, SourceDir, SourceLen) ||
|
|
(RcsDir[SourceLen] != '/')) {
|
|
/* RcsDir is not in SourceDir */
|
|
if (! NoRealFiles)
|
|
{
|
|
/* check it out... */
|
|
(void) printf("(cd %s; co -q ${w}/%s)\n",
|
|
RcsDir,
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
} else {
|
|
/* RcsDir is in SourceDir */
|
|
if (! NoRealFiles)
|
|
{
|
|
/* check it out... */
|
|
(void) printf("(cd %s; co -q ${w}/%s)\n",
|
|
RcsDir + SourceLen,
|
|
WorkingFile + WorkingLen);
|
|
}
|
|
}
|
|
}
|
|
(void) free(WorkingFile);
|
|
}
|
|
|
|
/* free storage */
|
|
while (WorkingHead) {
|
|
WorkingPtr = WorkingHead;
|
|
WorkingHead = WorkingPtr->next;
|
|
(void) free(WorkingPtr->fullname);
|
|
(void) free(WorkingPtr->keyname);
|
|
(void) free((char *) WorkingPtr);
|
|
}
|
|
while (SourceHead) {
|
|
SourcePtr = SourceHead;
|
|
SourceHead = SourcePtr->next;
|
|
(void) free(SourcePtr->fullname);
|
|
(void) free(SourcePtr->keyname);
|
|
(void) free((char *) SourcePtr);
|
|
}
|
|
while (RcsHead) {
|
|
RcsPtr = RcsHead;
|
|
RcsHead = RcsPtr->next;
|
|
(void) free(RcsPtr->fullname);
|
|
(void) free(RcsPtr->keyname);
|
|
(void) free((char *) RcsPtr);
|
|
}
|
|
|
|
(void) free(RcsDir);
|
|
return;
|
|
}
|
|
|
|
char
|
|
*ResolveLink(filename, freeit)
|
|
char *filename;
|
|
int freeit;
|
|
{
|
|
int len;
|
|
int try;
|
|
char *c;
|
|
char *tname;
|
|
|
|
tname = filename;
|
|
|
|
if (Debug) {
|
|
(void) fprintf(stderr, "ResolveLink %s->", tname);
|
|
(void) fflush(stderr);
|
|
}
|
|
for (try = 0; try < 10; try++) {
|
|
if ((len = readlink(tname, Buffer, sizeof(Buffer))) < 0) {
|
|
break;
|
|
} else {
|
|
Buffer[len] = '\0';
|
|
if ('/' != *Buffer) {
|
|
if (c = strrchr(tname, '/')) {
|
|
*c = '\0';
|
|
c = malloc((unsigned) (strlen(tname) +
|
|
strlen(Buffer) + 2));
|
|
(void) sprintf(c, "%s/%s", tname, Buffer);
|
|
} else {
|
|
c = malloc((unsigned) (strlen(Buffer) + 1));
|
|
(void) strcpy(c, Buffer);
|
|
}
|
|
} else {
|
|
c = malloc((unsigned) (strlen(Buffer) + 1));
|
|
(void) strcpy(c, Buffer);
|
|
}
|
|
if (freeit++)
|
|
(void) free(tname);
|
|
tname = c;
|
|
}
|
|
}
|
|
if (!freeit) {
|
|
c = malloc((unsigned) (strlen(tname) + 1));
|
|
(void) strcpy(c, tname);
|
|
tname = c;
|
|
}
|
|
if (Debug) {
|
|
(void) fprintf(stderr, "%s\n", tname);
|
|
(void) fflush(stderr);
|
|
}
|
|
return(tname);
|
|
}
|
|
|
|
/* New code for -X option */
|
|
|
|
static void do_rm_rf(target)
|
|
char *target;
|
|
{
|
|
char *malloc(), *temp;
|
|
struct stat buf;
|
|
if (lstat(target, &buf) != -1)
|
|
{
|
|
if (S_ISDIR(buf.st_mode))
|
|
{
|
|
DIR *thisdir;
|
|
#ifdef apollo
|
|
struct direct *thisent;
|
|
#else
|
|
struct dirent *thisent;
|
|
#endif
|
|
thisdir = opendir(target);
|
|
if (thisdir != NULL)
|
|
{
|
|
while (thisent = readdir(thisdir))
|
|
{
|
|
if (strcmp(thisent->d_name, ".") &&
|
|
strcmp(thisent->d_name, ".."))
|
|
{
|
|
temp = malloc(strlen(target) +
|
|
strlen(thisent->d_name) + 2);
|
|
if (temp != NULL)
|
|
{
|
|
(void)strcpy(temp, target);
|
|
(void)strcat(temp, "/");
|
|
(void)strcat(temp, thisent->d_name);
|
|
do_rm_rf(temp);
|
|
free(temp);
|
|
}
|
|
}
|
|
}
|
|
closedir(thisdir);
|
|
(void)rmdir(target);
|
|
}
|
|
}
|
|
else
|
|
(void)unlink(target);
|
|
}
|
|
}
|
|
|
|
static void do_touch(filename)
|
|
char *filename;
|
|
{
|
|
#ifdef apollo
|
|
struct timeval tvp[2];
|
|
struct timezone tzp;
|
|
gettimeofday(tvp, &tzp);
|
|
tvp[1] = tvp[0];
|
|
if (utimes(filename, tvp) == -1 &&
|
|
errno == ENOENT)
|
|
#else
|
|
if (utime(filename, (struct utimbuf *)NULL) == -1 &&
|
|
errno == ENOENT)
|
|
#endif
|
|
(void)creat(filename, 0777);
|
|
}
|
|
|
|
static void do_ln_s(src, dest)
|
|
char *src, *dest;
|
|
{
|
|
if (symlink(src, dest) == -1)
|
|
perror(dest);
|
|
}
|
|
|
|
static void do_diff(dirname, diffcmd, file1, file2, outfile)
|
|
char *dirname, *diffcmd, *file1, *file2, *outfile;
|
|
{
|
|
pid_t pid, res, fork();
|
|
|
|
pid = fork();
|
|
|
|
if (pid == -1)
|
|
perror("fork() failed");
|
|
else
|
|
{
|
|
if (pid == 0)
|
|
{
|
|
if (dirname != NULL && chdir(dirname) == -1)
|
|
perror("dirname");
|
|
else
|
|
{
|
|
int des;
|
|
des = open(outfile, O_WRONLY | O_APPEND | O_CREAT, 0777);
|
|
if (des == -1)
|
|
{
|
|
perror(outfile);
|
|
exit(1);
|
|
}
|
|
(void)dup2(des, fileno(stdout));
|
|
(void)dup2(des, fileno(stderr));
|
|
execlp(diffcmd, diffcmd, file1, file2, NULL);
|
|
perror(diffcmd);
|
|
}
|
|
exit(1);
|
|
}
|
|
while ((res = wait(NULL)) != pid && res != -1);
|
|
}
|
|
}
|
|
|
|
static void do_rm_f(target)
|
|
char *target;
|
|
{
|
|
struct stat buf;
|
|
if (lstat(target, &buf) != -1 &&
|
|
!(S_ISDIR(buf.st_mode)))
|
|
(void)unlink(target);
|
|
}
|
|
|
|
static void do_cp(src, dest)
|
|
char *src, *dest;
|
|
{
|
|
int res1, res2, fd1, fd2;
|
|
char buf[BUFSIZ];
|
|
|
|
fd1 = open(src, O_RDONLY);
|
|
if (fd1 == -1)
|
|
{
|
|
perror(src);
|
|
return;
|
|
}
|
|
fd2 = open(dest, O_WRONLY | O_CREAT, 0777);
|
|
if (fd2 == -1)
|
|
{
|
|
perror(dest);
|
|
close(fd1);
|
|
return;
|
|
}
|
|
|
|
while ((res1 = read(fd1, buf, BUFSIZ)) > 0)
|
|
{
|
|
while ((res2 = write(fd2, buf, res1)) > 0 && (res1 -= res2));
|
|
if (res2 == -1) break;
|
|
}
|
|
|
|
if (res1 == -1)
|
|
perror(src);
|
|
else if (res2 == -1)
|
|
perror(dest);
|
|
|
|
close(fd1);
|
|
close(fd2);
|
|
}
|
|
|
|
static void do_chmod(filename, newmode)
|
|
char *filename;
|
|
int newmode;
|
|
{
|
|
if (chmod(filename, newmode) == -1)
|
|
perror(filename);
|
|
}
|
|
|
|
static void do_co_q(dirname, targetname)
|
|
char *dirname, *targetname;
|
|
{
|
|
pid_t pid, res, fork();
|
|
|
|
pid = fork();
|
|
|
|
if (pid == -1)
|
|
perror("fork() failed");
|
|
else
|
|
{
|
|
if (pid == 0)
|
|
{
|
|
if (chdir(dirname) == -1)
|
|
perror("dirname");
|
|
else
|
|
{
|
|
execlp("co", "co", "-q", targetname, NULL);
|
|
perror("failed to exec co(1)");
|
|
}
|
|
exit(1);
|
|
}
|
|
while ((res = wait(NULL)) != pid && res != -1);
|
|
}
|
|
}
|
|
|
|
static void do_mkdir(dirname)
|
|
char *dirname;
|
|
{
|
|
if (mkdir(dirname, 0777) == -1)
|
|
perror(dirname);
|
|
}
|
|
|
|
static void do_chgrp(filename, newgroup)
|
|
char *filename, *newgroup;
|
|
{
|
|
struct group *group, *getgrnam();
|
|
group = getgrnam(newgroup);
|
|
if (group == NULL)
|
|
fprintf(stderr, "%s: no such group\n", newgroup);
|
|
else
|
|
chown(filename, UID_NO_CHANGE, group->gr_gid);
|
|
}
|