/* * Add Printer helper for Samba and CUPS * * Compile with gcc -Wall addprinter.c -o addprinter and set as your * addprinter command in smb.conf. It expects to find a file mapping * Samba-friendly port names to CUPS-friendly port names in the location * marked by PORTSFILE, below. The map file is just * PORTNAME[whitespace]CUPSNAME, one port per line. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define PORTSFILE "/etc/samba/ports-map" #define CONFFILE "/etc/samba/smb.conf" #define SPOOL_PATH "/var/spool/samba" int main( int argc, char *argv[] ) { pid_t pid = 0; char *line = NULL; size_t linelen, dummy = 0; FILE *ports = NULL; char *port = NULL; FILE *smbconf = NULL; int idx = 0; char *printer; char *sharename; char *portarg; /* Syslog support */ openlog( "addprinter", LOG_PID, LOG_LPR ); /* The manual page claims 6 arguments! Args are: - printer name - share name - port name - driver name - location - comment - host requesting printer addition */ if ( argc != 8 ) { syslog( LOG_ERR, "Expected 7 arguments, found %d", argc - 1 ); exit( 1 ); } else { syslog( LOG_INFO, "addprinter '%s' '%s' '%s' '%s' '%s' '%s' '%s'", argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7] ); } /* these are to make the code more readable :) */ printer = strdup( argv[1] ); sharename = strdup( argv[2] ); portarg = strdup( argv[3] ); /* Next, find the correct translation for the port */ if (( ports = fopen( PORTSFILE, "r" )) == NULL ) { syslog( LOG_ERR, "Failed to open ports file" ); exit( 1 ); } while(( linelen = getline( &line, &dummy, ports )) != -1 ) { if ( strncmp( line, portarg, strlen( portarg )) == 0 ) { /* Yay, match */ if ( linelen > strlen( portarg ) && !isblank( line[strlen(portarg)])) { /* Boo, it's not (i.e. it's a substring match) */ continue; } else { idx = strlen( portarg ); /* Nuke trailing newline */ if ( line[strlen( line ) - 1] == '\n' ) { line[ strlen( line ) - 1 ] = '\0'; } while( idx < linelen && isblank( line[ idx ])) { idx++; } if ( idx == linelen ) { continue; } port = strdup( &line[idx] ); } } } if ( line ) free( line ); /* clean up printer name, because otherwise lpadmin will barf. Might * be necessary to further restrict the printer name? We should also * probably check that the printer doesn't already exist. */ for ( idx = 0; idx < strlen( printer ); idx++ ) { if ( isblank( printer[idx] )) printer[idx] = '_'; } if ( !port ) { syslog( LOG_ERR, "No port found matching %s", portarg ); exit( 1 ); } else { syslog( LOG_INFO, "Setting up %s on %s\n", printer, port ); } pid = fork(); if ( pid == -1 ) { syslog( LOG_ERR, "error forking: %m" ); exit( 1 ); } if ( !pid ) { /* Child */ execl( "/usr/sbin/lpadmin", "lpadmin", "-p", printer, "-o", "raw", "-v", port, "-E", NULL ); syslog( LOG_ERR, "exec error running lpadmin: %m" ); exit( 1 ); /* notreached */ } else { int status; waitpid( pid, &status, 0 ); /* Bail on error */ if ( status != 0 ) { syslog( LOG_INFO, "lpadmin exited with status %d", status ); exit( 1 ); } } free( port ); /* Add the new printer to smb.conf */ if (( smbconf = fopen( CONFFILE, "a" )) != NULL ) { fprintf( smbconf, "\n" ); fprintf( smbconf, "[%s]\n", sharename ); fprintf( smbconf, ";; automatically added printer definition\n" ); fprintf( smbconf, "printer name = %s\n", printer ); fprintf( smbconf, "printable = yes\n" ); fprintf( smbconf, "path = %s\n", SPOOL_PATH ); fclose( smbconf ); } else { syslog( LOG_ERR, "failed to open %s: %m", CONFFILE ); exit( 1 ); } /* If this isn't printed out, Samba will not reload shares */ fprintf( stdout, "%s\n", portarg ); /* unnecessary, but tidy */ free( printer ); free( sharename ); free( portarg ); return 0; }