/* * Copyright (c) 1992, Brian Berliner and Jeff Polk * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License * as specified in the README file that comes with the CVS 1.3 kit. */ #include "cvs.h" /* rcvs: */ #include "rcvs.h" #include "patchlevel.h" #if __STDC__ char *rcvs_get_repos (char *dir, char **Id, char **Repository); #else char *rcvs_get_repos (); #endif /* __STDC__ */ /* * insert item p at end of list "list", do not hash */ int rcvs_addnode (list, p) List *list; Node *p; { int hashval; Node *q; /* put it into the regular list */ p->prev = list->list->prev; p->next = list->list; list->list->prev->next = p; list->list->prev = p; return (0); } /* rcvs: add all folders under one directory to list */ int rcvs_add_onedir(argc, argv, p) int argc; char *argv[]; Node *p; { char *ID; char *repos; char *Repository; char *dir = p->key; repos = rcvs_get_repos (dir, &ID, &Repository); rcvs_put_options (argc, argv, ID); if (repos != NULL) rcvs_addlist (&rcvs_dirlist, ID, dir, repos ); else error (0, 0, "rcvs_add_dir: warnig: repos is NULL"); return (0); } /* * rcvs: Add a node to a list, then initialize a sub-list with the data * field. The 'key' of a node holds the original arguments of cvs while * the data field of a node holds the relative path needed by sync. */ int rcvs_addlist (listp, lkey, pkey, pdata) List **listp; char *lkey; char *pkey; char *pdata; { Node *p; Node *P; List *L; if (trace) { char *cp; char *cp2; cp = pkey; if (cp == NULL) cp = xstrdup (""); cp2 = pdata; if (cp2 == NULL) cp2 = xstrdup (""); fprintf (stderr, "-> #addlist: %s %s (%s)\n", lkey, cp, cp2); } if (*listp == NULL) *listp = getlist (); if (pdata == NULL) error(1, 0, "rcvs_addlist: bug#1 pdata == NULL"); /* rcvs: search this list first */ if (lkey == NULL) error(1, 0, "rcvs_addlist bug #1: lkey == NULL"); P = findnode(*listp, lkey); /* rcvs: add server node to list */ if (P == NULL) { P = getnode (); P->type = DIRS; P->key = xstrdup (lkey); (void) addnode (*listp, P); L = getlist (); } else L = (void *) P->data; p = getnode (); p->type = FILES; p->key = xstrdup (pkey); p->data = xstrdup (pdata); (void) rcvs_addnode (L, p); /* store address of list into data field */ P->data = (void *) L; return (0); } /* figure out old CVSROOT from new CVSROOT and old repository. * This routine is needed when '-C' or '-c' was used to change * repository. */ int rcvs_change_cvsroot (old_repos, newroot, oldroot, relpath) char *old_repos; char *newroot; char **oldroot; char **relpath; { char oldROOT [PATH_MAX]; char tmp [PATH_MAX]; char *cp; char *rel; int found = FALSE; (void) strcpy (oldROOT, old_repos); rel = old_repos + strlen(old_repos); cp = oldROOT; while (cp) { cp = rindex ( oldROOT, '/'); if (cp) rel -= strlen(cp); else break; sprintf (tmp, "%s%s", newroot, rel); if (isdir (tmp)) found = TRUE; else if (found) break; *cp = '\0'; } if (!found) { command_name = xstrdup ("rcvs_change_cvsroot"); error (0, 0, "problem with new %s '%s'", CVSROOT_ENV, newroot); error (1, 0, "old repository: %s", old_repos); } if (trace) fprintf (stderr, "-> oldroot=%s \n", oldROOT); *oldroot = xstrdup(oldROOT); *relpath = old_repos + strlen(oldROOT) +1; return (0); } /* rcvs: recreate Admin file for '-C' or '-c' option. Called by * update_dirent_proc(). Calls Create_Admin(). */ int rcvs_remake_adm (dir, repository) char *dir; char *repository; { char tmp[PATH_MAX]; char new_repos[PATH_MAX]; char *oldroot = NULL; char *relpath = NULL; if (trace) fprintf (stderr, "-> #rcvs_remake_adm: %s %s\n", dir, repository); if (strcmp (command_name, "update") == 0) /* update */ { char *repos; char *ID; rcvs_module = rcvs_get_repos (dir, &ID, &repos); if (ID == NULL) error (1, 0, "rcvs_remake_adm, bug: ID==NULL"); if (index(ID, ':') == NULL) { if (rcvs_Copt_change_repos) { command_name = xstrdup ("rcvs_remake_adm"); error (1, 0, "%s is a local folder, use -c", dir); } } else { if (rcvs_copt_change_repos) { command_name = xstrdup ("rcvs_remake_adm"); error (1, 0, "%s is a remote folder, use -C", dir); } } repos = Name_Repository (dir,""); (void) rcvs_change_cvsroot (repos, CVSroot, &oldroot, &relpath); sprintf (new_repos, "%s/%s", CVSroot, relpath); } else /* checkout */ (void) strcpy (new_repos, repository); if (!quiet) { if (dir != NULL) (void) sprintf (tmp, "%s/%s", dir, CVSADM); else (void) strcpy (tmp, CVSADM); if (isfile (tmp)) fprintf (stderr, "remake %s/%s !!\n", dir, CVSADM); } if (trace) fprintf (stderr, "-> %s: dir=%s new_repos=%s \n", command_name, dir, new_repos); /*sprintf (tmp, "rm -r -f %s/%s", dir, CVSADM); (void) system (tmp);*/ Create_Admin (dir, new_repos, (char *) NULL, (char *) NULL); return (0); } /* rcvs: create Remote Admin file, called by Create_Admin */ int rcvs_create_adm (dir, repos) char *dir; char *repos; { static char *rcvs_source = NULL; static char *rel_path = NULL; FILE *fout; char *repository; char tmp[PATH_MAX]; char path[PATH_MAX]; char *Command_Name; char *command; Command_Name = command_name; command = xstrdup ("rcvs_create_adm"); command_name = command; rel_path = NULL; if (strcmp(repos,"") == 0) repository = Name_Repository (dir,""); else repository = repos; if (!isdir (repository)) error (1, 0, "there is no repository '%s'", repository); /* recording original source */ if (rcvs_level++ == 0) { (void) sprintf (tmp, "%s/", CVSroot); if (strncmp (repository, tmp, strlen (tmp)) == 0) rcvs_source = xstrdup (repository); else error (1, 0, "'%s' does not prefixed with CVSROOT %s", repository, CVSroot); if (rcvs_module != NULL) rel_path = rcvs_module; rcvs_module = NULL; } /* derive relative path */ if (rel_path == NULL) { (void) sprintf (tmp, "%s/", CVSroot); if (strncmp (repository, tmp, strlen (tmp)) != 0) error (1, 0, "bug #2, %s does not prefixed with CVSROOT %s", repository, CVSroot); rel_path = repository + strlen (tmp); } /* create Remote file */ if (dir != NULL) (void) sprintf (tmp, "%s/%s", dir, RCVSADM_REMOTE); else (void) strcpy (tmp, RCVSADM_REMOTE); fout = open_file (tmp, "w+"); if (RCVSuser == NULL || RCVShost == NULL || RCVSroot == NULL) error (1, 0, "bug#3, %s@%s:%s:%s\n ", RCVSuser, RCVShost, RCVSroot, RCVSdir ); (void ) sprintf (path, "%s@%s:%s:%s %s", RCVSuser, RCVShost, RCVSroot, RCVSdir, rel_path ); if (fprintf (fout, "%s\n", path) == EOF) error (1, 0, "write to %s failed", tmp); if (fclose (fout) == EOF) error (1, errno, "cannot close %s", tmp); if (trace) { char *curDir; curDir = xmalloc (PATH_MAX); (void) getwd (curDir); CurDir = xstrdup (curDir); free (curDir); fprintf (stderr, "-> rcvs_create_adm: CurDir =%s\n", CurDir, tmp); fprintf (stderr, "-> rcvs_create_adm: remote = %s\n", tmp); fprintf (stderr, "-> rcvs_create_adm: %s\n", path); } free (command); command_name = Command_Name; return (0); } /* rcvs: dump a list */ int rcvs_dump_list ( msg, mlist ) char *msg; List *mlist; { if (msg != NULL) fprintf(stderr, "-> %s", msg); walklist (mlist, rcvs_Print_Node); fprintf(stderr, "\n"); return (0); } /* rcvs: get host.domain for local host */ char * rcvs_gethostdomain() { #include struct hostent *hp; char host[PATH_MAX]; char tmp[PATH_MAX]; char *HostDomain; char *hostdomain = NULL; char *cp; /* get host */ (void) gethostname ( host, sizeof(host) ); if (host != NULL) cp = index( host, '.'); if ( cp != NULL) *cp = '\0'; /* get domain, see if it's set with CVSDOMAIN */ if (rcvs_domain != NULL) { sprintf (tmp, "%s.%s", host, rcvs_domain); return (xstrdup(tmp)); } /* get domain, try gethostbyname */ hp = gethostbyname(host); HostDomain = hp->h_name; if (HostDomain != NULL) cp = index( HostDomain, '.'); if (cp != NULL) hostdomain = xstrdup (HostDomain); /* get domain, try getdomainname */ if ( hostdomain == NULL) { char domain [PATH_MAX]; (void) getdomainname ( domain, sizeof(domain)); if (domain != NULL) cp = index( domain, '.'); if ( cp != NULL) { char tmp [PATH_MAX]; sprintf (tmp, "%s.%s", host, cp+1); hostdomain = xstrdup (tmp); } } if ( hostdomain == NULL) { command_name = xstrdup ("rcvs_gethostdomain"); error (0, 0, "can not find network domain"); error (0, 0, "set CVSDOMAIN to network domain of your machine"); error (1, 0, "not including hostname !!! (e.g. dec.com)"); } return (hostdomain); } /* rcvs: parse CVSROOT */ int rcvs_Parse_ID (Str, rcvsuser, rcvshost, rcvsroot, rcvsdir, cvsroot) char *Str; char **rcvsuser; char **rcvshost; char **rcvsroot; char **rcvsdir; char **cvsroot; { char *cp; char *Cp; char *str; int count = 0; if ( Str == "" || Str == NULL ) error (1, 0, "rcvs_Parse_ID: bug #1, Str=null string"); str = xstrdup (Str); if ((cp = index (str, ':')) == NULL) { if ((cp = index (str, '@')) != NULL) error (1, 0, "rcvs_Parse_ID: bad CVSROOT: '%s'\n", str); else *cvsroot = xstrdup (str); } else { if ((Cp = index (cp+1, ':')) != NULL) { *rcvsdir = xstrdup (Cp+1); *Cp = '\0'; } else error (1, 0, "rcvs_Parse_ID: bad CVSROOT '%s'\n", str); *rcvsroot = xstrdup (cp+1); *cp = '\0'; /* rcvs: has RCVSuser (rcvsuser@rcvshost) */ if ((cp = index (str, '@')) != NULL) { *rcvshost = xstrdup (cp+1); *cp = '\0'; *rcvsuser = xstrdup (str); } else *rcvshost = xstrdup (str); *cvsroot = *rcvsdir; } /* check results */ { if (*rcvsuser == NULL || strcmp (*rcvsuser, "") == 0) *rcvsuser = rcvs_username; if (*rcvsuser != NULL) count++; if (*rcvshost != NULL) count++; if (*rcvsroot != NULL) count++; if (*rcvsdir != NULL) count++; if (count >1 && count < 4) error(1,0,"%s is not in RCVSUSER@RCVSHOST:CVSROOT:RCVSDIR format", CVSROOT_ENV); } free (str); return (0); } /* rcvs: print the key of a node to stdio, called by rcvs_dump_list */ int rcvs_Print_Node (p) Node *p; { List *L; if (p->type == DIRS) fprintf(stderr, " %s", p->key); else fprintf(stderr, " %s (%s)", p->key, p->data); if (p->type == DIRS && p->data != NULL) { L = (void *) p->data; rcvs_dump_list( (char *) NULL, L); } return (0); } /* check repository of a local folder * cvsroot: current CVSROOT value * dir: name of folder * repository: the repository of existing folder */ int rcvs_check_local_repos (cvsroot, dir, repository) char *cvsroot; char *dir; char *repository; { char path[PATH_MAX]; char *Command_Name; char *command; Command_Name = command_name; command = xstrdup ("rcvs_check_local_repos"); command_name = command; if (!cvsroot || !*cvsroot) error (1, 0,"You don't have a %s environment variable",CVSROOT_ENV); (void) sprintf (path, "%s/%s", cvsroot, CVSROOTADM); if (access (path, R_OK | X_OK)) { error (0, 0, "you don't have sufficient access to %s: %s", CVSROOT_ENV, cvsroot); error (1, 0, "%s", path); } (void) sprintf (path, "%s/", cvsroot); if (strncmp (repository, path, strlen (path)) != 0 && !rcvs_copt_change_repos) { error (0, 0, "%s does not match local folder '%s'", CVSROOT_ENV, dir); error (1, 0, "%s = %s", CVSADM_REP, repository); } free (command); command_name = Command_Name; return (0); } /* get information from CVS/Repository and CVS/Remote, * dir: path relative to current directory * &Id: the CVSROOTr stored in CVS/Remote. * &Repository: the repository relative to local CVSROOT */ char * rcvs_get_repos (dir, Id, Repository) char *dir; char **Id; char **Repository; { char *ID; char repository[PATH_MAX]; char *Repos = NULL; char *Command_Name; char *command; Command_Name = command_name; command = xstrdup ("rcvs_get_repos"); command_name = command; if (dir == NULL) error(1, 0, "rcvs_get_repos: #bug: dir is null"); sprintf (repository, "%s/%s", dir, CVSADM_REP); if (isreadable ( repository )) /* CVS/Repository */ { FILE *fpin; char repos[PATH_MAX]; char tmp[PATH_MAX]; char *cp; int remote_exist = FALSE; ID = NULL; if (dir == NULL) error (1, 0, "#bug:, dir==NULL"); if (dir != NULL) (void) sprintf (tmp, "%s/%s", dir, RCVSADM_REMOTE); else (void) strcpy (tmp, RCVSADM_REMOTE); if (isreadable (tmp)) /* CVS/Remote */ { remote_exist = TRUE; fpin = open_file (tmp, "r"); if (fgets (repos, PATH_MAX, fpin) == NULL) error (1, 0, "#bug: cannot read %s",tmp); if (fclose (fpin) == EOF) error (1, 0, "#bug: cannot close %s", tmp); if (repos == NULL) error(1, 0, "#bug:, repos = NULL"); if ((cp = rindex (repos, '\n')) != NULL) *cp = '\0'; if (repos == "") error(1, 0, "#bug:, repos = NULL"); else { char *str; str = xstrdup (repos); if ((cp = index (str, ' ')) == NULL) error (1, 0, "bad %s file", RCVSADM_REMOTE); else { *cp++ = '\0'; ID = xstrdup (str); Repos = xstrdup (cp); } } } if (rcvs_Copt_change_repos) { char *rep; rep = Name_Repository (dir,""); if ( rep != NULL && index (rep, '/') == NULL) error (1, 0, "%s is corrupted", CVSADM_REP); if (!remote_exist) { char *rcvsuser; char *rcvshost; char *rcvsroot; char *rcvsdir; char *cvsroot; (void) rcvs_Parse_ID (rcvs_ID, &rcvsuser, &rcvshost, &rcvsroot,&rcvsdir, &cvsroot); if (strncmp (rep, rcvsdir, strlen (rcvsdir)) != 0) { error (0, 0, "%s does not match local folder %s", rcvs_Id, dir); error (1, 0, "%s = %s", CVSADM_REP, rep); } if (!quiet) fprintf (stderr, "hum.. this must be a rcvs-0.3.9 folder\n"); Repos = xstrdup(rep + strlen(rcvsdir) + 1); } if (trace) fprintf (stderr, "-> -C option, use %s and ignore %s if it exist\n", rcvs_Id, RCVSADM_REMOTE); ID = xstrdup (rcvs_ID); } else if (!remote_exist) /* no CVS/Remote */ { if (trace) fprintf (stderr, "-> %s un-accessible, assume it's local folder\n",tmp); } if (ID != NULL && index (ID,':') != NULL) /* remote folder */ { char *rcvsuser; char *rcvshost; char *rcvsroot; char *rcvsdir; char *cvsroot; rcvs_native_RCVS = TRUE; *Id = ID; if (Repos != NULL && strncmp (Repos, RCVSMOD, strlen(RCVSMOD)) == 0) Repos += strlen(RCVSMOD); (void) rcvs_Parse_ID (ID, &rcvsuser, &rcvshost, &rcvsroot,&rcvsdir, &cvsroot); *Repository = xstrdup (rcvsdir); if ( trace && !rcvs_Copt_change_repos) { fprintf (stderr, "-> remote folder '%s' exist \n", dir); fprintf (stderr, "-> repository = %s\n", ID); } } else /* local folder */ { *Repository = Name_Repository (dir,""); if ( CVSroot_v != NULL && index(CVSroot_v,':') != NULL) { error (0, 0, "'%s' is local folder", dir); error (1, 0, "%s cannot be in remote format ",CVSROOT_ENV); } if (rcvs_CM->need_repos) { if (!rcvs_copt_change_repos) (void) rcvs_check_local_repos (CVSroot_v, dir, *Repository); } *Id = xstrdup (CVSroot); Repos = xstrdup (dir); } } else error (1,0,"#bug: %s is not a CVS folder", dir); free (command); command_name = Command_Name; return (Repos); } /* * rcvs: walk a list with a specific proc and argument */ int rcvs_walklist (argc, argv, msg, list, proc) int argc; char *argv[]; char *msg; List *list; int (*proc) (); { Node *head, *p; int err = 0; if (list == NULL) { error (1, 0, "rcvs_walklist: bug %s, list==NULL", msg); return (0); } head = list->list; for (p = head->next; p != head; p = p->next) err += proc (argc, argv, p); return (err); } /* rcvs: return size of file */ int filesize (repository) char *repository; { struct stat sbuf; if ( stat(repository, &sbuf) == 0) return (sbuf.st_size); else return(0); }