Compare commits

...

3 Commits

Author SHA1 Message Date
Jonas 'Sortie' Termansen e9d9eabb6e Add non-interactive mode to disked(8). 2023-04-23 23:35:08 +02:00
Jonas 'Sortie' Termansen b029127df5 Add passwd(1) -H option. 2023-04-23 23:35:08 +02:00
Jonas 'Sortie' Termansen c77745e447 Change chvidemode(1) to set requested mode instead of running command. 2023-04-22 19:54:40 +02:00
6 changed files with 246 additions and 135 deletions

View File

@ -6,7 +6,10 @@
.Nd disk editor
.Sh SYNOPSIS
.Nm disked
.Op Fl in
.Op Fl \-fstab Ns "=" Ns Ar path
.Op Ar device
.Op Ar command ...
.Sh DESCRIPTION
.Nm
is an interactive program that manages partition tables.
@ -19,17 +22,22 @@ supports the Master Boot Record and GUID Partition Table partitioning schemes.
.Pp
.Nm
provides an interactive command line.
Its prompt shows the currently selected device (defaulting to the first device
alphabetically) or
Its prompt shows the currently selected
.Ar device
(defaulting to the first device alphabetically if any) or
.Li (disked)
if none is selected.
If a
.Ar command
is specified on the command line, then that command is run with its arguments
non-interactively instead of reading from the standard input.
.Pp
Commands perform their actions when run rather than waiting for the user to
write out changes.
.Nm
only creates partitions aligned to 1 MiB boundaries whose size is a multiple of
1 MiB.
Unused regions are aligned and those smaller than the alignment are not shown.
.Pp
The options are as follows:
.Bl -tag -width "12345678"
.It Fl \-fstab Ns "=" Ns Ar path
@ -39,6 +47,17 @@ instead of
.Pa /etc/fstab
as
.Xr fstab 5 .
.It Fl i
Run in interactive mode with prompt with line editing.
Commands will ask for missing parameters.
This is the default if the standard input and output are terminals and a
.Ar command
is not specified on the command line.
.It Fl n
Run in non-interactive mode reading commands from the standard input.
Commands will not ask for missing parameters and
.Nm
will immediately exit unsuccessfully if any command fail.
.El
.Pp
The following commands are supported:
@ -78,14 +97,19 @@ Partitions are counted from 1.
Display this manual page if no operands are given, otherwise run
.Xr man 1
with the given command line.
.It Sy mkpart
.It Sy mkpart Ar hole Ar offset Ar length Ar filesystem Ar mountpoint
Create a partition on the current device.
If the partition table has multiple unused regions
.Pq holes ,
.Nm
asks you which one to use.
You need to specify the offset into the hole where the partition is created and
then the length of the partition.
asks you which
.Ar hole
(counting from 1) to use.
You need to specify the
.Ar offset
into the hole where the partition is created and
then the
.Ar length of the partition.
See
.Sx QUANTITIES
below on the possible partition offset and length values.
@ -106,7 +130,9 @@ Use the existing disk data.
.El
.Pp
If you format a mountable filesystem, then you will be asked if you want to
create a mountpoint for the partition, which will be added to
create a
.Ar mountpoint
for the partition, which will be added to
.Xr fstab 5 .
.It Sy mktable Oo mbr "|" gpt Oc
Create a partition table on the current device of the specified type.

View File

@ -240,6 +240,8 @@ static const char* device_name(const char* name)
return name;
}
static bool interactive;
static void display_rows_columns(char* (*format)(void*, size_t, size_t),
void* ctx, size_t rows, size_t columns)
{
@ -395,6 +397,8 @@ static void prompt(char* buffer,
const char* question,
const char* answer)
{
if ( !interactive )
errx(1, "Cannot ask question in non-interactive mode: %s", question);
while ( true )
{
printf("\e[1m");
@ -599,7 +603,6 @@ bool rewrite_finish(struct rewrite* rewr)
return true;
}
static bool interactive;
static bool quitting;
static struct harddisk** hds;
static size_t hds_count;
@ -1132,6 +1135,25 @@ static void switch_device(struct harddisk* hd)
scan_device();
}
static bool lookup_harddisk_by_string(struct harddisk** out,
const char* argv0,
const char* name)
{
for ( size_t i = 0; i < hds_count; i++ )
{
char buf[sizeof(i) * 3];
snprintf(buf, sizeof(buf), "%zu", i);
if ( strcmp(name, hds[i]->path) != 0 &&
strcmp(name, device_name(hds[i]->path)) != 0 &&
strcmp(name, buf) != 0 )
continue;
*out = hds[i];
return true;
}
command_errorx("%s: No such device `%s'", argv0, name);
return false;
}
static bool lookup_partition_by_string(struct partition** out,
const char* argv0,
const char* numstr)
@ -1573,8 +1595,6 @@ static char* display_hole_format(void* ctx, size_t row, size_t column)
static void on_mkpart(size_t argc, char** argv)
{
(void) argc;
(void) argv;
size_t num_holes = 0;
struct device_area* hole = NULL;
for ( size_t i = 0; i < current_areas_count; i++ )
@ -1598,8 +1618,11 @@ static void on_mkpart(size_t argc, char** argv)
char answer[sizeof(size_t) * 3];
while ( true )
{
prompt(answer, sizeof(answer),
"Which hole to create the partition inside?", "1");
if ( 2 <= argc )
strlcpy(answer, argv[1], sizeof(answer));
else
prompt(answer, sizeof(answer),
"Which hole to create the partition inside?", "1");
char* end;
unsigned long num = strtoul(answer, &end, 10);
if ( *end || num_holes < num )
@ -1618,7 +1641,8 @@ static void on_mkpart(size_t argc, char** argv)
}
break;
}
printf("\n");
if ( argc < 2 )
printf("\n");
}
unsigned int slot = 0;
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended )
@ -1678,54 +1702,68 @@ static void on_mkpart(size_t argc, char** argv)
assert(start_str); // TODO: Error handling.
char* length_str = format_bytes_amount((uintmax_t) hole->length);
assert(length_str); // TODO: Error handling.
printf("Creating partition inside hole at %s of length %s (100%%)\n",
start_str, length_str);
if ( argc < 3 )
printf("Creating partition inside hole at %s of length %s (100%%)\n",
start_str, length_str);
free(start_str);
free(length_str);
off_t start;
while ( true )
{
char answer[256];
prompt(answer, sizeof(answer),
"Free space before partition? (42%/15G/...)", "0%");
if ( 3 <= argc )
strlcpy(answer, argv[2], sizeof(answer));
else
prompt(answer, sizeof(answer),
"Free space before partition? (42%/15G/...)", "0%");
if ( !parse_disk_quantity(&start, answer, hole->length) )
{
fprintf(stderr, "Invalid quantity `%s'.\n", answer);
command_errorx("%s: %s: Invalid quantity: %s",
argv[0], device_name(current_hd->path), answer);
continue;
}
if ( start == hole->length )
{
fprintf(stderr, "Answer was all free space, but need space for the "
"partition itself.\n");
command_errorx("%s: %s: Answer was all free space, but need space "
"for the partition itself",
argv[0], device_name(current_hd->path));
continue;
}
break;
}
printf("\n");
if ( argc < 3 )
printf("\n");
off_t max_length = hole->length - start;
off_t length;
length_str = format_bytes_amount((uintmax_t) max_length);
assert(length_str);
printf("Partition size can be at most %s (100%%).\n", length_str);
if ( argc < 4 )
printf("Partition size can be at most %s (100%%).\n", length_str);
free(length_str);
while ( true )
{
char answer[256];
prompt(answer, sizeof(answer),
"Partition size? (42%/15G/...)", "100%");
if ( 4 <= argc )
strlcpy(answer, argv[3], sizeof(answer));
else
prompt(answer, sizeof(answer),
"Partition size? (42%/15G/...)", "100%");
if ( !parse_disk_quantity(&length, answer, max_length) )
{
fprintf(stderr, "Invalid quantity `%s'.\n", answer);
command_errorx("%s: %s: Invalid quantity: %s",
argv[0], device_name(current_hd->path), answer);
continue;
}
if ( length == 0 )
{
fprintf(stderr, "Answer was zero (or rounded down to zero).\n");
command_errorx("%s: %s: Length was zero (or rounded down to zero)",
argv[0], device_name(current_hd->path));
continue;
}
break;
}
printf("\n");
if ( argc < 4 )
printf("\n");
char fstype[256];
while ( true )
{
@ -1736,13 +1774,17 @@ static void on_mkpart(size_t argc, char** argv)
question = "Format a filesystem? (no/ext2/extended)";
else if ( is_gpt )
question = "Format a filesystem? (no/ext2/biosboot)";
prompt(fstype, sizeof(fstype), question, "ext2");
if ( 5 <= argc )
strlcpy(fstype, argv[4], sizeof(fstype));
else
prompt(fstype, sizeof(fstype), question, "ext2");
if ( strcmp(fstype, "no") != 0 &&
strcmp(fstype, "ext2") != 0 &&
(!is_mbr || strcmp(fstype, "extended") != 0) &&
(!is_gpt || strcmp(fstype, "biosboot") != 0) )
{
fprintf(stderr, "Invalid filesystem choice `%s'.\n", fstype);
command_errorx("%s: %s: Invalid filesystem choice: %s",
argv[0], device_name(current_hd->path), fstype);
continue;
}
if ( !strcmp(fstype, "extended") )
@ -1762,27 +1804,27 @@ static void on_mkpart(size_t argc, char** argv)
bool mountable = !strcmp(fstype, "ext2");
while ( mountable )
{
prompt(mountpoint, sizeof(mountpoint),
"Where to mount partition? (mountpoint or 'no')", "no");
if ( 6 <= argc )
strlcpy(mountpoint, argv[5], sizeof(mountpoint));
else
prompt(mountpoint, sizeof(mountpoint),
"Where to mount partition? (mountpoint or 'no')", "no");
if ( !strcmp(mountpoint, "no") )
{
mountpoint[0] = '\0';
break;
}
if ( !strcmp(mountpoint, "mountpoint") )
{
printf("Then answer which mountpoint.\n");
continue;
}
if ( !verify_mountpoint(mountpoint) )
{
fprintf(stderr, "Invalid mountpoint `%s'.\n", fstype);
command_errorx("%s: %s: Invalid mountpoint: %s",
argv[0], device_name(current_hd->path), mountpoint);
continue;
}
simplify_mountpoint(mountpoint);
break;
}
printf("\n");
if ( mountable && argc < 6 )
printf("\n");
size_t renumbered_partitions = 0;
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended )
{
@ -2696,14 +2738,8 @@ static const struct command commands[] =
};
static const size_t commands_count = sizeof(commands) / sizeof(commands[0]);
void execute(char* cmd)
static void execute_argv(int argc, char** argv)
{
size_t argc = 0;
char* argv[256];
split_arguments(cmd, &argc, argv, 255);
if ( argc < 1 )
return;
argv[argc] = NULL;
for ( size_t i = 0; i < commands_count; i++ )
{
if ( strcmp(argv[0], commands[i].name) != 0 )
@ -2738,6 +2774,17 @@ void execute(char* cmd)
"Try `help' for more information.\n", argv[0]);
}
static void execute(char* cmd)
{
size_t argc = 0;
char* argv[256];
split_arguments(cmd, &argc, argv, 255);
if ( argc < 1 )
return;
argv[argc] = NULL;
execute_argv(argc, argv);
}
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
@ -2766,6 +2813,8 @@ int main(int argc, char* argv[])
{
setlocale(LC_ALL, "");
bool set_interactive = false;
const char* argv0 = argv[0];
for ( int i = 1; i < argc; i++ )
{
@ -2780,6 +2829,8 @@ int main(int argc, char* argv[])
char c;
while ( (c = *++arg) ) switch ( c )
{
case 'i': interactive = true; set_interactive = true; break;
case 'n': interactive = false; set_interactive = true; break;
default:
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
help(stderr, argv0);
@ -2813,20 +2864,30 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv);
interactive = isatty(0) && isatty(1);
if ( !set_interactive )
interactive = isatty(0) && isatty(1) && argc < 3;
if ( !devices_open_all(&hds, &hds_count) )
err(1, "iterating devices");
qsort(hds, hds_count, sizeof(struct harddisk*), harddisk_compare_path);
if ( 1 <= hds_count )
if ( 2 <= argc )
{
struct harddisk* hd;
if ( !lookup_harddisk_by_string(&hd, argv[0], argv[1]) )
exit(1);
switch_device(hd);
}
else if ( 1 <= hds_count )
switch_device(hds[0]);
char* line = NULL;
size_t line_size = 0;
ssize_t line_length;
while ( !quitting )
if ( 3 <= argc )
execute_argv(argc - 2, argv + 2);
else while ( !quitting )
{
if ( interactive )
{
@ -2855,4 +2916,6 @@ int main(int argc, char* argv[])
for ( size_t i = 0; i < hds_count; i++ )
harddisk_close(hds[i]);
free(hds);
return 0;
}

View File

@ -20,19 +20,21 @@
.Op Fl \-height Ns "=" Ns Ar height
.Op Fl \-min-height Ns "=" Ns Ar min-height
.Op Fl \-max-height Ns "=" Ns Ar max-height
.Op Ar command ...
.Op Ar videomode
.Sh DESCRIPTION
.Nm
changes the video mode by displaying an interactive menu containing a list of
available modes, with an additional entry for entering a custom mode (if
supported by the driver).
If the mode change succeeds and
.Ar command
is specified,
.Ar command
is executed.
If the mode change fails, the menu is redisplayed until cancellation or a
successful mode change.
If the
.Ar videomode
argument is specified in the
.Ar width Ns x Ns Ar height Ns x Ns Ar bits-per-pixel
format per
.Xr videomode 5 ,
then the video mode is immediately set non-interactively.
.Pp
By default,
.Nm
@ -142,17 +144,9 @@ inclusive.
.Nm
exits with an exit status of 10 if the menu is quit, 11 if no modes are
available, 12 if no modes are available after filtering, 13 if the terminal has
no associated video devices, 127 if
.Ar command
failed to run, or 1 on any other error.
If
no associated video devices, or 1 on any other error.
.Nm
changes the video mode successfully,
.Nm
exits with the exit status of
.Ar command
if specified,
or 0 otherwise.
exits 0 if the video mode is successfully changed.
.Sh SEE ALSO
.Xr chkblayout 1 ,
.Xr dispmsg_issue 2 ,

View File

@ -299,6 +299,17 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv);
unsigned int xres = 0;
unsigned int yres = 0;
unsigned int bpp = 0;
if ( 2 <= argc )
{
if ( 2 < argc )
error(1, 0, "Unexpected extra operand");
if ( sscanf(argv[1], "%ux%ux%u", &xres, &yres, &bpp) != 3 )
error(1, 0, "Invalid video mode: %s", argv[1]);
}
int tty_fd = open("/dev/tty", O_RDWR);
if ( tty_fd < 0 )
error(1, errno, "/dev/tty");
@ -349,6 +360,34 @@ retry_pick_mode:
decided = false;
first_render = true;
memset(&render_at, 0, sizeof(render_at));
if ( 2 <= argc )
{
bool found_other = true;
size_t other_selection = 0;
for ( size_t i = 0; i < num_modes; i++ )
{
if ( modes[i].view_xres == xres &&
modes[i].view_yres == yres &&
modes[i].fb_format == bpp )
{
selection = i;
decided = true;
break;
}
if ( modes[i].control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
found_other = true;
other_selection = i;
}
}
if ( !decided )
{
if ( found_other )
selection = other_selection;
else
error(1, 0, "No such available resolution: %s", argv[1]);
}
}
while ( !decided )
{
fflush(stdout);
@ -495,10 +534,10 @@ retry_pick_mode:
struct dispmsg_crtc_mode mode = modes[selection];
if ( mode.control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{
uintmax_t req_bpp;
uintmax_t req_width;
uintmax_t req_height;
while ( true )
uintmax_t req_bpp = bpp;
uintmax_t req_width = xres;
uintmax_t req_height = yres;
while ( argc < 2 )
{
printf("Enter video mode [BPP x WIDTH x HEIGHT]: ");
fflush(stdout);
@ -527,11 +566,5 @@ retry_pick_mode:
goto retry_pick_mode;
}
if ( 1 < argc )
{
execvp(argv[1], argv + 1);
error(127, errno, "`%s'", argv[1]);
}
return 0;
}

View File

@ -6,6 +6,7 @@
.Nd change user password
.Sh SYNOPSIS
.Nm
.Op Fl H
.Op Fl c Ar cipher
.Op Ar user
.Sh DESCRIPTION
@ -19,6 +20,11 @@ The options are as follows:
.It Fl c Ar cipher
Hash the password using the specified
.Ar cipher .
.It Fl H
Read a password from the standard input and write the
.Xr crypt_newpass 3
hash to the standard output.
The password database is unchanged.
.El
.Sh FILES
.Bl -tag -width "/etc/passwd" -compact

View File

@ -34,79 +34,67 @@
static void password(char* buffer,
size_t buffer_size,
const char* whose,
const char* question)
const char* question,
bool require_tty)
{
if ( !isatty(0) )
bool is_tty = isatty(0);
if ( !require_tty && is_tty )
errx(1, "Input is not a terminal");
unsigned int termmode;
gettermmode(0, &termmode);
settermmode(0, termmode & ~TERMMODE_ECHO);
if ( whose )
printf("%s's ", whose);
printf("%s ", question);
fflush(stdout);
fflush(stdin);
unsigned int termmode = 0;
if ( is_tty )
{
gettermmode(0, &termmode);
settermmode(0, termmode & ~TERMMODE_ECHO);
if ( whose )
printf("%s's ", whose);
printf("%s ", question);
fflush(stdout);
fflush(stdin);
}
// TODO: This may leave a copy of the password in the stdio buffer.
fgets(buffer, buffer_size, stdin);
fflush(stdin);
printf("\n");
if ( is_tty )
{
fflush(stdin);
printf("\n");
settermmode(0, termmode);
}
size_t buffer_length = strlen(buffer);
if ( buffer_length && buffer[buffer_length-1] == '\n' )
buffer[--buffer_length] = '\0';
settermmode(0, termmode);
}
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
{
while ( i < *argc && !(*argv)[i] )
{
for ( int n = i; n < *argc; n++ )
(*argv)[n] = (*argv)[n+1];
(*argc)--;
}
}
}
int main(int argc, char* argv[])
{
const char* cipher = "blowfish,a";
bool hash_password = false;
for ( int i = 1; i < argc; i++ )
int opt;
while ( (opt = getopt(argc, argv, "c:H")) != -1 )
{
const char* arg = argv[i];
if ( arg[0] != '-' || !arg[1] )
continue;
argv[i] = NULL;
if ( !strcmp(arg, "--") )
break;
if ( arg[1] != '-' )
switch ( opt )
{
char c;
while ( (c = *++arg) ) switch ( c )
{
case 'c':
if ( !*(cipher = arg + 1) )
{
if ( i + 1 == argc )
errx(125, "option requires an argument -- 'c'");
cipher = argv[i+1];
argv[++i] = NULL;
}
arg = "c";
break;
default:
errx(1, "unknown option -- '%c'", c);
}
}
else
{
errx(1, "unrecognized option: %s", arg);
case 'c': cipher = optarg; break;
case 'H': hash_password = true; break;
default: return 1;
}
}
compact_arguments(&argc, &argv);
if ( hash_password )
{
if ( argc - optind )
errx(1, "Unexpected extra operand");
char pass[128];
password(pass, sizeof(pass), NULL, "Enter password (will not echo)",
false);
fgets(pass, sizeof(pass), stdin);
char newhash[128];
if ( crypt_newhash(pass, cipher, newhash, sizeof(newhash)) < 0 )
err(1, "crypt_newhash");
if ( printf("%s\n", newhash) < 0 || fflush(stdout) == EOF )
err(1, "stdout");
return 0;
}
uid_t my_uid = getuid();
char* my_username = getlogin();
@ -116,9 +104,9 @@ int main(int argc, char* argv[])
err(1, "stdup");
const char* username;
if ( argc <= 1 )
if ( argc - optind <= 1 )
username = my_username;
else if ( argc <= 2 )
else if ( argc - optind <= 2 )
username = argv[1];
else
errx(1, "Unexpected extra operand");
@ -139,16 +127,17 @@ int main(int argc, char* argv[])
{
char current[128];
password(current, sizeof(current), pwd->pw_name,
"current password (will not echo)");
"current password (will not echo)", true);
if ( crypt_checkpass(current, pwd->pw_passwd) < 0 )
errx(1, "Wrong password for '%s'", pwd->pw_name);
explicit_bzero(current, sizeof(current));
}
char first[128];
password(first, sizeof(first), NULL, "Enter new password (will not echo)");
password(first, sizeof(first), NULL, "Enter new password (will not echo)",
true);
char second[128];
password(second, sizeof(second), NULL, "Enter new password (again)");
password(second, sizeof(second), NULL, "Enter new password (again)", true);
if ( strcmp(first, second) != 0 )
errx(1, "Passwords don't match");
explicit_bzero(second, sizeof(second));