1*4dcde513Sjoris /* $OpenBSD: status.c,v 1.100 2017/06/01 08:08:24 joris Exp $ */
26036ca11Sjfb /*
33ad3fb45Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
4f736e780Sxsa * Copyright (c) 2005-2008 Xavier Santolaria <xsa@openbsd.org>
56036ca11Sjfb *
63ad3fb45Sjoris * Permission to use, copy, modify, and distribute this software for any
73ad3fb45Sjoris * purpose with or without fee is hereby granted, provided that the above
83ad3fb45Sjoris * copyright notice and this permission notice appear in all copies.
96036ca11Sjfb *
103ad3fb45Sjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113ad3fb45Sjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123ad3fb45Sjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133ad3fb45Sjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143ad3fb45Sjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153ad3fb45Sjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163ad3fb45Sjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176036ca11Sjfb */
186036ca11Sjfb
19aaa6eb81Sjoris #include <stdlib.h>
201f8531bdSotto #include <string.h>
216534056aStobias #include <time.h>
221f8531bdSotto #include <unistd.h>
236036ca11Sjfb
246036ca11Sjfb #include "cvs.h"
259fac60a5Sjoris #include "remote.h"
266036ca11Sjfb
273ad3fb45Sjoris void cvs_status_local(struct cvs_file *);
286036ca11Sjfb
29f5174622Sxsa static int show_sym = 0;
30f5174622Sxsa
31e4276007Sjfb struct cvs_cmd cvs_cmd_status = {
32f331ff59Stobias CVS_OP_STATUS, CVS_USE_WDIR, "status",
33e4276007Sjfb { "st", "stat" },
34e4276007Sjfb "Display status information on checked out files",
35e4276007Sjfb "[-lRv]",
36f5174622Sxsa "lRv",
37e4276007Sjfb NULL,
383ad3fb45Sjoris cvs_status
3916cfc147Sjoris };
406036ca11Sjfb
413ad3fb45Sjoris #define CVS_STATUS_SEP \
423ad3fb45Sjoris "==================================================================="
4316cfc147Sjoris
443ad3fb45Sjoris const char *status_tab[] = {
453ad3fb45Sjoris "Unknown",
463ad3fb45Sjoris "Locally Added",
473ad3fb45Sjoris "Locally Removed",
483ad3fb45Sjoris "Locally Modified",
493ad3fb45Sjoris "Up-to-date",
503ad3fb45Sjoris "Needs Checkout",
513ad3fb45Sjoris "Needs Checkout",
523ad3fb45Sjoris "Needs Merge",
533ad3fb45Sjoris "Needs Patch",
543ad3fb45Sjoris "Entry Invalid",
553ad3fb45Sjoris "Unresolved Conflict",
563ad3fb45Sjoris "Classifying error",
573ad3fb45Sjoris };
583ad3fb45Sjoris
593ad3fb45Sjoris int
cvs_status(int argc,char ** argv)603ad3fb45Sjoris cvs_status(int argc, char **argv)
616036ca11Sjfb {
621890abdaSjoris int ch, flags;
633ad3fb45Sjoris char *arg = ".";
643ad3fb45Sjoris struct cvs_recursion cr;
656036ca11Sjfb
669fac60a5Sjoris flags = CR_RECURSE_DIRS;
671890abdaSjoris
683ad3fb45Sjoris while ((ch = getopt(argc, argv, cvs_cmd_status.cmd_opts)) != -1) {
696036ca11Sjfb switch (ch) {
70a922347aSjfb case 'l':
711890abdaSjoris flags &= ~CR_RECURSE_DIRS;
72a922347aSjfb break;
73a922347aSjfb case 'R':
74bcf22459Stobias flags |= CR_RECURSE_DIRS;
75a922347aSjfb break;
76a922347aSjfb case 'v':
77f5174622Sxsa show_sym = 1;
78a922347aSjfb break;
796036ca11Sjfb default:
803ad3fb45Sjoris fatal("%s", cvs_cmd_status.cmd_synopsis);
816036ca11Sjfb }
826036ca11Sjfb }
836036ca11Sjfb
843ad3fb45Sjoris argc -= optind;
853ad3fb45Sjoris argv += optind;
866036ca11Sjfb
873ad3fb45Sjoris cr.enterdir = NULL;
883ad3fb45Sjoris cr.leavedir = NULL;
899fac60a5Sjoris
90*4dcde513Sjoris if (cvsroot_is_local()) {
919fac60a5Sjoris flags |= CR_REPO;
92bc5d89feSjoris cr.fileproc = cvs_status_local;
939fac60a5Sjoris } else {
9480f6ca9bSjoris cvs_client_connect_to_server();
959fac60a5Sjoris if (!(flags & CR_RECURSE_DIRS))
969fac60a5Sjoris cvs_client_send_request("Argument -l");
979fac60a5Sjoris if (show_sym)
989fac60a5Sjoris cvs_client_send_request("Argument -v");
999fac60a5Sjoris cr.fileproc = cvs_client_sendfile;
1009fac60a5Sjoris }
1019fac60a5Sjoris
1021890abdaSjoris cr.flags = flags;
103b6207e53Sxsa
1043ad3fb45Sjoris if (argc > 0)
1053ad3fb45Sjoris cvs_file_run(argc, argv, &cr);
106b5f0ecd9Sjfb else
1073ad3fb45Sjoris cvs_file_run(1, &arg, &cr);
108235ffbbdSjfb
109*4dcde513Sjoris if (cvsroot_is_remote()) {
1109fac60a5Sjoris cvs_client_send_files(argv, argc);
1119fac60a5Sjoris cvs_client_senddir(".");
1129fac60a5Sjoris cvs_client_send_request("status");
1139fac60a5Sjoris cvs_client_get_responses();
1149fac60a5Sjoris }
1159fac60a5Sjoris
1167e393898Sjoris return (0);
117235ffbbdSjfb }
118235ffbbdSjfb
1193ad3fb45Sjoris void
cvs_status_local(struct cvs_file * cf)1203ad3fb45Sjoris cvs_status_local(struct cvs_file *cf)
121235ffbbdSjfb {
1223ad3fb45Sjoris size_t len;
123aaa6eb81Sjoris RCSNUM *head, *brev;
1243ad3fb45Sjoris const char *status;
125d433019cSstsp struct rcs_delta *rdp;
126b9fc9a72Sderaadt char buf[PATH_MAX + CVS_REV_BUFSZ + 128];
1277d7c52beSmillert char timebuf[CVS_TIME_BUFSZ], revbuf[CVS_REV_BUFSZ];
128f5174622Sxsa struct rcs_sym *sym;
129235ffbbdSjfb
1303ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_status_local(%s)", cf->file_path);
1313ad3fb45Sjoris
13251ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag);
1333ad3fb45Sjoris
1343ad3fb45Sjoris if (cf->file_type == CVS_DIR) {
1357d73e7b0Sxsa if (verbosity > 1)
1363ad3fb45Sjoris cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
1373ad3fb45Sjoris return;
1387d73e7b0Sxsa }
139235ffbbdSjfb
1405cf15c45Sjoris if (cf->file_status == FILE_UPTODATE &&
1415cf15c45Sjoris !(cf->file_flags & FILE_ON_DISK) &&
14298902223Sjoris !(cf->file_flags & FILE_USER_SUPPLIED))
143fd5737cbSjoris return;
144fd5737cbSjoris
145e28eda4eStobias if (cf->file_rcs != NULL)
1462d6bc62cSjoris head = cf->file_rcsrev;
147e28eda4eStobias else
148725515b2Sjoris head = NULL;
1499af0ab72Stobias
1503ad3fb45Sjoris cvs_printf("%s\n", CVS_STATUS_SEP);
1516036ca11Sjfb
152e28eda4eStobias if (cf->file_rcs != NULL && head == NULL)
153e28eda4eStobias status = status_tab[FILE_UNKNOWN];
154e28eda4eStobias else
1553ad3fb45Sjoris status = status_tab[cf->file_status];
156e28eda4eStobias
1573ad3fb45Sjoris if (cf->file_status == FILE_MODIFIED &&
1583ad3fb45Sjoris cf->file_ent->ce_conflict != NULL)
1593ad3fb45Sjoris status = "File had conflicts on merge";
1606036ca11Sjfb
1615cf15c45Sjoris if (!(cf->file_flags & FILE_ON_DISK)) {
162c486465dSxsa (void)xsnprintf(buf, sizeof(buf), "no file %s\t",
163c486465dSxsa cf->file_name);
164fd443860Sxsa } else
165fd443860Sxsa if (strlcpy(buf, cf->file_name, sizeof(buf)) >= sizeof(buf))
166fd443860Sxsa fatal("cvs_status_local: overflow");
167fd443860Sxsa
168fd443860Sxsa cvs_printf("File: %-17s\tStatus: %s\n\n", buf, status);
169553914b8Sxsa
1703ad3fb45Sjoris if (cf->file_ent == NULL) {
171c486465dSxsa (void)xsnprintf(buf, sizeof(buf),
1723ad3fb45Sjoris "No entry for %s", cf->file_name);
173e28eda4eStobias } else if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
1743ad3fb45Sjoris len = strlcpy(buf, "New file!", sizeof(buf));
1753ad3fb45Sjoris if (len >= sizeof(buf))
1763ad3fb45Sjoris fatal("cvs_status_local: truncation");
177d32a75e7Sjfb } else {
1783ad3fb45Sjoris rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
1790b9511b4Sxsa
1803ad3fb45Sjoris if (cf->file_ent->ce_conflict == NULL) {
18101d427ddSjoris if (cvs_server_active == 0) {
182694b1da3Sstsp (void)strlcpy(timebuf, cf->file_ent->ce_time,
183694b1da3Sstsp sizeof(timebuf));
1843ad3fb45Sjoris } else {
18501d427ddSjoris timebuf[0] = '\0';
18601d427ddSjoris }
18701d427ddSjoris } else {
1883ad3fb45Sjoris len = strlcpy(timebuf, cf->file_ent->ce_conflict,
1893ad3fb45Sjoris sizeof(timebuf));
1903ad3fb45Sjoris if (len >= sizeof(timebuf))
1913ad3fb45Sjoris fatal("cvs_status_local: truncation");
1920b9511b4Sxsa }
1933ad3fb45Sjoris
1940d508764Sxsa (void)strlcpy(buf, revbuf, sizeof(buf));
1950d508764Sxsa if (cvs_server_active == 0) {
1960d508764Sxsa (void)strlcat(buf, "\t", sizeof(buf));
1970d508764Sxsa (void)strlcat(buf, timebuf, sizeof(buf));
1980d508764Sxsa }
199d32a75e7Sjfb }
200d32a75e7Sjfb
2014b74b9b9Sxsa cvs_printf(" Working revision:\t%s\n", buf);
202d12f10c0Sxsa
2033ad3fb45Sjoris buf[0] = '\0';
204e28eda4eStobias if (cf->file_rcs == NULL) {
2053ad3fb45Sjoris len = strlcat(buf, "No revision control file", sizeof(buf));
2063ad3fb45Sjoris if (len >= sizeof(buf))
2073ad3fb45Sjoris fatal("cvs_status_local: truncation");
208e28eda4eStobias } else if (head == NULL) {
209e28eda4eStobias len = strlcat(buf, "No head revision", sizeof(buf));
210e28eda4eStobias if (len >= sizeof(buf))
211e28eda4eStobias fatal("cvs_status_local: truncation");
212d12f10c0Sxsa } else {
213570941ffSjoris rcsnum_tostr(head, revbuf, sizeof(revbuf));
214c486465dSxsa (void)xsnprintf(buf, sizeof(buf), "%s\t%s", revbuf,
2153ad3fb45Sjoris cf->file_rpath);
216ce2fed3bSjoris }
217ce2fed3bSjoris
218d12f10c0Sxsa cvs_printf(" Repository revision:\t%s\n", buf);
219d12f10c0Sxsa
220d433019cSstsp if (cf->file_rcs != NULL && head != NULL) {
221d433019cSstsp rdp = rcs_findrev(cf->file_rcs, head);
222d433019cSstsp if (rdp == NULL) {
223d433019cSstsp fatal("cvs_status_local: No head revision delta");
224d433019cSstsp }
225d433019cSstsp
226d433019cSstsp cvs_printf(" Commit Identifier:\t%s\n",
227d433019cSstsp (rdp->rd_commitid != NULL) ? rdp->rd_commitid : "(none)");
228d433019cSstsp }
229d433019cSstsp
2303ad3fb45Sjoris if (cf->file_ent != NULL) {
231aaa6eb81Sjoris if (cf->file_ent->ce_tag != NULL) {
232aaa6eb81Sjoris if ((brev = rcs_sym_getrev(cf->file_rcs,
233aaa6eb81Sjoris cf->file_ent->ce_tag)) == NULL) {
234aaa6eb81Sjoris (void)strlcpy(buf, "- MISSING from RCS file!",
235aaa6eb81Sjoris sizeof(buf));
236aaa6eb81Sjoris } else {
237aaa6eb81Sjoris rcsnum_tostr(brev, revbuf, sizeof(revbuf));
238d884564eSjoris if (RCSNUM_ISBRANCH(brev)) {
239d884564eSjoris xsnprintf(buf, sizeof(buf),
240aaa6eb81Sjoris "(branch: %s)", revbuf);
241d884564eSjoris } else {
242d884564eSjoris xsnprintf(buf, sizeof(buf),
243d884564eSjoris "(revision: %s)", revbuf);
244d884564eSjoris }
245aaa6eb81Sjoris free(brev);
246aaa6eb81Sjoris }
247aaa6eb81Sjoris
248aaa6eb81Sjoris cvs_printf(" Sticky Tag:\t\t%s %s\n",
249aaa6eb81Sjoris cf->file_ent->ce_tag, buf);
250aaa6eb81Sjoris } else if (verbosity > 0) {
25102ae6043Sxsa cvs_printf(" Sticky Tag:\t\t(none)\n");
252aaa6eb81Sjoris }
25302ae6043Sxsa
254f736e780Sxsa if (cf->file_ent->ce_date != -1) {
2556534056aStobias struct tm datetm;
256f736e780Sxsa char datetmp[CVS_TIME_BUFSZ];
257f736e780Sxsa
2586534056aStobias gmtime_r(&(cf->file_ent->ce_date), &datetm);
259f736e780Sxsa (void)strftime(datetmp, sizeof(datetmp),
2606534056aStobias CVS_DATE_FMT, &datetm);
261f736e780Sxsa
262f736e780Sxsa cvs_printf(" Sticky Date:\t\t%s\n", datetmp);
263f736e780Sxsa } else if (verbosity > 0)
264f736e780Sxsa cvs_printf(" Sticky Date:\t\t(none)\n");
265f736e780Sxsa
2663ad3fb45Sjoris if (cf->file_ent->ce_opts != NULL)
2673ad3fb45Sjoris cvs_printf(" Sticky Options:\t%s\n",
2683ad3fb45Sjoris cf->file_ent->ce_opts);
26902ae6043Sxsa else if (verbosity > 0)
27002ae6043Sxsa cvs_printf(" Sticky Options:\t(none)\n");
271077dcb78Sxsa }
272077dcb78Sxsa
2737e3fae51Sjoris if (cf->file_rcs != NULL && show_sym == 1) {
274f5174622Sxsa cvs_printf("\n");
275f5174622Sxsa cvs_printf(" Existing Tags:\n");
276f5174622Sxsa
277f5174622Sxsa if (!TAILQ_EMPTY(&(cf->file_rcs->rf_symbols))) {
278f5174622Sxsa TAILQ_FOREACH(sym,
279f5174622Sxsa &(cf->file_rcs->rf_symbols), rs_list) {
280f5174622Sxsa (void)rcsnum_tostr(sym->rs_num, revbuf,
281f5174622Sxsa sizeof(revbuf));
282f5174622Sxsa
283f5174622Sxsa cvs_printf("\t%-25s\t(%s: %s)\n", sym->rs_name,
284f5174622Sxsa RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
285f5174622Sxsa "revision", revbuf);
286f5174622Sxsa }
287f5174622Sxsa } else
288f5174622Sxsa cvs_printf("\tNo Tags Exist\n");
289f5174622Sxsa }
290f5174622Sxsa
291f0c47733Sxsa cvs_printf("\n");
2926036ca11Sjfb }
293