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 .Nd disk editor
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm disked .Nm disked
.Op Fl in
.Op Fl \-fstab Ns "=" Ns Ar path .Op Fl \-fstab Ns "=" Ns Ar path
.Op Ar device
.Op Ar command ...
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is an interactive program that manages partition tables. is an interactive program that manages partition tables.
@ -19,17 +22,22 @@ supports the Master Boot Record and GUID Partition Table partitioning schemes.
.Pp .Pp
.Nm .Nm
provides an interactive command line. provides an interactive command line.
Its prompt shows the currently selected device (defaulting to the first device Its prompt shows the currently selected
alphabetically) or .Ar device
(defaulting to the first device alphabetically if any) or
.Li (disked) .Li (disked)
if none is selected. 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 Commands perform their actions when run rather than waiting for the user to
write out changes. write out changes.
.Nm .Nm
only creates partitions aligned to 1 MiB boundaries whose size is a multiple of only creates partitions aligned to 1 MiB boundaries whose size is a multiple of
1 MiB. 1 MiB.
Unused regions are aligned and those smaller than the alignment are not shown. Unused regions are aligned and those smaller than the alignment are not shown.
.Pp
The options are as follows: The options are as follows:
.Bl -tag -width "12345678" .Bl -tag -width "12345678"
.It Fl \-fstab Ns "=" Ns Ar path .It Fl \-fstab Ns "=" Ns Ar path
@ -39,6 +47,17 @@ instead of
.Pa /etc/fstab .Pa /etc/fstab
as as
.Xr fstab 5 . .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 .El
.Pp .Pp
The following commands are supported: 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 Display this manual page if no operands are given, otherwise run
.Xr man 1 .Xr man 1
with the given command line. 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. Create a partition on the current device.
If the partition table has multiple unused regions If the partition table has multiple unused regions
.Pq holes , .Pq holes ,
.Nm .Nm
asks you which one to use. asks you which
You need to specify the offset into the hole where the partition is created and .Ar hole
then the length of the partition. (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 See
.Sx QUANTITIES .Sx QUANTITIES
below on the possible partition offset and length values. below on the possible partition offset and length values.
@ -106,7 +130,9 @@ Use the existing disk data.
.El .El
.Pp .Pp
If you format a mountable filesystem, then you will be asked if you want to 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 . .Xr fstab 5 .
.It Sy mktable Oo mbr "|" gpt Oc .It Sy mktable Oo mbr "|" gpt Oc
Create a partition table on the current device of the specified type. 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; return name;
} }
static bool interactive;
static void display_rows_columns(char* (*format)(void*, size_t, size_t), static void display_rows_columns(char* (*format)(void*, size_t, size_t),
void* ctx, size_t rows, size_t columns) void* ctx, size_t rows, size_t columns)
{ {
@ -395,6 +397,8 @@ static void prompt(char* buffer,
const char* question, const char* question,
const char* answer) const char* answer)
{ {
if ( !interactive )
errx(1, "Cannot ask question in non-interactive mode: %s", question);
while ( true ) while ( true )
{ {
printf("\e[1m"); printf("\e[1m");
@ -599,7 +603,6 @@ bool rewrite_finish(struct rewrite* rewr)
return true; return true;
} }
static bool interactive;
static bool quitting; static bool quitting;
static struct harddisk** hds; static struct harddisk** hds;
static size_t hds_count; static size_t hds_count;
@ -1132,6 +1135,25 @@ static void switch_device(struct harddisk* hd)
scan_device(); 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, static bool lookup_partition_by_string(struct partition** out,
const char* argv0, const char* argv0,
const char* numstr) 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) static void on_mkpart(size_t argc, char** argv)
{ {
(void) argc;
(void) argv;
size_t num_holes = 0; size_t num_holes = 0;
struct device_area* hole = NULL; struct device_area* hole = NULL;
for ( size_t i = 0; i < current_areas_count; i++ ) 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]; char answer[sizeof(size_t) * 3];
while ( true ) while ( true )
{ {
prompt(answer, sizeof(answer), if ( 2 <= argc )
"Which hole to create the partition inside?", "1"); strlcpy(answer, argv[1], sizeof(answer));
else
prompt(answer, sizeof(answer),
"Which hole to create the partition inside?", "1");
char* end; char* end;
unsigned long num = strtoul(answer, &end, 10); unsigned long num = strtoul(answer, &end, 10);
if ( *end || num_holes < num ) if ( *end || num_holes < num )
@ -1618,7 +1641,8 @@ static void on_mkpart(size_t argc, char** argv)
} }
break; break;
} }
printf("\n"); if ( argc < 2 )
printf("\n");
} }
unsigned int slot = 0; unsigned int slot = 0;
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended ) 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. assert(start_str); // TODO: Error handling.
char* length_str = format_bytes_amount((uintmax_t) hole->length); char* length_str = format_bytes_amount((uintmax_t) hole->length);
assert(length_str); // TODO: Error handling. assert(length_str); // TODO: Error handling.
printf("Creating partition inside hole at %s of length %s (100%%)\n", if ( argc < 3 )
start_str, length_str); printf("Creating partition inside hole at %s of length %s (100%%)\n",
start_str, length_str);
free(start_str); free(start_str);
free(length_str); free(length_str);
off_t start; off_t start;
while ( true ) while ( true )
{ {
char answer[256]; char answer[256];
prompt(answer, sizeof(answer), if ( 3 <= argc )
"Free space before partition? (42%/15G/...)", "0%"); 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) ) 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; continue;
} }
if ( start == hole->length ) if ( start == hole->length )
{ {
fprintf(stderr, "Answer was all free space, but need space for the " command_errorx("%s: %s: Answer was all free space, but need space "
"partition itself.\n"); "for the partition itself",
argv[0], device_name(current_hd->path));
continue; continue;
} }
break; break;
} }
printf("\n"); if ( argc < 3 )
printf("\n");
off_t max_length = hole->length - start; off_t max_length = hole->length - start;
off_t length; off_t length;
length_str = format_bytes_amount((uintmax_t) max_length); length_str = format_bytes_amount((uintmax_t) max_length);
assert(length_str); 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); free(length_str);
while ( true ) while ( true )
{ {
char answer[256]; char answer[256];
prompt(answer, sizeof(answer), if ( 4 <= argc )
"Partition size? (42%/15G/...)", "100%"); strlcpy(answer, argv[3], sizeof(answer));
else
prompt(answer, sizeof(answer),
"Partition size? (42%/15G/...)", "100%");
if ( !parse_disk_quantity(&length, answer, max_length) ) 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; continue;
} }
if ( length == 0 ) 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; continue;
} }
break; break;
} }
printf("\n"); if ( argc < 4 )
printf("\n");
char fstype[256]; char fstype[256];
while ( true ) while ( true )
{ {
@ -1736,13 +1774,17 @@ static void on_mkpart(size_t argc, char** argv)
question = "Format a filesystem? (no/ext2/extended)"; question = "Format a filesystem? (no/ext2/extended)";
else if ( is_gpt ) else if ( is_gpt )
question = "Format a filesystem? (no/ext2/biosboot)"; 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 && if ( strcmp(fstype, "no") != 0 &&
strcmp(fstype, "ext2") != 0 && strcmp(fstype, "ext2") != 0 &&
(!is_mbr || strcmp(fstype, "extended") != 0) && (!is_mbr || strcmp(fstype, "extended") != 0) &&
(!is_gpt || strcmp(fstype, "biosboot") != 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; continue;
} }
if ( !strcmp(fstype, "extended") ) if ( !strcmp(fstype, "extended") )
@ -1762,27 +1804,27 @@ static void on_mkpart(size_t argc, char** argv)
bool mountable = !strcmp(fstype, "ext2"); bool mountable = !strcmp(fstype, "ext2");
while ( mountable ) while ( mountable )
{ {
prompt(mountpoint, sizeof(mountpoint), if ( 6 <= argc )
"Where to mount partition? (mountpoint or 'no')", "no"); strlcpy(mountpoint, argv[5], sizeof(mountpoint));
else
prompt(mountpoint, sizeof(mountpoint),
"Where to mount partition? (mountpoint or 'no')", "no");
if ( !strcmp(mountpoint, "no") ) if ( !strcmp(mountpoint, "no") )
{ {
mountpoint[0] = '\0'; mountpoint[0] = '\0';
break; break;
} }
if ( !strcmp(mountpoint, "mountpoint") )
{
printf("Then answer which mountpoint.\n");
continue;
}
if ( !verify_mountpoint(mountpoint) ) 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; continue;
} }
simplify_mountpoint(mountpoint); simplify_mountpoint(mountpoint);
break; break;
} }
printf("\n"); if ( mountable && argc < 6 )
printf("\n");
size_t renumbered_partitions = 0; size_t renumbered_partitions = 0;
if ( current_pt_type == PARTITION_TABLE_TYPE_MBR && hole->inside_extended ) 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]); 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++ ) for ( size_t i = 0; i < commands_count; i++ )
{ {
if ( strcmp(argv[0], commands[i].name) != 0 ) if ( strcmp(argv[0], commands[i].name) != 0 )
@ -2738,6 +2774,17 @@ void execute(char* cmd)
"Try `help' for more information.\n", argv[0]); "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) static void compact_arguments(int* argc, char*** argv)
{ {
for ( int i = 0; i < *argc; i++ ) for ( int i = 0; i < *argc; i++ )
@ -2766,6 +2813,8 @@ int main(int argc, char* argv[])
{ {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
bool set_interactive = false;
const char* argv0 = argv[0]; const char* argv0 = argv[0];
for ( int i = 1; i < argc; i++ ) for ( int i = 1; i < argc; i++ )
{ {
@ -2780,6 +2829,8 @@ int main(int argc, char* argv[])
char c; char c;
while ( (c = *++arg) ) switch ( c ) while ( (c = *++arg) ) switch ( c )
{ {
case 'i': interactive = true; set_interactive = true; break;
case 'n': interactive = false; set_interactive = true; break;
default: default:
fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c); fprintf(stderr, "%s: unknown option -- '%c'\n", argv0, c);
help(stderr, argv0); help(stderr, argv0);
@ -2813,20 +2864,30 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &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) ) if ( !devices_open_all(&hds, &hds_count) )
err(1, "iterating devices"); err(1, "iterating devices");
qsort(hds, hds_count, sizeof(struct harddisk*), harddisk_compare_path); 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]); switch_device(hds[0]);
char* line = NULL; char* line = NULL;
size_t line_size = 0; size_t line_size = 0;
ssize_t line_length; ssize_t line_length;
while ( !quitting ) if ( 3 <= argc )
execute_argv(argc - 2, argv + 2);
else while ( !quitting )
{ {
if ( interactive ) if ( interactive )
{ {
@ -2855,4 +2916,6 @@ int main(int argc, char* argv[])
for ( size_t i = 0; i < hds_count; i++ ) for ( size_t i = 0; i < hds_count; i++ )
harddisk_close(hds[i]); harddisk_close(hds[i]);
free(hds); free(hds);
return 0;
} }

View File

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

View File

@ -299,6 +299,17 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &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); int tty_fd = open("/dev/tty", O_RDWR);
if ( tty_fd < 0 ) if ( tty_fd < 0 )
error(1, errno, "/dev/tty"); error(1, errno, "/dev/tty");
@ -349,6 +360,34 @@ retry_pick_mode:
decided = false; decided = false;
first_render = true; first_render = true;
memset(&render_at, 0, sizeof(render_at)); 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 ) while ( !decided )
{ {
fflush(stdout); fflush(stdout);
@ -495,10 +534,10 @@ retry_pick_mode:
struct dispmsg_crtc_mode mode = modes[selection]; struct dispmsg_crtc_mode mode = modes[selection];
if ( mode.control & DISPMSG_CONTROL_OTHER_RESOLUTIONS ) if ( mode.control & DISPMSG_CONTROL_OTHER_RESOLUTIONS )
{ {
uintmax_t req_bpp; uintmax_t req_bpp = bpp;
uintmax_t req_width; uintmax_t req_width = xres;
uintmax_t req_height; uintmax_t req_height = yres;
while ( true ) while ( argc < 2 )
{ {
printf("Enter video mode [BPP x WIDTH x HEIGHT]: "); printf("Enter video mode [BPP x WIDTH x HEIGHT]: ");
fflush(stdout); fflush(stdout);
@ -527,11 +566,5 @@ retry_pick_mode:
goto retry_pick_mode; goto retry_pick_mode;
} }
if ( 1 < argc )
{
execvp(argv[1], argv + 1);
error(127, errno, "`%s'", argv[1]);
}
return 0; return 0;
} }

View File

@ -6,6 +6,7 @@
.Nd change user password .Nd change user password
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl H
.Op Fl c Ar cipher .Op Fl c Ar cipher
.Op Ar user .Op Ar user
.Sh DESCRIPTION .Sh DESCRIPTION
@ -19,6 +20,11 @@ The options are as follows:
.It Fl c Ar cipher .It Fl c Ar cipher
Hash the password using the specified Hash the password using the specified
.Ar cipher . .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 .El
.Sh FILES .Sh FILES
.Bl -tag -width "/etc/passwd" -compact .Bl -tag -width "/etc/passwd" -compact

View File

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