xargs fornece um comando xargs -P 0
, o documento menciona que gera tantos processos quanto possível para executar os comandos em paralelo. Mas está parando, por exemplo, no número de CPU disponível ou literalmente em várias dezenas de milhares de threads? Se for a segunda opção, não é menos eficiente do que gerar o número de threads de CPU? Acho que mudar constantemente entre processos pode levar um tempo não negligenciável, certo?
tobiasBora's questions
Eu gostaria de falsificar um sistema FHS em um sistema não FHS (NixOs) sem acesso root. Para esse fim, preciso montar algumas pastas na raiz (como montar /tmp/mylib
em /lib
) usando usernamespaces (não vejo outra solução).
Infelizmente, não consigo encontrar como fazê-lo funcionar: tentei seguir este tutorial , mas quando copio o código ele falha (não consigo nem iniciar um bash):
$ gcc userns_child_exec.c -lcap -o userns_child_exec
$ id
uid=1000(myname) gid=100(users) groups=100(users),1(wheel),17(audio),20(lp),57(networkmanager),59(scanner),131(docker),998(vboxusers),999(adbusers)
$ ./userns_child_exec -U -M '0 1000 1' -G '0 100 1' bash
write /proc/535313/gid_map: Operation not permitted
bash: initialize_job_control: no job control in background: Bad file descriptor
[nix-shell:~/Documents/Logiciels/Nix_bidouille/2022_04_26_-_nix_fake_FHS_user_namespace/demo]$
[root@bestos:~/Documents/Logiciels/Nix_bidouille/2022_04_26_-_nix_fake_FHS_user_namespace/demo]#
exit
(observe que o prompt para o bash é exibido, mas não consigo digitar nada, ele fecha diretamente)
Alguma ideia de como fazer isso funcionar?
Código:
/* userns_child_exec.c
Copyright 2013, Michael Kerrisk
Licensed under GNU General Public License v2 or later
Create a child process that executes a shell command in new
namespace(s); allow UID and GID mappings to be specified when
creating a user namespace.
*/
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
/* A simple error-handling function: print an error message based
on the value in 'errno' and terminate the calling process */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
struct child_args {
char **argv; /* Command to be executed by child, with arguments */
int pipe_fd[2]; /* Pipe used to synchronize parent and child */
};
static int verbose;
static void
usage(char *pname)
{
fprintf(stderr, "Usage: %s [options] cmd [arg...]\n\n", pname);
fprintf(stderr, "Create a child process that executes a shell command "
"in a new user namespace,\n"
"and possibly also other new namespace(s).\n\n");
fprintf(stderr, "Options can be:\n\n");
#define fpe(str) fprintf(stderr, " %s", str);
fpe("-i New IPC namespace\n");
fpe("-m New mount namespace\n");
fpe("-n New network namespace\n");
fpe("-p New PID namespace\n");
fpe("-u New UTS namespace\n");
fpe("-U New user namespace\n");
fpe("-M uid_map Specify UID map for user namespace\n");
fpe("-G gid_map Specify GID map for user namespace\n");
fpe(" If -M or -G is specified, -U is required\n");
fpe("-v Display verbose messages\n");
fpe("\n");
fpe("Map strings for -M and -G consist of records of the form:\n");
fpe("\n");
fpe(" ID-inside-ns ID-outside-ns len\n");
fpe("\n");
fpe("A map string can contain multiple records, separated by commas;\n");
fpe("the commas are replaced by newlines before writing to map files.\n");
exit(EXIT_FAILURE);
}
/* Update the mapping file 'map_file', with the value provided in
'mapping', a string that defines a UID or GID mapping. A UID or
GID mapping consists of one or more newline-delimited records
of the form:
ID_inside-ns ID-outside-ns length
Requiring the user to supply a string that contains newlines is
of course inconvenient for command-line use. Thus, we permit the
use of commas to delimit records in this string, and replace them
with newlines before writing the string to the file. */
static void
update_map(char *mapping, char *map_file)
{
int fd, j;
size_t map_len; /* Length of 'mapping' */
/* Replace commas in mapping string with newlines */
map_len = strlen(mapping);
for (j = 0; j < map_len; j++)
if (mapping[j] == ',')
mapping[j] = '\n';
fd = open(map_file, O_RDWR);
if (fd == -1) {
fprintf(stderr, "open %s: %s\n", map_file, strerror(errno));
exit(EXIT_FAILURE);
}
if (write(fd, mapping, map_len) != map_len) {
fprintf(stderr, "write %s: %s\n", map_file, strerror(errno));
exit(EXIT_FAILURE);
}
close(fd);
}
static int /* Start function for cloned child */
childFunc(void *arg)
{
struct child_args *args = (struct child_args *) arg;
char ch;
/* Wait until the parent has updated the UID and GID mappings. See
the comment in main(). We wait for end of file on a pipe that will
be closed by the parent process once it has updated the mappings. */
close(args->pipe_fd[1]); /* Close our descriptor for the write end
of the pipe so that we see EOF when
parent closes its descriptor */
if (read(args->pipe_fd[0], &ch, 1) != 0) {
fprintf(stderr, "Failure in child: read from pipe returned != 0\n");
exit(EXIT_FAILURE);
}
/* Execute a shell command */
execvp(args->argv[0], args->argv);
errExit("execvp");
}
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE]; /* Space for child's stack */
int
main(int argc, char *argv[])
{
int flags, opt;
pid_t child_pid;
struct child_args args;
char *uid_map, *gid_map;
char map_path[PATH_MAX];
/* Parse command-line options. The initial '+' character in
the final getopt() argument prevents GNU-style permutation
of command-line options. That's useful, since sometimes
the 'command' to be executed by this program itself
has command-line options. We don't want getopt() to treat
those as options to this program. */
flags = 0;
verbose = 0;
gid_map = NULL;
uid_map = NULL;
while ((opt = getopt(argc, argv, "+imnpuUM:G:v")) != -1) {
switch (opt) {
case 'i': flags |= CLONE_NEWIPC; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': flags |= CLONE_NEWPID; break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'v': verbose = 1; break;
case 'M': uid_map = optarg; break;
case 'G': gid_map = optarg; break;
case 'U': flags |= CLONE_NEWUSER; break;
default: usage(argv[0]);
}
}
/* -M or -G without -U is nonsensical */
if ((uid_map != NULL || gid_map != NULL) &&
!(flags & CLONE_NEWUSER))
usage(argv[0]);
args.argv = &argv[optind];
/* We use a pipe to synchronize the parent and child, in order to
ensure that the parent sets the UID and GID maps before the child
calls execve(). This ensures that the child maintains its
capabilities during the execve() in the common case where we
want to map the child's effective user ID to 0 in the new user
namespace. Without this synchronization, the child would lose
its capabilities if it performed an execve() with nonzero
user IDs (see the capabilities(7) man page for details of the
transformation of a process's capabilities during execve()). */
if (pipe(args.pipe_fd) == -1)
errExit("pipe");
/* Create the child in new namespace(s) */
child_pid = clone(childFunc, child_stack + STACK_SIZE,
flags | SIGCHLD, &args);
if (child_pid == -1)
errExit("clone");
/* Parent falls through to here */
if (verbose)
printf("%s: PID of child created by clone() is %ld\n",
argv[0], (long) child_pid);
/* Update the UID and GID maps in the child */
if (uid_map != NULL) {
snprintf(map_path, PATH_MAX, "/proc/%ld/uid_map",
(long) child_pid);
update_map(uid_map, map_path);
}
if (gid_map != NULL) {
snprintf(map_path, PATH_MAX, "/proc/%ld/gid_map",
(long) child_pid);
update_map(gid_map, map_path);
}
/* Close the write end of the pipe, to signal to the child that we
have updated the UID and GID maps */
close(args.pipe_fd[1]);
if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */
errExit("waitpid");
if (verbose)
printf("%s: terminating\n", argv[0]);
exit(EXIT_SUCCESS);
}
EDITAR
Na verdade, é bem estranho: o erro aparece ao escrever o grupo, mas funcionou para o uid:
[leo@bestos:~]$ cat /proc/582197/gid_map
[leo@bestos:~]$ cat /proc/582197/uid_map
0 1000 1
[leo@bestos:~]$ ll /proc/582197/gid_map
-rw-r--r-- 1 leo users 0 mai 18 09:09 /proc/582197/gid_map
[leo@bestos:~]$ ll /proc/582197/uid_map
-rw-r--r-- 1 leo users 0 mai 18 09:09 /proc/582197/uid_map
É possível (no ext4 clássico e/ou em qualquer outro sistema de arquivos) criar dois arquivos que apontem para o mesmo conteúdo, de modo que, se um arquivo for modificado, o conteúdo seja duplicado e os dois arquivos se tornem diferentes? Seria muito prático economizar espaço no meu disco rígido.
Contexto: Tenho alguns vídeos pesados que compartilho em um servidor de nuvem próprio que podem ser modificados por muitas pessoas e, portanto, pode ser possível que algumas pessoas modifiquem/removam esses arquivos... Eu realmente gostaria de ter certeza de que tenho um backup desses arquivos e, portanto, preciso manter dois diretórios, o nextcloud normal e um diretório "backup", que (pelo menos) dobra o tamanho necessário para armazená-lo.
Eu estava pensando em criar um repositório git no topo do diretório nextcloud, e isso tornaria o processo de backup muito mais fácil quando novos vídeos são adicionados (apenas git add .
), mas git
ainda dobra o espaço entre o blob e o diretório de trabalho.
Idealmente, uma solução que possa ser combinada com o git seria incrível (ou seja, que me permita criar um histórico das alterações de vídeo, com commits, checkouts... sem dobrar o espaço em disco.
Além disso, estou curioso para ter solução para vários sistemas de arquivos (especialmente se você tiver truques para sistemas de arquivos que não implementam snapshots). Observe que o instantâneo do LVM não é realmente uma solução, pois não quero fazer backup do meu volume completo, apenas de alguns arquivos/pastas específicos.
Obrigado!
Eu tenho usado uma chave ssh por um tempo abrindo-a usando o agente gpg. Eu me lembro da senha do agente gpg, mas não me lembro da chave ssh.
Como eu poderia recuperar a chave ssh do agente gpg?
Quais são os diferentes métodos para executar um executável não-nixos no NixOs? (Por exemplo, binários proprietários.) Eu gostaria de ver também os métodos manuais.
No incrível nixos , é possível lançar um container leve que irá rodar um sistema cujo configuration.nix
arquivo é diferente da configuração do host compilando primeiro usando:
$ nixos-rebuild build-vm -I nixos-config=./configuration.nix
e rodando por:
$ ./result/bin/run-*-vm
No entanto, o primeiro comando não pode funcionar em sistemas operacionais onde o nixos não está instalado, como debian + nixpkgs , porque nixos-rebuild
não existe.
Como ainda posso usar build-vm
em sistemas não nixos?
Acabei de comprar o tablet gráfico VEIKK A30. O mouse é reconhecido diretamente. Infelizmente, não consigo encontrar como habilitar a sensibilidade à pressão no Linux. Eu vi um cara relatando que com alguns ajustes foi possível fazer funcionar, mas não consigo encontrar nenhuma referência sobre isso.
Edit: aqui está a saída do dmesg
[mars19 01:15] usb 2-1: new full-speed USB device number 10 using xhci_hcd
[ +0,153026] usb 2-1: New USB device found, idVendor=2feb, idProduct=0002, bcdDevice= 0.00
[ +0,000006] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ +0,000004] usb 2-1: Product: A30
[ +0,000003] usb 2-1: Manufacturer: VEIKK.INC
[ +0,000004] usb 2-1: SerialNumber: 0000001
[ +0,003052] input: VEIKK.INC A30 Mouse as /devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.0/0003:2FEB:0002.000C/input/input64
[ +0,064250] input: VEIKK.INC A30 as /devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.0/0003:2FEB:0002.000C/input/input65
[ +0,000429] hid-generic 0003:2FEB:0002.000C: input,hidraw0: USB HID v1.00 Mouse [VEIKK.INC A30] on usb-0000:00:14.0-1/input0
[ +0,001079] input: VEIKK.INC A30 as /devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1:1.1/0003:2FEB:0002.000D/input/input66
[ +0,062599] hid-generic 0003:2FEB:0002.000D: input,hidraw1: USB HID v1.00 Keyboard [VEIKK.INC A30] on usb-0000:00:14.0-1/input1
[ +0,001208] hid-generic 0003:2FEB:0002.000E: hiddev0,hidraw2: USB HID v1.00 Device [VEIKK.INC A30] on usb-0000:00:14.0-1/input2
Edit2: hum, parece que o dispositivo que envia a pressão pode ser lido, sudo cat /dev/hidraw0
pois os padrões diferem dependendo da pressão que aplico. Eu não sei como ler este binário ^^ Se eu puder, talvez eu possa usar uinput para mapeá-lo para um novo dispositivo? ^^ Observe que /dev/input
contém arquivos como mouseX, eventY e mouse1 está correlacionado com o tablet, mas não com a pressão, e o único arquivo nesta pasta que exibe muitas informações vinculadas ao tablet é o arquivo /dev/input/by-id/usb-VEIKK.INC_A30_0000001-event-mouse
. Mas é menos claro que os padrões correspondem à pressão, muitas informações são enviadas aqui. Se você souber como analisá-los me avise!
Edit3: Então eu ainda não tenho um driver, mas pelo menos parece ser fácil ler a entrada da comunicação bruta do dispositivo. Eu fiz este script python como uma prova de conceito:
#!/usr/bin/env python3
import struct
PRINT_TIMESTAMP = True
# Open the file in the read-binary mode
f = open("/dev/input/by-id/usb-VEIKK.INC_A30_0000001-event-mouse", "rb" )
while 1:
data = f.read(24)
# print struct.unpack('4IHHI',data)
###### FORMAT = ( Time Stamp_INT , 0 , Time Stamp_DEC , 0 ,
###### type , code ( key pressed ) , value (press/release) )
time_int, _, time_dec, _, ev_type, ev_code, ev_val = struct.unpack('4IHHI',data)
t = (ev_type, ev_code)
if ((t == (0,0) and ev_val == 0)
or (t == (4, 4) and ev_val >= 589825 and ev_val <= 589827)):
# Redundant as it's for normal/bottom/top clicks
# (same code for press/release), or just garbage 0,0,0
continue
if PRINT_TIMESTAMP:
print("[{:.2f}] ".format(time_int + time_dec/1e6),
end="", flush=True)
if t == (3,0):
print("Pos x: {} ({:.2f}%)".format(ev_val, 100*ev_val/32767), flush=True)
elif t == (3,1):
print("Pos y: {} ({:.2f}%)".format(ev_val, 100*ev_val/32767), flush=True)
elif t == (3,24):
print("Pression: {} ({:.2f}%)".format(ev_val, 100*ev_val/8191), flush=True)
elif t == (1,272):
print("Normal click ({})".format("press" if ev_val else "release"), flush=True)
elif t == (1,273):
print("click button 2 (bottom) ({})".format("press" if ev_val else "release"), flush=True)
elif t == (1,274):
print("click button 3 (top) ({})".format("press" if ev_val else "release"), flush=True)
else:
print("Unknow: type={}, code={}, value={}".format(ev_type, ev_code, ev_val), flush=True)
Demonstração:
[1553182025.55] Pos y: 11458 (34.97%)
[1553182025.55] Pos x: 14310 (43.67%)
[1553182025.56] Pos x: 14314 (43.68%)
[1553182025.56] Pos x: 14318 (43.70%)
[1553182025.57] Pos x: 14321 (43.71%)
[1553182025.57] Normal click (press)
[1553182025.57] Pos x: 14323 (43.71%)
[1553182025.57] Pression: 1122 (13.70%)
[1553182025.57] Pos x: 14326 (43.72%)
[1553182025.57] Pos y: 11466 (34.99%)
[1553182025.57] Pression: 1260 (15.38%)
[1553182025.58] Pos x: 14329 (43.73%)
[1553182025.58] Pression: 1337 (16.32%)
[1553182025.58] Pos x: 14330 (43.73%)
[1553182025.58] Pos y: 11494 (35.08%)
[1553182025.58] Pression: 1515 (18.50%)
[1553182025.59] Pos y: 11506 (35.11%)
[1553182025.59] Pression: 1687 (20.60%)
[1553182025.59] Pos y: 11517 (35.15%)
[1553182025.59] Pression: 1689 (20.62%)
[1553182025.59] Pos y: 11529 (35.18%)
[1553182025.59] Pression: 1789 (21.84%)
[1553182025.60] Pos y: 11536 (35.21%)
[1553182025.60] Pression: 1829 (22.33%)
[1553182025.60] Pos y: 11542 (35.22%)
[1553182025.60] Pression: 1907 (23.28%)
[1553182025.61] Pression: 2031 (24.80%)
[1553182025.61] Pos y: 11549 (35.25%)
[1553182025.61] Pression: 2140 (26.13%)
Edit 4: Página incrível: https://digimend.github.io/support/howto/trbl/locating_failure/ No entanto, tudo funciona aqui ... exceto na última etapa, quando quero testá-lo. Tentei testar com o MyPaint, e não detecta pressão.
Eu também tentei fazer meu próprio código que basicamente copia a entrada do arquivo de evento para um novo dispositivo assim:
#!/usr/bin/env python3
import sys
import libevdev
import time
def print_capabilities(l):
v = l.driver_version
print("Input driver version is {}.{}.{}".format(v >> 16, (v >> 8) & 0xff, v & 0xff))
id = l.id
print("Input device ID: bus {:#x} vendor {:#x} product {:#x} version {:#x}".format(
id["bustype"],
id["vendor"],
id["product"],
id["version"],
))
print("Input device name: {}".format(l.name))
print("Supported events:")
for t, cs in l.evbits.items():
print(" Event type {} ({})".format(t.value, t.name))
for c in cs:
if t in [libevdev.EV_LED, libevdev.EV_SND, libevdev.EV_SW]:
v = l.value[c]
print(" Event code {} ({}) state {}".format(c.value, c.name, v))
else:
print(" Event code {} ({})".format(c.value, c.name))
if t == libevdev.EV_ABS:
a = l.absinfo[c]
print(" {:10s} {:6d}".format('Value', a.value))
print(" {:10s} {:6d}".format('Minimum', a.minimum))
print(" {:10s} {:6d}".format('Maximum', a.maximum))
print(" {:10s} {:6d}".format('Fuzz', a.fuzz))
print(" {:10s} {:6d}".format('Flat', a.flat))
print(" {:10s} {:6d}".format('Resolution', a.resolution))
print("Properties:")
for p in l.properties:
print(" Property type {} ({})".format(p.value, p.name))
def print_event(e):
print("Event: time {}.{:06d}, ".format(e.sec, e.usec), end='')
if e.matches(libevdev.EV_SYN):
if e.matches(libevdev.EV_SYN.SYN_MT_REPORT):
print("++++++++++++++ {} ++++++++++++".format(e.code.name))
elif e.matches(libevdev.EV_SYN.SYN_DROPPED):
print(">>>>>>>>>>>>>> {} >>>>>>>>>>>>".format(e.code.name))
else:
print("-------------- {} ------------".format(e.code.name))
else:
print("type {:02x} {} code {:03x} {:20s} value {:4d}".format(e.type.value, e.type.name, e.code.value, e.code.name, e.value))
def main(args):
path = args[1]
dev = libevdev.Device()
dev.name = "Combined Both Devices"
dev.enable(libevdev.EV_ABS.ABS_X,
libevdev.InputAbsInfo(minimum=0, maximum=32767))
dev.enable(libevdev.EV_ABS.ABS_Y,
libevdev.InputAbsInfo(minimum=0, maximum=32767))
dev.enable(libevdev.EV_ABS.ABS_Z,
libevdev.InputAbsInfo(minimum=0, maximum=8191))
dev.enable(libevdev.EV_ABS.ABS_0B,
libevdev.InputAbsInfo(minimum=0, maximum=8191))
dev.enable(libevdev.EV_ABS.ABS_DISTANCE,
libevdev.InputAbsInfo(minimum=0, maximum=8191))
dev.enable(libevdev.EV_ABS.ABS_PRESSURE,
libevdev.InputAbsInfo(minimum=0, maximum=8191))
dev.enable(libevdev.EV_MSC.MSC_SCAN)
dev.enable(libevdev.EV_KEY.BTN_LEFT)
dev.enable(libevdev.EV_KEY.BTN_RIGHT)
dev.enable(libevdev.EV_KEY.BTN_MIDDLE)
dev.enable(libevdev.EV_KEY.BTN_TOUCH)
dev.enable(libevdev.EV_SYN.SYN_REPORT)
dev.enable(libevdev.EV_SYN.SYN_CONFIG)
dev.enable(libevdev.EV_SYN.SYN_MT_REPORT)
dev.enable(libevdev.EV_SYN.SYN_DROPPED)
dev.enable(libevdev.EV_SYN.SYN_04)
dev.enable(libevdev.EV_SYN.SYN_05)
dev.enable(libevdev.EV_SYN.SYN_06)
dev.enable(libevdev.EV_SYN.SYN_07)
dev.enable(libevdev.EV_SYN.SYN_08)
dev.enable(libevdev.EV_SYN.SYN_09)
dev.enable(libevdev.EV_SYN.SYN_0A)
dev.enable(libevdev.EV_SYN.SYN_0B)
dev.enable(libevdev.EV_SYN.SYN_0C)
dev.enable(libevdev.EV_SYN.SYN_0D)
dev.enable(libevdev.EV_SYN.SYN_0E)
dev.enable(libevdev.EV_SYN.SYN_MAX)
try:
uinput = dev.create_uinput_device()
print("New device at {} ({})".format(uinput.devnode, uinput.syspath))
# Sleep for a bit so udev, libinput, Xorg, Wayland, ...
# all have had a chance to see the device and initialize
# it. Otherwise the event will be sent by the kernel but
# nothing is ready to listen to the device yet.
time.sleep(1)
with open(path, "rb") as fd:
l = libevdev.Device(fd)
print_capabilities(l)
print("################################\n"
"# Waiting for events #\n"
"################################")
while True:
try:
ev = l.events()
for e in ev:
uinput.send_events([e])
print_event(e)
if e.matches(libevdev.EV_ABS.ABS_PRESSURE):
print("Pressure! Will send another packeton Z axis!")
uinput.send_events([libevdev.InputEvent(libevdev.EV_ABS.ABS_Z, e.value)])
uinput.send_events([libevdev.InputEvent(libevdev.EV_ABS.ABS_0B, e.value)])
uinput.send_events([libevdev.InputEvent(libevdev.EV_ABS.ABS_DISTANCE, e.value)])
except libevdev.EventsDroppedException:
for e in l.sync():
print_event(e)
uinput.send_events([e])
except KeyboardInterrupt:
pass
except IOError as e:
import errno
if e.errno == errno.EACCES:
print("Insufficient permissions to access {}".format(path))
elif e.errno == errno.ENOENT:
print("Device {} does not exist".format(path))
else:
raise e
except OSError as e:
print(e)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: {} /dev/input/eventX".format(sys.argv[0]))
sys.exit(1)
main(sys.argv)
e percebi que é mais ou menos igual ao mouse Veikk, e não funciona melhor.
Estou tentando criar manualmente minha própria unidade USB personalizada, com vários arquivos ISO e uma partição para dados. Usei a instrução que coloquei aqui para criar minha chave, mas resumindo, fiz
- uma partição
/dev/sda1
para dados - uma partição
/dev/sda2
que tem o grub instalado - uma partição
/dev/sda3
que contém meus arquivos iso na pastalinux-iso/
Coloquei no arquivo grub2/grub/conf
(on /dev/sda2
) o seguinte arquivo:
insmod loopback
insmod iso9660
menuentry 'XUbuntu 16.04 "Xenial Xerus" -- amd64' {
set isofile="/linux-iso/xubuntu-16.04.1-desktop-amd64.iso"
search --no-floppy --set -f $isofile
loopback loop $isofile
linux (loop)/casper/vmlinuz.efi locale=fr_FR bootkbd=fr console-setup/layoutcode=fr iso-scan/filename=$isofile boot=casper persistent file=/cdrom/preseed/ubuntu.seed noprompt ro quiet splash noeject --
initrd (loop)/casper/initrd.lz
}
menuentry 'Debian 9.3.0 amd64 netinst test 3' {
set isofile="/linux-iso/debian-9.3.0-amd64-netinst.iso"
search --no-floppy --set -f $isofile
loopback loop $isofile
linux (loop)/install.amd/vmlinuz priority=low config fromiso=/dev/sdb3/$isofile
initrd (loop)/install.amd/initrd.gz
}
Assim, quando eu carrego o ubuntu tudo funciona muito bem... Mas quando eu carrego o debian ele falha na etapa "Configurar CD-Rom", com o erro:
Incorrect CD-ROM detected.
The CD-ROM drive contains a CD which cannot be used for installation.
Please insert a suitable CD to continue with the installation."
Eu também tentei montar /dev/sdb3
em /cdrom
, mas nesse caso tenho um erro na próxima etapa:
Load installer components from CD:
There was a problem reading data from the CD-ROM. Please make sure it is in the drive.
Failed to copy file from CD-ROM. Retry?"
Você sabe como resolver esse problema?
Obrigada!