65 |
"\t-u[rev] Unlock the revision (latest revision on branch,\n", |
"\t-u[rev] Unlock the revision (latest revision on branch,\n", |
66 |
"\t latest revision on trunk if omitted).\n", |
"\t latest revision on trunk if omitted).\n", |
67 |
"\t-U Unset strict locking.\n", |
"\t-U Unset strict locking.\n", |
68 |
|
"\t--no-execute Turn off execute bits on repository file.\n", |
69 |
|
"\t--execute Turn on execute bits on respoitory file.\n", |
70 |
"(Specify the --help global option for a list of other help options)\n", |
"(Specify the --help global option for a list of other help options)\n", |
71 |
NULL |
NULL |
72 |
}; |
}; |
103 |
/* Interactive (-I). Problematic with client/server. */ |
/* Interactive (-I). Problematic with client/server. */ |
104 |
int interactive; |
int interactive; |
105 |
|
|
106 |
|
enum {AVOID = 0, NOEXECUTE, EXECUTE} execute; |
107 |
|
|
108 |
/* This is the cheesy part. It is a vector with the options which |
/* This is the cheesy part. It is a vector with the options which |
109 |
we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future |
we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future |
110 |
this presumably will be replaced by other variables which break |
this presumably will be replaced by other variables which break |
210 |
|
|
211 |
|
|
212 |
|
|
213 |
|
static struct option long_options[] = |
214 |
|
{ |
215 |
|
{"no-execute", 0, NULL, 1}, |
216 |
|
{"execute", 0, NULL, 2}, |
217 |
|
{0, 0, 0, 0} |
218 |
|
}; |
219 |
|
|
220 |
|
|
221 |
|
|
222 |
|
/* Accept a `;' delimited string and break it into tokens. Allocate a return |
223 |
|
* string. Copy the first token into the return string. For remaining tokens, |
224 |
|
* convert to the long option VAL (from the global LONG_OPTIONS above) and |
225 |
|
* append that char to the return value. When long option tokens are |
226 |
|
* unrecognized, a warning is printed and they are ignored. |
227 |
|
* |
228 |
|
* i.e., S will be of the format `[SHORTOPTIONS][;LONGOPTION]...'. It is |
229 |
|
* perfectly acceptable for SHORTOPTIONS to resolve to the empty string, but |
230 |
|
* an empty LONGOPTION will cause a warning message to be printed. |
231 |
|
*/ |
232 |
|
char * |
233 |
|
make_UserAdminOptions (const char *infopath, unsigned int ln, const char *s) |
234 |
|
{ |
235 |
|
const char *p; |
236 |
|
bool first = true; |
237 |
|
char *ns = xmalloc (1); |
238 |
|
|
239 |
|
assert (s); |
240 |
|
|
241 |
|
p = s; |
242 |
|
*ns = '\0'; |
243 |
|
do |
244 |
|
{ |
245 |
|
struct option *found; |
246 |
|
const char *q; |
247 |
|
size_t len; |
248 |
|
|
249 |
|
q = strchr (p, ';'); |
250 |
|
if (q) len = q - p; |
251 |
|
else len = strlen (p); |
252 |
|
|
253 |
|
if (first) |
254 |
|
{ |
255 |
|
first = false; |
256 |
|
found = NULL; |
257 |
|
} |
258 |
|
else |
259 |
|
for (found = long_options; found->name; found++) |
260 |
|
if (len == strlen (found->name) |
261 |
|
&& !strncmp (p, found->name, len)) |
262 |
|
break; |
263 |
|
|
264 |
|
if (found && found->name) |
265 |
|
{ |
266 |
|
ns = xrealloc (ns, len + 2); |
267 |
|
ns[len++] = found->val; |
268 |
|
ns[len] = '\0'; |
269 |
|
TRACE (TRACE_FUNCTION, "Adding long UserAdminOptions `%s'", |
270 |
|
found->name); |
271 |
|
} |
272 |
|
else if (first) |
273 |
|
{ |
274 |
|
size_t nslen = strlen (ns); |
275 |
|
ns = xrealloc (ns, nslen + len + 1); |
276 |
|
strncat (ns, p, len); |
277 |
|
ns[nslen + len] = '\0'; |
278 |
|
TRACE (TRACE_FUNCTION, "Appending `%s' to UserAdminOptions", |
279 |
|
ns + nslen); |
280 |
|
} |
281 |
|
else |
282 |
|
{ |
283 |
|
char *tmp = xmalloc (len + 1); |
284 |
|
strncpy (tmp, p, len); |
285 |
|
ns[len] = '\0'; |
286 |
|
error (0, 0, |
287 |
|
"%s [%u]: Unrecognized long admin option `%s'.", |
288 |
|
infopath, ln, tmp); |
289 |
|
free (tmp); |
290 |
|
} |
291 |
|
|
292 |
|
p = q; |
293 |
|
} while (p); |
294 |
|
|
295 |
|
return ns; |
296 |
|
} |
297 |
|
|
298 |
|
|
299 |
|
|
300 |
int |
int |
301 |
admin (int argc, char **argv) |
admin (int argc, char **argv) |
302 |
{ |
{ |
310 |
int i; |
int i; |
311 |
bool only_allowed_options; |
bool only_allowed_options; |
312 |
|
|
313 |
|
static const char short_options[] = |
314 |
|
"+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:"; |
315 |
|
|
316 |
if (argc <= 1) |
if (argc <= 1) |
317 |
usage (admin_usage); |
usage (admin_usage); |
318 |
|
|
325 |
|
|
326 |
optind = 0; |
optind = 0; |
327 |
only_allowed_options = true; |
only_allowed_options = true; |
328 |
while ((c = getopt (argc, argv, |
while ((c = getopt_long |
329 |
"+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1) |
(argc, argv, short_options, long_options, &optind)) |
330 |
|
!= EOF) |
331 |
{ |
{ |
332 |
if ( |
if ( |
333 |
# ifdef CLIENT_SUPPORT |
# ifdef CLIENT_SUPPORT |
339 |
|
|
340 |
switch (c) |
switch (c) |
341 |
{ |
{ |
342 |
|
case 1: /* --no-execute */ |
343 |
|
admin_data.execute = NOEXECUTE; |
344 |
|
break; |
345 |
|
|
346 |
|
case 2: /* --execute */ |
347 |
|
admin_data.execute = EXECUTE; |
348 |
|
break; |
349 |
|
|
350 |
case 'i': |
case 'i': |
351 |
/* This has always been documented as useless in cvs.texinfo |
/* This has always been documented as useless in cvs.texinfo |
352 |
and it really is--admin_fileproc silently does nothing |
and it really is--admin_fileproc silently does nothing |
635 |
send_arg ("-U"); |
send_arg ("-U"); |
636 |
if (admin_data.delete_revs != NULL) |
if (admin_data.delete_revs != NULL) |
637 |
send_arg (admin_data.delete_revs); |
send_arg (admin_data.delete_revs); |
638 |
|
if (admin_data.execute == EXECUTE) |
639 |
|
send_arg ("--execute"); |
640 |
|
else if (admin_data.execute == NOEXECUTE) |
641 |
|
send_arg ("--no-execute"); |
642 |
if (admin_data.desc != NULL) |
if (admin_data.desc != NULL) |
643 |
{ |
{ |
644 |
char *p = admin_data.desc; |
char *p = admin_data.desc; |
1081 |
if (status == 0) |
if (status == 0) |
1082 |
{ |
{ |
1083 |
RCS_rewrite (rcs, NULL, NULL); |
RCS_rewrite (rcs, NULL, NULL); |
1084 |
|
|
1085 |
|
/* |
1086 |
|
* Update the execute bit for the file if requested. |
1087 |
|
*/ |
1088 |
|
if (admin_data->execute != AVOID) |
1089 |
|
{ |
1090 |
|
struct stat sb; |
1091 |
|
|
1092 |
|
if (stat (rcs->path, &sb) < 0) |
1093 |
|
error (0, errno, "cannot stat `%s'", rcs->path); |
1094 |
|
else |
1095 |
|
{ |
1096 |
|
mode_t mode; |
1097 |
|
|
1098 |
|
if (admin_data->execute == EXECUTE) |
1099 |
|
mode = (sb.st_mode |
1100 |
|
| (((sb.st_mode & S_IRUSR) ? S_IXUSR : 0) |
1101 |
|
| ((sb.st_mode & S_IRGRP) ? S_IXGRP : 0) |
1102 |
|
| ((sb.st_mode & S_IROTH) ? S_IXOTH : 0))); |
1103 |
|
else /* admin_data->execute == NOEXECUTE */ |
1104 |
|
mode = (sb.st_mode |
1105 |
|
& ~(S_IEXEC | S_IXGRP | S_IXOTH)); |
1106 |
|
|
1107 |
|
if (mode == sb.st_mode) |
1108 |
|
error (0, 0, "%s: already has mode=0%o", |
1109 |
|
rcs->path, (unsigned int) mode); |
1110 |
|
else |
1111 |
|
{ |
1112 |
|
TRACE (TRACE_FLOW, "chmod(%s,0%o)", rcs->path, |
1113 |
|
(unsigned int) mode); |
1114 |
|
|
1115 |
|
if (!noexec) |
1116 |
|
{ |
1117 |
|
if (chmod (rcs->path, mode) < 0) |
1118 |
|
error (0, errno, |
1119 |
|
"cannot change mode of file `%s'", |
1120 |
|
rcs->path); |
1121 |
|
} |
1122 |
|
} |
1123 |
|
} |
1124 |
|
} |
1125 |
|
|
1126 |
if (!really_quiet) |
if (!really_quiet) |
1127 |
cvs_output ("done\n", 5); |
cvs_output ("done\n", 5); |
1128 |
} |
} |