10Sstevel@tonic-gate /*
27934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
80Sstevel@tonic-gate * All rights reserved.
90Sstevel@tonic-gate *
100Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
110Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are
120Sstevel@tonic-gate * duplicated in all such forms and that any documentation,
130Sstevel@tonic-gate * advertising materials, and other materials related to such
140Sstevel@tonic-gate * distribution and use acknowledge that the software was developed
150Sstevel@tonic-gate * by the University of California, Berkeley. The name of the
160Sstevel@tonic-gate * University may not be used to endorse or promote products derived
170Sstevel@tonic-gate * from this software without specific prior written permission.
180Sstevel@tonic-gate */
190Sstevel@tonic-gate
200Sstevel@tonic-gate #include "defs.h"
210Sstevel@tonic-gate #include <string.h>
220Sstevel@tonic-gate #include <syslog.h>
237934SMark.Phalan@Sun.COM #include <k5-int.h>
240Sstevel@tonic-gate #include <krb5defs.h>
250Sstevel@tonic-gate #include <priv_utils.h>
260Sstevel@tonic-gate
270Sstevel@tonic-gate #define NHOSTS 100
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * Remote distribution program.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate char *distfile = NULL;
340Sstevel@tonic-gate char Tmpfile[] = "/tmp/rdistXXXXXX";
350Sstevel@tonic-gate char *tmpname = &Tmpfile[5];
360Sstevel@tonic-gate
370Sstevel@tonic-gate int debug; /* debugging flag */
380Sstevel@tonic-gate int nflag; /* NOP flag, just print commands without executing */
390Sstevel@tonic-gate int qflag; /* Quiet. Don't print messages */
400Sstevel@tonic-gate int options; /* global options */
410Sstevel@tonic-gate int iamremote; /* act as remote server for transfering files */
420Sstevel@tonic-gate
430Sstevel@tonic-gate FILE *fin = NULL; /* input file pointer */
440Sstevel@tonic-gate int rem = -1; /* file descriptor to remote source/sink process */
450Sstevel@tonic-gate char host[32]; /* host name */
460Sstevel@tonic-gate int nerrs; /* number of errors while sending/receiving */
470Sstevel@tonic-gate char user[10]; /* user's name */
480Sstevel@tonic-gate char homedir[128]; /* user's home directory */
490Sstevel@tonic-gate char buf[RDIST_BUFSIZ]; /* general purpose buffer */
500Sstevel@tonic-gate
510Sstevel@tonic-gate struct passwd *pw; /* pointer to static area used by getpwent */
520Sstevel@tonic-gate struct group *gr; /* pointer to static area used by getgrent */
530Sstevel@tonic-gate
540Sstevel@tonic-gate char des_inbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest read size */
550Sstevel@tonic-gate char des_outbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest write size */
560Sstevel@tonic-gate krb5_data desinbuf, desoutbuf;
570Sstevel@tonic-gate krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
58*8175SPeter.Shoults@Sun.COM krb5_context bsd_context = NULL;
590Sstevel@tonic-gate krb5_auth_context auth_context;
600Sstevel@tonic-gate krb5_creds *cred;
610Sstevel@tonic-gate char *krb_cache = NULL;
620Sstevel@tonic-gate krb5_flags authopts;
630Sstevel@tonic-gate krb5_error_code status;
640Sstevel@tonic-gate enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;
650Sstevel@tonic-gate
660Sstevel@tonic-gate int encrypt_flag = 0; /* Flag set when encryption is used */
670Sstevel@tonic-gate int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */
68*8175SPeter.Shoults@Sun.COM static profile_options_boolean autologin_option[] = {
69*8175SPeter.Shoults@Sun.COM { "autologin", &krb5auth_flag, 0 },
70*8175SPeter.Shoults@Sun.COM { NULL, NULL, 0 }
71*8175SPeter.Shoults@Sun.COM };
72*8175SPeter.Shoults@Sun.COM static int no_krb5auth_flag = 0;
73*8175SPeter.Shoults@Sun.COM
740Sstevel@tonic-gate int debug_port = 0;
750Sstevel@tonic-gate
760Sstevel@tonic-gate int retval = 0;
770Sstevel@tonic-gate char *krb_realm = NULL;
780Sstevel@tonic-gate
790Sstevel@tonic-gate /* Flag set, if -PN / -PO is specified */
800Sstevel@tonic-gate static boolean_t rcmdoption_done = B_FALSE;
810Sstevel@tonic-gate
820Sstevel@tonic-gate static int encrypt_done = 0; /* Flag set, if -x is specified */
830Sstevel@tonic-gate profile_options_boolean option[] = {
840Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 },
850Sstevel@tonic-gate { NULL, NULL, 0 }
860Sstevel@tonic-gate };
870Sstevel@tonic-gate
880Sstevel@tonic-gate static char *rcmdproto = NULL;
890Sstevel@tonic-gate profile_option_strings rcmdversion[] = {
900Sstevel@tonic-gate { "rcmd_protocol", &rcmdproto, 0 },
910Sstevel@tonic-gate { NULL, NULL, 0 }
920Sstevel@tonic-gate };
930Sstevel@tonic-gate
940Sstevel@tonic-gate char *realmdef[] = { "realms", NULL, "rdist", NULL };
950Sstevel@tonic-gate char *appdef[] = { "appdefaults", "rdist", NULL };
960Sstevel@tonic-gate
97473Sbw static void usage(void);
98473Sbw static char *prtype(int t);
99473Sbw static void prsubcmd(struct subcmd *s);
100473Sbw static void docmdargs(int nargs, char *args[]);
101473Sbw void prnames();
102473Sbw void prcmd();
103473Sbw
1040Sstevel@tonic-gate int
main(argc,argv)1050Sstevel@tonic-gate main(argc, argv)
1060Sstevel@tonic-gate int argc;
1070Sstevel@tonic-gate char *argv[];
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate register char *arg;
1100Sstevel@tonic-gate int cmdargs = 0;
1110Sstevel@tonic-gate char *dhosts[NHOSTS], **hp = dhosts;
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate pw = getpwuid(getuid());
1160Sstevel@tonic-gate if (pw == NULL) {
1170Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Who are you?\n"), argv[0]);
1180Sstevel@tonic-gate exit(1);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate strncpy(user, pw->pw_name, sizeof (user));
1210Sstevel@tonic-gate user[sizeof (user) - 1] = '\0';
1220Sstevel@tonic-gate strncpy(homedir, pw->pw_dir, sizeof (homedir));
1230Sstevel@tonic-gate homedir[sizeof (homedir) - 1] = '\0';
1240Sstevel@tonic-gate gethostname(host, sizeof (host));
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate while (--argc > 0) {
1270Sstevel@tonic-gate if ((arg = *++argv)[0] != '-')
1280Sstevel@tonic-gate break;
1290Sstevel@tonic-gate if ((strcmp(arg, "-Server") == 0))
1300Sstevel@tonic-gate iamremote++;
1310Sstevel@tonic-gate else while (*++arg) {
1320Sstevel@tonic-gate if (strncmp(*argv, "-PO", 3) == 0) {
1330Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) {
1340Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist: "
1350Sstevel@tonic-gate "Only one of -PN "
1360Sstevel@tonic-gate "and -PO allowed.\n"));
1370Sstevel@tonic-gate usage();
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL;
1400Sstevel@tonic-gate krb5auth_flag++;
1410Sstevel@tonic-gate rcmdoption_done = B_TRUE;
1420Sstevel@tonic-gate break;
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate if (strncmp(*argv, "-PN", 3) == 0) {
1450Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) {
1460Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist: "
1470Sstevel@tonic-gate "Only one of -PN "
1480Sstevel@tonic-gate "and -PO allowed.\n"));
1490Sstevel@tonic-gate usage();
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL;
1520Sstevel@tonic-gate krb5auth_flag++;
1530Sstevel@tonic-gate rcmdoption_done = B_TRUE;
1540Sstevel@tonic-gate break;
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate switch (*arg) {
1580Sstevel@tonic-gate #ifdef DEBUG
1590Sstevel@tonic-gate case 'p':
1600Sstevel@tonic-gate if (--argc <= 0)
1610Sstevel@tonic-gate usage();
1620Sstevel@tonic-gate debug_port = htons(atoi(*++argv));
1630Sstevel@tonic-gate break;
1640Sstevel@tonic-gate #endif /* DEBUG */
1650Sstevel@tonic-gate case 'k':
1660Sstevel@tonic-gate if (--argc <= 0) {
1670Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist: "
1680Sstevel@tonic-gate "-k flag must be followed with "
1690Sstevel@tonic-gate " a realm name.\n"));
1700Sstevel@tonic-gate exit(1);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate if ((krb_realm = strdup(*++argv)) == NULL) {
1730Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist: "
1740Sstevel@tonic-gate "Cannot malloc.\n"));
1750Sstevel@tonic-gate exit(1);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate krb5auth_flag++;
1780Sstevel@tonic-gate break;
1790Sstevel@tonic-gate
180*8175SPeter.Shoults@Sun.COM case 'K':
181*8175SPeter.Shoults@Sun.COM no_krb5auth_flag++;
182*8175SPeter.Shoults@Sun.COM break;
183*8175SPeter.Shoults@Sun.COM
1840Sstevel@tonic-gate case 'a':
1850Sstevel@tonic-gate krb5auth_flag++;
1860Sstevel@tonic-gate break;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate case 'x':
1890Sstevel@tonic-gate encrypt_flag++;
1900Sstevel@tonic-gate encrypt_done++;
1910Sstevel@tonic-gate krb5auth_flag++;
1920Sstevel@tonic-gate break;
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate case 'f':
1950Sstevel@tonic-gate if (--argc <= 0)
1960Sstevel@tonic-gate usage();
1970Sstevel@tonic-gate distfile = *++argv;
1980Sstevel@tonic-gate if (distfile[0] == '-' && distfile[1] == '\0')
1990Sstevel@tonic-gate fin = stdin;
2000Sstevel@tonic-gate break;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate case 'm':
2030Sstevel@tonic-gate if (--argc <= 0)
2040Sstevel@tonic-gate usage();
2050Sstevel@tonic-gate if (hp >= &dhosts[NHOSTS-2]) {
2060Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist:"
2070Sstevel@tonic-gate " too many destination"
2080Sstevel@tonic-gate " hosts\n"));
2090Sstevel@tonic-gate exit(1);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate *hp++ = *++argv;
2120Sstevel@tonic-gate break;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate case 'd':
2150Sstevel@tonic-gate if (--argc <= 0)
2160Sstevel@tonic-gate usage();
2170Sstevel@tonic-gate define(*++argv);
2180Sstevel@tonic-gate break;
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate case 'D':
2210Sstevel@tonic-gate debug++;
2220Sstevel@tonic-gate break;
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate case 'c':
2250Sstevel@tonic-gate cmdargs++;
2260Sstevel@tonic-gate break;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate case 'n':
2290Sstevel@tonic-gate if (options & VERIFY) {
2300Sstevel@tonic-gate printf("rdist: -n overrides -v\n");
2310Sstevel@tonic-gate options &= ~VERIFY;
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate nflag++;
2340Sstevel@tonic-gate break;
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate case 'q':
2370Sstevel@tonic-gate qflag++;
2380Sstevel@tonic-gate break;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate case 'b':
2410Sstevel@tonic-gate options |= COMPARE;
2420Sstevel@tonic-gate break;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate case 'R':
2450Sstevel@tonic-gate options |= REMOVE;
2460Sstevel@tonic-gate break;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate case 'v':
2490Sstevel@tonic-gate if (nflag) {
2500Sstevel@tonic-gate printf("rdist: -n overrides -v\n");
2510Sstevel@tonic-gate break;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate options |= VERIFY;
2540Sstevel@tonic-gate break;
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate case 'w':
2570Sstevel@tonic-gate options |= WHOLE;
2580Sstevel@tonic-gate break;
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate case 'y':
2610Sstevel@tonic-gate options |= YOUNGER;
2620Sstevel@tonic-gate break;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate case 'h':
2650Sstevel@tonic-gate options |= FOLLOW;
2660Sstevel@tonic-gate break;
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate case 'i':
2690Sstevel@tonic-gate options |= IGNLNKS;
2700Sstevel@tonic-gate break;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate default:
2730Sstevel@tonic-gate usage();
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate *hp = NULL;
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate mktemp(Tmpfile);
2800Sstevel@tonic-gate
281*8175SPeter.Shoults@Sun.COM /*
282*8175SPeter.Shoults@Sun.COM * if the user disables krb5 on the cmdline (-K), then skip
283*8175SPeter.Shoults@Sun.COM * all krb5 setup.
284*8175SPeter.Shoults@Sun.COM *
285*8175SPeter.Shoults@Sun.COM * if the user does not disable krb5 or enable krb5 on the
286*8175SPeter.Shoults@Sun.COM * cmdline, check krb5.conf to see if it should be enabled.
287*8175SPeter.Shoults@Sun.COM */
288*8175SPeter.Shoults@Sun.COM
289*8175SPeter.Shoults@Sun.COM if (no_krb5auth_flag) {
290*8175SPeter.Shoults@Sun.COM krb5auth_flag = 0;
291*8175SPeter.Shoults@Sun.COM encrypt_flag = 0;
292*8175SPeter.Shoults@Sun.COM } else if (!krb5auth_flag) {
293*8175SPeter.Shoults@Sun.COM /* is autologin set in krb5.conf? */
2940Sstevel@tonic-gate status = krb5_init_context(&bsd_context);
295*8175SPeter.Shoults@Sun.COM /* don't sweat failure here */
296*8175SPeter.Shoults@Sun.COM if (!status) {
297*8175SPeter.Shoults@Sun.COM /*
298*8175SPeter.Shoults@Sun.COM * note that the call to profile_get_options_boolean
299*8175SPeter.Shoults@Sun.COM * with autologin_option can affect value of
300*8175SPeter.Shoults@Sun.COM * krb5auth_flag
301*8175SPeter.Shoults@Sun.COM */
302*8175SPeter.Shoults@Sun.COM (void) profile_get_options_boolean(bsd_context->profile,
303*8175SPeter.Shoults@Sun.COM appdef,
304*8175SPeter.Shoults@Sun.COM autologin_option);
305*8175SPeter.Shoults@Sun.COM }
306*8175SPeter.Shoults@Sun.COM }
307*8175SPeter.Shoults@Sun.COM
308*8175SPeter.Shoults@Sun.COM if (krb5auth_flag > 0) {
309*8175SPeter.Shoults@Sun.COM if (!bsd_context) {
310*8175SPeter.Shoults@Sun.COM status = krb5_init_context(&bsd_context);
311*8175SPeter.Shoults@Sun.COM if (status) {
312*8175SPeter.Shoults@Sun.COM com_err("rdist", status,
313*8175SPeter.Shoults@Sun.COM gettext("while initializing krb5"));
314*8175SPeter.Shoults@Sun.COM exit(1);
315*8175SPeter.Shoults@Sun.COM }
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /* Set up des buffers */
3190Sstevel@tonic-gate desinbuf.data = des_inbuf;
3200Sstevel@tonic-gate desoutbuf.data = des_outbuf;
3210Sstevel@tonic-gate desinbuf.length = sizeof (des_inbuf);
3220Sstevel@tonic-gate desoutbuf.length = sizeof (des_outbuf);
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate * Get our local realm to look up local realm options.
3260Sstevel@tonic-gate */
3270Sstevel@tonic-gate status = krb5_get_default_realm(bsd_context, &realmdef[1]);
3280Sstevel@tonic-gate if (status) {
3290Sstevel@tonic-gate com_err("rdist", status,
3300Sstevel@tonic-gate gettext("while getting default realm"));
3310Sstevel@tonic-gate exit(1);
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate * See if encryption should be done for this realm
3350Sstevel@tonic-gate */
3360Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, realmdef,
3370Sstevel@tonic-gate option);
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate * Check the appdefaults section
3400Sstevel@tonic-gate */
3410Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, appdef,
3420Sstevel@tonic-gate option);
3430Sstevel@tonic-gate profile_get_options_string(bsd_context->profile, appdef,
3440Sstevel@tonic-gate rcmdversion);
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate if ((encrypt_done > 0) || (encrypt_flag > 0)) {
3470Sstevel@tonic-gate if (krb5_privacy_allowed() == TRUE) {
3480Sstevel@tonic-gate encrypt_flag++;
3490Sstevel@tonic-gate } else {
3500Sstevel@tonic-gate (void) fprintf(stderr, gettext("rdist: "
3510Sstevel@tonic-gate "Encryption not supported.\n"));
3520Sstevel@tonic-gate exit(1);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) {
3570Sstevel@tonic-gate if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
3580Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL;
3590Sstevel@tonic-gate } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
3600Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL;
3610Sstevel@tonic-gate } else {
3620Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unrecognized "
3630Sstevel@tonic-gate "KCMD protocol (%s)"), rcmdproto);
3640Sstevel@tonic-gate exit(1);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate if (iamremote) {
3700Sstevel@tonic-gate setreuid(getuid(), getuid());
3710Sstevel@tonic-gate server();
3720Sstevel@tonic-gate exit(nerrs != 0);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
3750Sstevel@tonic-gate (void) fprintf(stderr,
3760Sstevel@tonic-gate "rdist needs to run with sufficient privilege\n");
3770Sstevel@tonic-gate exit(1);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate if (cmdargs)
3810Sstevel@tonic-gate docmdargs(argc, argv);
3820Sstevel@tonic-gate else {
3830Sstevel@tonic-gate if (fin == NULL) {
3840Sstevel@tonic-gate if (distfile == NULL) {
3850Sstevel@tonic-gate if ((fin = fopen("distfile", "r")) == NULL)
3860Sstevel@tonic-gate fin = fopen("Distfile", "r");
3870Sstevel@tonic-gate } else
3880Sstevel@tonic-gate fin = fopen(distfile, "r");
3890Sstevel@tonic-gate if (fin == NULL) {
3900Sstevel@tonic-gate perror(distfile ? distfile : "distfile");
3910Sstevel@tonic-gate exit(1);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate yyparse();
3950Sstevel@tonic-gate if (nerrs == 0)
3960Sstevel@tonic-gate docmds(dhosts, argc, argv);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
399473Sbw return (nerrs != 0);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
402473Sbw static void
usage()4030Sstevel@tonic-gate usage()
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate printf(gettext("Usage: rdist [-nqbhirvwyDax] [-PN / -PO] "
4060Sstevel@tonic-gate #ifdef DEBUG
4070Sstevel@tonic-gate "[-p port] "
4080Sstevel@tonic-gate #endif /* DEBUG */
4090Sstevel@tonic-gate "[-k realm] [-f distfile] [-d var=value] [-m host] [file ...]\n"));
4100Sstevel@tonic-gate printf(gettext("or: rdist [-nqbhirvwyDax] [-PN / -PO] [-p port] "
4110Sstevel@tonic-gate "[-k realm] -c source [...] machine[:dest]\n"));
4120Sstevel@tonic-gate exit(1);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate /*
4160Sstevel@tonic-gate * rcp like interface for distributing files.
4170Sstevel@tonic-gate */
418473Sbw static void
docmdargs(nargs,args)4190Sstevel@tonic-gate docmdargs(nargs, args)
4200Sstevel@tonic-gate int nargs;
4210Sstevel@tonic-gate char *args[];
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate register struct namelist *nl, *prev;
4240Sstevel@tonic-gate register char *cp;
4250Sstevel@tonic-gate struct namelist *files, *hosts;
4260Sstevel@tonic-gate struct subcmd *cmds;
4270Sstevel@tonic-gate char *dest;
4280Sstevel@tonic-gate static struct namelist tnl = { NULL, NULL };
4290Sstevel@tonic-gate int i;
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate if (nargs < 2)
4320Sstevel@tonic-gate usage();
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate prev = NULL;
4350Sstevel@tonic-gate for (i = 0; i < nargs - 1; i++) {
4360Sstevel@tonic-gate nl = makenl(args[i]);
4370Sstevel@tonic-gate if (prev == NULL)
4380Sstevel@tonic-gate files = prev = nl;
4390Sstevel@tonic-gate else {
4400Sstevel@tonic-gate prev->n_next = nl;
4410Sstevel@tonic-gate prev = nl;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate cp = args[i];
4460Sstevel@tonic-gate if ((dest = index(cp, ':')) != NULL)
4470Sstevel@tonic-gate *dest++ = '\0';
4480Sstevel@tonic-gate tnl.n_name = cp;
4490Sstevel@tonic-gate hosts = expand(&tnl, E_ALL);
4500Sstevel@tonic-gate if (nerrs)
4510Sstevel@tonic-gate exit(1);
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate if (dest == NULL || *dest == '\0')
4540Sstevel@tonic-gate cmds = NULL;
4550Sstevel@tonic-gate else {
4560Sstevel@tonic-gate cmds = makesubcmd(INSTALL);
4570Sstevel@tonic-gate cmds->sc_options = options;
4580Sstevel@tonic-gate cmds->sc_name = dest;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate if (debug) {
4620Sstevel@tonic-gate printf("docmdargs()\nfiles = ");
4630Sstevel@tonic-gate prnames(files);
4640Sstevel@tonic-gate printf("hosts = ");
4650Sstevel@tonic-gate prnames(hosts);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate insert(NULL, files, hosts, cmds);
4680Sstevel@tonic-gate docmds(NULL, 0, NULL);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate * Print a list of NAME blocks (mostly for debugging).
4730Sstevel@tonic-gate */
474473Sbw void
prnames(nl)4750Sstevel@tonic-gate prnames(nl)
4760Sstevel@tonic-gate register struct namelist *nl;
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate printf("( ");
4790Sstevel@tonic-gate while (nl != NULL) {
4800Sstevel@tonic-gate printf("%s ", nl->n_name);
4810Sstevel@tonic-gate nl = nl->n_next;
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate printf(")\n");
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
486473Sbw void
prcmd(c)4870Sstevel@tonic-gate prcmd(c)
4880Sstevel@tonic-gate struct cmd *c;
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate extern char *prtype();
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate while (c) {
4930Sstevel@tonic-gate printf("c_type %s, c_name %s, c_label %s, c_files ",
4940Sstevel@tonic-gate prtype(c->c_type), c->c_name,
4950Sstevel@tonic-gate c->c_label? c->c_label : "NULL");
4960Sstevel@tonic-gate prnames(c->c_files);
4970Sstevel@tonic-gate prsubcmd(c->c_cmds);
4980Sstevel@tonic-gate c = c->c_next;
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
502473Sbw static void
prsubcmd(s)5030Sstevel@tonic-gate prsubcmd(s)
5040Sstevel@tonic-gate struct subcmd *s;
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate extern char *prtype();
5070Sstevel@tonic-gate extern char *proptions();
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate while (s) {
5100Sstevel@tonic-gate printf("sc_type %s, sc_options %d%s, sc_name %s, sc_args ",
5110Sstevel@tonic-gate prtype(s->sc_type),
5120Sstevel@tonic-gate s->sc_options, proptions(s->sc_options),
5130Sstevel@tonic-gate s->sc_name ? s->sc_name : "NULL");
5140Sstevel@tonic-gate prnames(s->sc_args);
5150Sstevel@tonic-gate s = s->sc_next;
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate char *
prtype(t)5200Sstevel@tonic-gate prtype(t)
5210Sstevel@tonic-gate int t;
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate switch (t) {
5240Sstevel@tonic-gate case EQUAL:
5250Sstevel@tonic-gate return ("EQUAL");
5260Sstevel@tonic-gate case LP:
5270Sstevel@tonic-gate return ("LP");
5280Sstevel@tonic-gate case RP:
5290Sstevel@tonic-gate return ("RP");
5300Sstevel@tonic-gate case SM:
5310Sstevel@tonic-gate return ("SM");
5320Sstevel@tonic-gate case ARROW:
5330Sstevel@tonic-gate return ("ARROW");
5340Sstevel@tonic-gate case COLON:
5350Sstevel@tonic-gate return ("COLON");
5360Sstevel@tonic-gate case DCOLON:
5370Sstevel@tonic-gate return ("DCOLON");
5380Sstevel@tonic-gate case NAME:
5390Sstevel@tonic-gate return ("NAME");
5400Sstevel@tonic-gate case STRING:
5410Sstevel@tonic-gate return ("STRING");
5420Sstevel@tonic-gate case INSTALL:
5430Sstevel@tonic-gate return ("INSTALL");
5440Sstevel@tonic-gate case NOTIFY:
5450Sstevel@tonic-gate return ("NOTIFY");
5460Sstevel@tonic-gate case EXCEPT:
5470Sstevel@tonic-gate return ("EXCEPT");
5480Sstevel@tonic-gate case PATTERN:
5490Sstevel@tonic-gate return ("PATTERN");
5500Sstevel@tonic-gate case SPECIAL:
5510Sstevel@tonic-gate return ("SPECIAL");
5520Sstevel@tonic-gate case OPTION:
5530Sstevel@tonic-gate return ("OPTION");
5540Sstevel@tonic-gate }
555473Sbw return (NULL);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate char *
proptions(o)5590Sstevel@tonic-gate proptions(o)
5600Sstevel@tonic-gate int o;
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate return (printb((unsigned short) o, OBITS));
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate char *
printb(v,bits)5660Sstevel@tonic-gate printb(v, bits)
5670Sstevel@tonic-gate register char *bits;
5680Sstevel@tonic-gate register unsigned short v;
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate register int i, any = 0;
5710Sstevel@tonic-gate register char c;
5720Sstevel@tonic-gate char *p = buf;
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate bits++;
5750Sstevel@tonic-gate if (bits) {
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate *p++ = '<';
5780Sstevel@tonic-gate while ((i = *bits++) != 0) {
5790Sstevel@tonic-gate if (v & (1 << (i-1))) {
5800Sstevel@tonic-gate if (any)
5810Sstevel@tonic-gate *p++ = ',';
5820Sstevel@tonic-gate any = 1;
5830Sstevel@tonic-gate for (; (c = *bits) > 32; bits++)
5840Sstevel@tonic-gate *p++ = c;
5850Sstevel@tonic-gate } else
5860Sstevel@tonic-gate for (; *bits > 32; bits++)
5870Sstevel@tonic-gate ;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate *p++ = '>';
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate *p = '\0';
5930Sstevel@tonic-gate return (buf);
5940Sstevel@tonic-gate }
595