[PATCH] Fix for rpcclient and getopt()...

Michael Sweet mike at easysw.com
Thu Mar 14 07:32:06 GMT 2002


All,

Attached is a patch against the current 2.2 CVS (I imagine it should
patch pretty cleanly against HEAD as well) to hopefully fix the
getopt() nightmare.

Some background: The rpcclient program requires the name of the
server to connect to.  In SAMBA 2.2.0 and 2.2.1, the first argument
had to contain the server name, while in 2.2.2 through 2.2.3a the
*last* argument had to contain the server name.  The current CVS
is back to the first argument again.  This wreaks havoc on third-
party programs like "cupsaddsmb" in CUPS which use rpcclient to
install printer drivers, for example.

The problem appears to stem from the use of the getopt() function,
which (unfortunately) comes in at least three flavors which operate
slightly differently.

The attached patch should work with all versions of getopt(), and
allows the server name to appear anywhere on the command-line, not
just as the first or last argument.  It also forces the POSIX
conventions when using GLIBC (you set an environment variable)
so that argv is not modified.

-- 
______________________________________________________________________
Michael Sweet, Easy Software Products                  mike at easysw.com
Printing Software for UNIX                       http://www.easysw.com
-------------- next part --------------
Index: rpcclient.c
===================================================================
RCS file: /cvsroot/samba/source/rpcclient/rpcclient.c,v
retrieving revision 1.120.4.29
diff -u -r1.120.4.29 rpcclient.c
--- rpcclient.c	26 Feb 2002 18:54:10 -0000	1.120.4.29
+++ rpcclient.c	14 Mar 2002 15:10:34 -0000
@@ -644,73 +644,95 @@
 	AllowDebugChange = False;
 
 	/* Parse options */
-	if (argc == 0) {
+	if (argc < 2) {
 		usage();
-		return 0;
+		return 1;
 	}
-	
-	if (strncmp("//", argv[1], 2) == 0 || strncmp("\\\\", argv[1], 2) == 0)
-		argv[1] += 2;
-
-	pstrcpy(server, argv[1]);
-
-	argv++;
-	argc--;
-
-	while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:l:h")) != EOF) {
-		switch (opt) {
-		case 'A':
-			/* only get the username, password, and domain from the file */
-			read_authfile (optarg, username, password, domain);
-			if (strlen (password))
-				got_pass = True;
-			break;
 
-		case 'c':
-			pstrcpy(cmdstr, optarg);
-			break;
-
-		case 'd':
-			DEBUGLEVEL = atoi(optarg);
-			break;
-
-		case 'l':
-			slprintf(logfile, sizeof(logfile) - 1, "%s.client", optarg);
-			lp_set_logfile(logfile);
-			interactive = False;
-			break;
-
-		case 'N':
-			got_pass = True;
-			break;
-			
-		case 's':
-			pstrcpy(servicesf, optarg);
-			break;
-
-		case 'U': {
-			char *lp;
-			pstrcpy(username,optarg);
-			if ((lp=strchr(username,'%'))) {
-				*lp = 0;
-				pstrcpy(password,lp+1);
+        /*
+	 * M. Sweet: getopt() behaves slightly differently on various
+	 * platforms.  The following loop ensures that the System V,
+	 * BSD, and Linux (glibc) implementations work similarly to
+	 * allow the server name anywhere on the command-line.
+	 *
+	 * GLIBC requires the "POSIXLY_CORRECT" environment variable to
+	 * be set to duplicate the POSIX semantics.  Sigh...
+	 */
+
+        putenv("POSIXLY_CORRECT=yes");
+
+	pstrcpy(server, "");
+
+        while (argc > optind) {
+		while ((opt = getopt(argc, argv, "A:s:Nd:U:W:c:l:h")) != EOF) {
+			switch (opt) {
+			case 'A':
+				/* only get the username, password, and domain from the file */
+				read_authfile (optarg, username, password, domain);
+				if (strlen (password))
+					got_pass = True;
+				break;
+
+			case 'c':
+				pstrcpy(cmdstr, optarg);
+				break;
+
+			case 'd':
+				DEBUGLEVEL = atoi(optarg);
+				break;
+
+			case 'l':
+				slprintf(logfile, sizeof(logfile) - 1, "%s.client", optarg);
+				lp_set_logfile(logfile);
+				interactive = False;
+				break;
+
+			case 'N':
 				got_pass = True;
-				memset(strchr(optarg,'%')+1,'X',strlen(password));
+				break;
+
+			case 's':
+				pstrcpy(servicesf, optarg);
+				break;
+
+			case 'U': {
+				char *lp;
+				pstrcpy(username,optarg);
+				if ((lp=strchr(username,'%'))) {
+					*lp = 0;
+					pstrcpy(password,lp+1);
+					got_pass = True;
+					memset(strchr(optarg,'%')+1,'X',strlen(password));
+				}
+				break;
+			}
+
+			case 'W':
+				pstrcpy(domain, optarg);
+				break;
+
+			case 'h':
+			default:
+				usage();
+				return 1;
 			}
-			break;
 		}
-		
-		case 'W':
-			pstrcpy(domain, optarg);
-			break;
-			
-		case 'h':
-		default:
-			usage();
-			exit(1);
+
+		if (argc > optind) {
+			if (strncmp("//", argv[optind], 2) == 0 ||
+			    strncmp("\\\\", argv[optind], 2) == 0)
+				argv[optind] += 2;
+
+			pstrcpy(server, argv[optind]);
+
+			optind ++;
 		}
 	}
 
+	if (!server[0]) {
+		usage();
+		return 1;
+	}
 
 	/* the following functions are part of the Samba debugging
 	   facilities.  See lib/debug.c */


More information about the samba-technical mailing list