No hay comando 'sudo' en Cygwin

41

Debido a que no hay un comando sudo en Cygwin , los scripts que quiero ejecutar fallan

./install.sh: line N: sudo: command not found

¿Cuál es la forma estándar de evitar esto? ¿Edición de los scripts para eliminar sudo? ¿Tienes alguna sudoherramienta similar para Windows?

Jason Sundram
fuente
@dotancohen, espero haber elegido el correcto.
Jason Sundram
¡Parece una buena solución para mí! ¡El apoyo de Cygwin ha mejorado en los últimos cinco años!
dotancohen
@Benj, me pregunto por qué esa pregunta no se migró aquí también.
Jason Sundram
@JasonSundram de hecho. Avíseme si se mueve la respuesta, luego actualizaré el enlace.
Benj

Respuestas:

8

Escribí el (bastante simple) TOUACExt de SUDO para CygWin , una concha de automatización de secuencia de comandos pre-beta que se acerca al comportamiento de los clásicos sudo para Linux:

  • Abre y cierra automáticamente sudoserver.py cuando es necesario.
  • Solicitud de aviso de elevación de UAC .

La instalación requiere copiar los cuatro .shscripts en algún directorio de ruta, crear un alias y solo algunos pasos más detallados en el hilo.

Los resultados : escribe uno sudo YourCommandy obtiene el resultado, sin tener que preocuparse por el resto del proceso.

Sopalajo de Arrierez
fuente
35

Una forma es crear un comando falso "sudo" con el siguiente contenido:

#!/usr/bin/bash

"$@"

Esto permitirá install.shque continúe, porque se encuentra sudo.

Esto no eleva los privilegios como lo hace el sudo real. Si realmente necesita privilegios elevados, inicie cygwin shell desde una cuenta con privilegios administrativos (XP) o haga clic en cygwin.bat y "ejecutar como administrador" (Vista, Win7)

Peón
fuente
55
Solo por curiosidad de alguien que no habla con fluidez bash: ¿Por qué funciona esto? La página de manual no dice nada sobre $@hacer algo sudoparecido. En cambio, son solo todos los argumentos del guión. ¿Y las citas a su alrededor no serían superfluas en ese caso? De lo contrario, si lo hicieras sudo foo bar, intenta ejecutarlo "foo bar"como un solo comando que probablemente no exista dado el miedo irracional a los espacios en sistemas similares a UNIX.
Joey
77
@Johannes: "$@"(con comillas dobles) funciona de manera diferente a "$*": se expande a una palabra separada para cada variable de posición. Ejemplo: Si $1 == "foo bar"y $2 == "baz", entonces "$@"es "foo bar" baz- una palabra para cada parámetro (a diferencia "$*", lo que resulta en "foo bar baz"una sola palabra). Consulte el manual de la bashsección Parámetros , subsección Parámetros especiales . El resultado final del guión de Peon es que ejecuta sus argumentos exactamente como fueron pasados.
Grawity
1
Ah ok ¿Y de dónde sudoviene la parte? El fragmento anterior no hace nada de forma remota en esa dirección, ¿verdad?
Joey
2
@Johannes: en Unix, un real sudoaumentaría los privilegios de mortal a rootantes de ejecutar el comando. En Cygwin, no existe tal cosa, por lo que el script falso de Peon (que se supone que debes nombrar sudo) simplemente ejecuta el comando directamente sin cambiar sus privilegios. (Esto significa que es posible que deba ejecutar ./install.shcomo Administrador)
Grawity
2
@grawity: runasdebería funcionar, no depende de UAC y solicita una contraseña por sí misma. Estaba confundido por qué el guión en la respuesta aparentemente no hizo lo que el nombre implicaba, lo cual asumí que era el objetivo. Perdón por mi estupidez ;-)
Joey
21

Encontré la respuesta en la lista de correo de cygwin . Para ejecutar commandcon privilegios elevados en Cygwin, preceda el comando de cygstart --action=runasesta manera:

$ cygstart --action=runas command

Esto abrirá un cuadro de diálogo de Windows solicitando la contraseña de administrador y ejecutará el comando si se ingresa la contraseña correcta.

Esto es fácil de escribir, siempre y cuando ~/binesté en su camino:

$ cat ~/bin/sudo
#!/usr/bin/bash
cygstart --action=runas "$@"

$ PATH=$HOME/bin:$PATH
$ chmod +x ~/bin/sudo
$ sudo elevatedCommand

Probado en Windows 8 de 64 bits.

dotancohen
fuente
55
El problema con el cygstartmétodo es que solo funciona para comandos / programas de Windows. No puedes hacer sudo ls. SUDO para CygWin es ordenado, pero aún le falta un buen sudodominio.
Sopalajo de Arrierez
Gracias Sopalajode. ¿En qué situación has necesitado usar sudo lsen Cygwin?
dotancohen
3
Oh, no, @Dotancohen, fue solo un ejemplo. Puede usar sudoCygWin para ejecutar cualquier comando de Windows o CygWin. Es muy útil para mí. Pero el método más práctico que he encontrado es este derivador de scripts para SUDO para CygWin he desarrollado: superuser.com/questions/741345/... (todavía en fase beta, pero parece que funciona). Con él puedes ordenar cómodamente cosas como sudo net start vncserver.
Sopalajo de Arrierez
@SopalajodeArrierez: ¡Eso es absolutamente fantástico! Gracias por la publicación y el enlace.
dotancohen
curiosamente, esto se quita /biny /usr/binde la PATH. Invoca con éxito emacs: ShellExecute(NULL, "runas", "C:\cygwin64\bin\emacs-w32.exe", "(null)", "(null)", 1)pero emacs no puede encontrar, lspor ejemplo M-x dired, incluso después de restaurar interactivamente la RUTA usando (setenv ...). ¿Hay un problema de rutas confiables aquí?
BaseZen
5

Sobre la base de la respuesta de dotancohen, estoy usando un alias:

alias sudo="cygstart --action=runas"

Funciona como un encanto para programas externos (sin embargo, no incorporados en shell):

sudo chown User:Group <file>
thoni56
fuente
3

Sudo (Elevate) para Windows ™

Hago mucho trabajo en la línea de comandos en Windows ™.

En el propio Cygwin, creo que puede ejecutar un comando raíz con su -c /the/cmdrespecto a sudo en el sistema de archivos de Windows ™ que eleva los permisos del usuario desde la línea de comandos. Si usted es un administrador, esto funcionará muy bien para usted. De lo contrario, use runas y obtenga el pase de administrador;).

Ahora no puedo recordar de dónde obtuvimos este código, pero aquí está. Espero que ayude.

Por cierto, el paquete que utilizamos para compilar esto fue gcc-mingw32.

$ i586-mingw32msvc-gcc sudo.c -o sudo.exe
# Put sudo.exe in /usr/bin or in your windows path (%homedrive%\windows)
#example:
$ sudo vi /cygdrive/c/windows/system32/drivers/etc/hosts

/**
* (sudo for Windows™)
* @filename sudo.c
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <shellapi.h>
#include <wchar.h>


LPWSTR *mergestrings(LPWSTR *left, LPCWSTR right)
{
    size_t size = ( 1 + lstrlen(*left) + lstrlen(right) ) * sizeof(LPWSTR*);
    if ( *left ) {
        LPWSTR leftcopy = _wcsdup(*left);
        *left = (LPWSTR)realloc(*left, size);
        *left = lstrcpy(*left, leftcopy);
        *left = lstrcat(*left, right);
        free( leftcopy );
    }
    else
        *left = _wcsdup(right);
    return left;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpcommand, int nShowCmd)
{
    DWORD result = 0x2a;
    LPWSTR *argv = NULL;
    int argc = 0;
    if ( argv = CommandLineToArgvW(GetCommandLineW(), &argc) ) {
        if ( argc < 2 ) {
            LPWSTR usagemsg = NULL;
            usagemsg = *mergestrings(&usagemsg, argv[0]);
            usagemsg = *mergestrings(&usagemsg, TEXT(" <command_to_run> [arguments]"));
            MessageBox(NULL, usagemsg, TEXT("Usage:"), MB_OK | MB_ICONEXCLAMATION );
            LocalFree( argv );
            free( usagemsg );
            return ERROR_BAD_ARGUMENTS;
        }
        else {
            LPWSTR command = argv[1];
            LPWSTR arguments = NULL;
            int c;
            for ( c = 2; c < argc; c++ ) {
                arguments = *mergestrings(&arguments, argv[c]);
                arguments = *mergestrings(&arguments, TEXT(" "));
            }
            result = (DWORD)ShellExecute(NULL, TEXT("runas"), command, arguments, NULL, SW_SHOWNORMAL);
            LocalFree( argv );
            if ( arguments )
                free( arguments );
            switch ( result )
            {
                case 0:
                    result = ERROR_OUTOFMEMORY;
                    break;

                case 27:
                case 31:
                    result = ERROR_NO_ASSOCIATION;
                    break;

                case 28:
                case 29:
                case 30:
                    result = ERROR_DDE_FAIL;
                    break;
                case 32:
                    result = ERROR_DLL_NOT_FOUND;
                    break;
                default:
                    if ( result > 32 )
                        result = 0x2a;
            }
        }
    }
    else
        result = GetLastError();

    if (result != 0x2a) {
        LPWSTR errormsg = NULL;
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
                      NULL, result, 0, (LPWSTR)&errormsg, 0, NULL);
        MessageBox(NULL, errormsg, TEXT("Error:"), MB_OK | MB_ICONERROR);
        LocalFree( errormsg );
        return result;
    }
    else
        return NO_ERROR;
}
tao
fuente
55
Este código es horrible Está lleno de errores como no verificar el valor de retorno de realloc () antes de desreferenciar o escribir sizeof (LPWSTR *) en lugar de sizeof (* LPWSTR) donde LPWSTR parece ser un tipo de puntero y uno quiere recuperar el tamaño de un carácter, no El tamaño del puntero. Además, no está totalmente claro por qué, por ejemplo, el caso 29 conduce a ERROR_DDE_FAIL. ¿Puedes concluir del código por qué? No puedo y supongo que nadie más también puede hacerlo. Por favor, no publique dicho código en el futuro.
44
@Mattew: por favor, en el futuro, ayude a la comunidad publicando una versión limpia del fragmento de código que no le guste.
Erik Allik
El código no debería estar en el superusuario. Póngalo en codereview.se, y solo enlácelo desde aquí.
Ben Voigt
@ user185282: buenos puntos. He rechazado la respuesta.
inolvidableid
Estimado tao: Usted escribió: "No recuerdo de dónde obtuvimos este código". ¿Escribiste este código o alguien más lo escribió?
inolvidableid
2

Una ligera mejora en el script de sudo falso de Peon :

#!/bin/sh
# Drop any option arguments.
while [[ $# -ge 0 && $1 = -* ]]; do
  shift
done

"$@"

Este script silenciosamente descarta cualquier opción pasada a sudo y ejecuta el comando (sin realmente elevar los privilegios). Descartar las opciones mejora un poco la compatibilidad. Un script de envoltura más completo debería analizar las opciones de la misma manera que sudo.

En lugar de tratar de reemplazar sudo con un contenedor que lo haga cygstart --action=runas "$@", simplemente use este simple contenedor falso de sudo y ejecute el script de instalación (o lo que esté intentando ejecutar que use sudo) con privilegios elevados.

Gene Pavlovsky
fuente